1. 程式人生 > >Java自定義註解——簡易實現spring @Autowired

Java自定義註解——簡易實現spring @Autowired

用過spring的都知道@Autowired,但是類似的註解內部是怎樣實現的呢?下面通過一個小例子來了解一下類似的實現過程

在看這個例子之前需要先對java反射機制有了解,不需要多深入,只需知道反射是幹什麼的就可以了,程式碼很少,不復雜,一看就懂,通過這個例子可以初步認識反射、自定義註解等知識 首先寫自定義註解的程式碼,在寫之前需要先了解以下幾個元註解

@Target:

   @Target說明了Annotation所修飾的物件範圍:Annotation可被用於 packages、types(類、介面、列舉、Annotation型別)、型別成員(方法、構造方法、成員變數、列舉值)、方法引數和本地變數(如迴圈變數、catch引數)。在Annotation型別的宣告中使用了target可更加明晰其修飾的目標。

  作用:用於描述註解的使用範圍(即:被描述的註解可以用在什麼地方)

  取值(ElementType)有:

    1.CONSTRUCTOR:用於描述構造器
    2.FIELD:用於描述域
    3.LOCAL_VARIABLE:用於描述區域性變數
    4.METHOD:用於描述方法
    5.PACKAGE:用於描述包
    6.PARAMETER:用於描述引數
    7.TYPE:用於描述類、介面(包括註解型別) 或enum宣告


@Retention:

  @Retention定義了該Annotation被保留的時間長短:某些Annotation僅出現在原始碼中,而被編譯器丟棄;而另一些卻被編譯在class檔案中;編譯在class檔案中的Annotation可能會被虛擬機器忽略,而另一些在class被裝載時將被讀取(請注意並不影響class的執行,因為Annotation與class在使用上是被分離的)。使用這個meta-Annotation可以對 Annotation的“生命週期”限制。

  作用:表示需要在什麼級別儲存該註釋資訊,用於描述註解的生命週期(即:被描述的註解在什麼範圍內有效)

  取值(RetentionPoicy)有:

    1.SOURCE:在原始檔中有效(即原始檔保留)
    2.CLASS:在class檔案中有效(即class保留)
    3.RUNTIME:在執行時有效(即執行時保留)

  Retention meta-annotation型別有唯一的value作為成員,它的取值來自java.lang.annotation.RetentionPolicy的列舉型別值。


@Documented:

  @Documented用於描述其它型別的annotation應該被作為被標註的程式成員的公共API,因此可以被例如javadoc此類的工具文件化。Documented是一個標記註解,沒有成員。

下面是示例程式碼
/**
 * 測試註解
 * @author lc
 *
 */
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface TestAnnotation {
    /**
     * 數值
     * @return
     */
    int num() default 1;
}

接著是使用註解的程式碼

public class Test {
	@TestAnnotation(num=45)
	private static int a;//使用註解
	private int b = 9; //未使用註解的變數,主要是用於做對比

	public static void main(String[] args) throws IllegalArgumentException, IllegalAccessException {
		TestZjImpl.set(Test.class);
		System.out.println(a);
	}
}



最後是通過反射機制給註解的變數賦值

public static void set(Class c) throws IllegalArgumentException, IllegalAccessException{
		Field[] fields = c.getDeclaredFields();//獲取所有變數
		for(int i=0; i<fields.length;i++){
			fields[i].setAccessible(true);//獲取訪問私有變數的許可權
			if(fields[i].isAnnotationPresent(TestAnnotation.class)){//判斷是否是使用註解的引數
				TestAnnotation t = fields[i].getAnnotation(TestAnnotation.class);
				System.out.println("註解中配置的num引數是:"+t.num());
				fields[i].set(t, 18);//給變數賦值
			}
		}
	}


程式碼很簡單,一看就懂,spring的@Autowired當然不會這麼簡單,想進一步瞭解的可以看原始碼,其它的用法可以根據示例程式碼自己發揮