Java注解工作機制


前言:

做Java開發我們常常用到注解,如@Service、@Overrided、@Autowired、@Param等,但這些注解的工作原理是怎么樣的恐怕不是每個人都說的清楚,在沒了解注解的工作原理之前倒是可以大致推斷一下:當注解標注到某個類或者方法或者某個成員變量或者某個輸入參數上的時候,一定有一個對應的機制來對注解標注的類、方法、成員變量和參數進行某些處理。比如Bean掃描、編譯檢查、注入值、約束是否為空等等。

1、注解定義:

注解就是用來描述包、類、成員變量、方法或者參數的元數據,注解本身也是一個類(Java里一切都是對象)。配置過Spring的同學肯定很清楚,Spring中的Bean需要在xml里面聲明,比如說一個Bean他的構造方法是啥,他依賴哪些其他bean,初始化變量值是多少,這些都是描述性的數據告知Spring按照這個描述去創建這個Bean。我們隨便找個例子:

<bean id="Kenny" class="com.springinaction.springidol.Instrumentalist">
        <property name="song" value="Jingle Bells"></property>
        <property name="age" value="37"></property>
        <property name="instrument" ref="saxphone"></property> 
        <property name="instrument" ref="piano"></property> 
        <property name="instrument">
            <bean class="com.springinaction.springidol.piano"></bean>
        </property>
    </bean>

這些對類和變量等的描述實際上就是元數據,而這些都可以用注解取代,因為注解也是元數據。比如@Component注解標注在一個類上就可以說明該類是一個bean,@Autowire標注在成員變量上就直接給該成員變量賦值。看起來注解標注在代碼上耦合性更強了,但實際上本着約定優於配置的原則,代碼更加清晰,也容易維護。

2、注解分類

注解大體上可以分成兩類,一類是系統帶的如@Override,這類注解對其標注的目標的處理在JVM層面進行;另一類是我們自定義的注解,自己定義的注解自己要進行解析。還有一類是描述注解的注解,共有4個,分別是:
@Documented 注解信息是否添加到javadoc中
@Retention 注解的生命周期

RetentionPolicy.SOURCE(編譯結束后失效如@Override)、RetentionPolicy.CLASS(JVM加載類的時候失效,默認。不能通過反射獲取)、RetentionPolicy.RUNTIME(始終不失效,一般用於自定義注解,可通過反射獲取)

@Target 注解用在什么地方,分別有幾個地方:

ElementType.TYPE:類上
ElementType.FIELD:成員變量
ElementType.METHOD 方法
ElementType.PARAMETER 參數
ElementType.CONSTRUCTOR 構造方法
ElementType.LOCAL_VARIABLE 本地變量
ElementType.ANNOTATION_TYPE 另一個注釋
ElementType.PACKAGE 包上

@Inherited 注解作用被子類繼承

3、自定義注解

3.1 定義一個注解需要幾步?

首先、@Target肯定要有;
其次、生命周期盡量RUNTIME;
然后、使用@interface聲明;
再次、內部只支持基本類型、String類型和枚舉類型;
最后、所有屬性都必須寫成field(),並可提供默認值default;

3.2 如何使用注解?

首先、在對應位置(@Target)標注;
然后、給注解中的屬性賦值;

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@interface Company {
   public enum Status {RUNNING, CLOSED}
   String name() default "NETEASE"//有默認值
   Status status() default Status.RIUNNING;
   String location();//沒有默認值
} 
public class Demo{
    @Company(name="阿里巴巴",status=Company.Status.RUNNING,location="北京"public void companyInfo(){}
}
@interface Country{
  String value();
}
@Country"中國"public void method(){};

上面是第一個自定義注解的例子,該注解需要標注在方法上,在運行期間一直存在。如果注解中只有一個屬性可以命名為value()這種的好處是注解標注的時候不用寫value=xxx而是直接寫xxx即可。

3.3 注解標注完如何處理?

首先、定義一個注解處理類和注解處理方法;
然后、通過反射獲取注解標注的類或者方法或者變量等等並對其做相應處理;

import java.lang.reflect.Field;
public class AnnotationProccessor {
    public  static void process(Demo demo){
        Class demoClazz = Demo.class;
          for(Method method : demoClazz.getMethods()) {
             Company companyAnnotation = (Company)method.getAnnotation(Company.class);
             if(companyAnnotation !=null) {
                System.out.println(" Method Name : "+ method.getName());
                System.out.println(" name : "+ companyAnnotation.name());
                System.out.println(" Status : "+ companyAnnotation.status());
     }
  } 
}

上面的類只對特定的類進行了處理,在Spring中一個如@Service這種注解,Spring在啟動IOC容器的時候會對每個類進行掃描,把所有標注@Component及其子注解如@Service的類進行Bean處理。

總結:

以上就是注解的相關原理和機制,我們前面的猜測是正確的,其處理機制主要是JVM內部處理和使用反射的自定義處理。


注意!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系我们删除。



 
粤ICP备14056181号  © 2014-2020 ITdaan.com