java 註解和自定義註解詳解

定義

註解是在JDK1.5之後引入的新特性位於​java.lang.annotation​,註解其實就是對代碼進行一種特殊的標記,這些標記可以在編譯,類加載和運行時被讀取,並執行相應的處理。

第三方註解

在Java開發者,JDK自帶了一些註解,在第三方框架Spring  帶了大量的註解,這些註解稱爲第三方註解

1、Jdk通用註解

  1. @Override註解:編譯檢查,告訴編譯器這個是個覆蓋父類的方法。如果父類刪除了該方法,則子類會報錯。

@Target({ElementType.METHOD})

@Retention(RetentionPolicy.SOURCE)

public @interface Override {

}

  1. @Deprecated 註解:編譯檢查,表示被註解的元素已被棄用

@Documented

@Retention(RetentionPolicy.RUNTIME)

@Target({ElementType.CONSTRUCTOR, ElementType.FIELD, ElementType.LOCAL_VARIABLE, ElementType.METHOD,

                ElementType.PACKAGE, ElementType.PARAMETER, ElementType.TYPE})

public @interface Deprecated {

}

上面兩個註解除了都有一些元註解之外,沒有任何的東西,但是我們加了這兩個註解後,編譯器就能夠識別,可以將其理解爲是一個標籤,它並沒有實際的邏輯處理,而實現邏輯的就是註解的用戶。它本質就是一個 『標記式註解』,僅被編譯器可知 ,這就是註解的工作原理。

註解的本質就是一個接口,該接口默認繼承了java.lang.annotation.Annotation接口。

public interface Annotation {

        boolean equals(Object var1);

 

        int hashCode();

 

        String toString();

 

        Class<? extends Annotation> annotationType();

}

 

2、元註解

元註解用於註解其他註解的。Java 5.0定義了4個標準的元註解,如下:

  1. @Target
  1. @Retention
  1. @Documented
  1. @Inherited

 

2.1@Target

@Target註解用於聲明註解的作用範圍,例如作用範圍爲類、接口、方法等。源碼:

package java.lang.annotation;

 

@Documented

@Retention(RetentionPolicy.RUNTIME)

@Target({ElementType.ANNOTATION_TYPE})

public @interface Target {

        ElementType[] value();

}

其中ElementType表明了該註解可以使用的位置:

public enum ElementType {

        TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE, ANNOTATION_TYPE, PACKAGE, TYPE_PARAMETER, TYPE_USE;

}

具體解釋:

枚舉 作用
ElementType.PACKAGE 註解用在包
ElementType.TYPE 註解作用於類型(類,接口,註解,枚舉)
ElementType.ANNOTATION_TYPE 註解作用於註解
ElementType.CONSTRUCTOR 註解作用於構造方法
ElementType.METHOD 註解作用於方法
ElementType.PARAMETER 註解作用於方法參數
ElementType.FIELD 註解作用於屬性
ElementType.LOCAL_VARIABLE 註解作用於局部變量

2.2@Retention

@Retention註解的作用就是指定註解的生命週期。比如在編譯時可以處理運行時可以處理等。源碼:

@Documented

@Retention(value = RetentionPolicy.RUNTIME)

@Target(value = {ElementType.ANNOTATION_TYPE})

public @interface Retention {

        public RetentionPolicy value();

}

 

它的枚舉類爲​RetentionPolicy​,只有三個可選值

 

枚舉 作用
RetentionPolicy.SOURCE 源碼中保留,編譯期可以處理
RetentionPolicy.CLASS Class文件中保留,Class加載時可以處理
RetentionPolicy.RUNTIME 運行時保留,運行中可以處理

2.3@Documented

是一個標記註解,有該註解的註解會在生成 java 文檔中保留

@Documented

@Retention(RetentionPolicy.RUNTIME)

@Target({ElementType.ANNOTATION_TYPE})

public @interface Documented {

}

 

2.4@Inherited

@Inherited 註解修飾的註解時具有可繼承性的,就是說我們用 @Inherited 修飾了一個類,那麼這個類的子類也會默認繼承此註解。

@Documented

@Retention(RetentionPolicy.RUNTIME)

@Target({ElementType.ANNOTATION_TYPE})

public @interface Inherited {

}

 

自定義註解

在第三方註解沒法滿足我們業務要求的時候,需要我們自己寫註解,這個時候就是自定義註解。

1.1、自定義註解語法

在註解中,需要使用四種元註解來聲明註解的作用範圍、生命週期、繼承,是否生成文檔等。另外在註解中也可以有自己的成員變量,如果一個註解沒有成員變量則稱爲標記註解。

 

@Retention(RetentionPolicy.RUNTIME)

@Target({ ElementType.METHOD })

@Documented

public @interface CxmAction {

    String code() default "";// 權限碼

String descrption() default "";// 描述

 

String prompt() default ""; // 權限提示

}

 

1.2、註解使用說明

1.2.1、AOP + 註解

使用AOP是一種常見的處理方式,首選,需要定義切面類

@Aspect

@Component

@Slf4j

@Order(-1)

public class CxmLogbackAspect {

 

/***

 * 定義controller切入點攔截規則,攔截SystemLog註解的業務方法

 */

@Pointcut("@annotation(com.cxm.common.annotation.SystemLog)")

public void logPointcut(){

 

}

 

/**

 * 環繞

 * @param proceedingJoinPoint

 * @return

 * @throws Throwable

 */

@Around("logPointcut()")

public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable {

    // 執行具體的業務邏輯

}

 

}

 

  • 1.2.2、HandlerInterceptor + 註解

使用Spring的攔截器HandlerInterceptorAdapter,也可以實現註解的業務,比如系統中使用這種方式配合SkipCertification,實現了某些指定接口跳過token驗證的功能

@Slf4j

@Component

public class PermissionInterceptor extends HandlerInterceptorAdapter {

 

/**

 * 

  * @Title: preHandle 

  * @Description: 在Controller執行之前調用,如果返回false,controller不執行

  * @param  @param request

  * @param  @param response

  * @param  @param handler

  * @param  @return

  * @param  @throws Exception 

  * @throws 

  *

 */

@Override

public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {

    if (!(handler instanceof HandlerMethod)) {// 如果不是HandlerMethod而是靜態資源的請求,就直接跳過去

        return true;

    }

    HandlerMethod method = (HandlerMethod) handler;

    SkipCertification  certification = method.getMethodAnnotation(SkipCertification.class);

    if (null != certification) {// 跳過token驗證

        return true;

    } else {

         // 執行校驗  

    }

}

 

}

 

1.2.3、java反射 + 註解

通過反射,可以獲取添加註解的屬性值

public static void main(String[] args) throws IllegalArgumentException, IllegalAccessException {

    TestAnnotation testAnnotation = new TestAnnotation();

    Field[] fields = obj.getClass().getDeclaredFields();

      for(Field field : fields) {

          field.setAccessible(true);

          if(field.isAnnotationPresent(testAnnotation )) {

              map.put(field.getName(),field.get(obj));

           }

        }

    }

 

1.2.4、 Filter + 註解

使用過濾器也可以實現直接的功能,比如利用fastJSON的AfterFilter,實現屬性增強

public void doWrite(List<Field> fields, Object object) {

    for (int i = 0; i < fields.size(); i++) {

        Field field = fields.get(i);

        Stall stallAnn = AnnotationUtils.getAnnotation(field, Stall.class);

        if (stallAnn != null) {

                Object value = ReflectionUtils.getField(field, object);

                if (value != null) {

                        this.doWrite(field, value);

                }

        }

    }

}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章