咱們有必要對JDK 5.0新增的註解(Annotation)技術進行簡單的學習,由於Spring 支持@AspectJ,而@AspectJ自己就是基於JDK 5.0的註解技術。因此學習JDK 5.0的註解知識有助於咱們更好地理解和掌握Spring的AOP技術。java
對於Java開發人員來講,在編寫代碼時,除了源程序之外,咱們還會使用 Javadoc標籤對類、方法或成員變量進行註釋,以便使用Javadoc工具生成和源代碼配套的Javadoc文檔。這些@param、@return等Javadoc標籤就是註解標籤,它們爲第三方工具提供了描述程序代碼的註釋信息。使用過Xdoclet的朋友,對此將更有感觸,像Struts、 Hibernate都提供了Xdoclet標籤,使用它們能夠快速地生成對應程序代碼的配置文件。web
JDK5.0註解能夠當作是Javadoc標籤和Xdoclet標籤的延伸和發展。在JDK5.0中,咱們能夠自定義這些標籤,並經過Java語言的反射機制中獲取類中標註的註解,完成特定的功能。數組
註解是代碼的附屬信息,它遵循一個基本原則:註解不能直接干擾程序代碼的運行,不管增長或刪除註解,代碼都可以正常運行。Java語言解釋器會忽略這些註解,而由第三方工具負責對註解進行處理。第三方工具能夠利用代碼中的註解間接控制程序代碼的運行,它們經過Java反射機制讀取註解的信息,並根據這些信息更改目標程序的邏輯,而這正是Spring AOP對@AspectJ提供支持所採起的方法。ide
註解的語法比較簡單,除了@符號的使用之外,它基本上與java的固有語法一致,java內置了三種註解,定義在java.lang包中。工具
@Override:只能用在方法之上的,用來告訴別人這一個方法是改寫父類的。學習
@Deprecated:建議別人不要使用舊的API的時候用的,編譯的時候會用產生警告信息,能夠設定在程序裏的全部的元素上。spa
@SuppressWarnings:表示關閉一些不當的編譯器警告信息。設計
下面是一個定義註解的實例。orm
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
public @interface Description {
String value();
}對象
其中的@interface是一個關鍵字,在設計annotations的時候必須把一個類型定義爲@interface,而不能用class或interface關鍵字。全部的註解類都隱式繼承於 java.lang.annotation.Annotation,註解不容許顯式繼承於其餘的接口。
一個註解能夠擁有多個成員,成員聲明和接口方法聲明相似,這裏,咱們僅定義了一個成員,成員的聲明有如下幾點限制:
a) 成員以無入參無拋出異常的方式聲明,如boolean value(String str)、boolean value() throws Exception等方式是非法的;
b) 能夠經過default爲成員指定一個默認值,如String level() default "LOW_LEVEL"、int high() default 2是合法的,固然也能夠不指定默認值;
c) 成員類型是受限的,合法的類型包括原始類型及其封裝類、String、Class、enums、註解類型,以及上述類型的數組類型。如ForumService value()、List foo()是非法的。
d) 若是註解只有一個成員,則成員名必須取名爲value(),在使用時能夠忽略成員名和賦值號(=),如@Description("使用註解的實例")。註解類擁有多個成員時,若是僅對value成員進行賦值則也可不使用賦值號,若是同時對多個成員進行賦值,則必須使用賦值號,如@DeclareParents (value = "NaiveWaiter", defaultImpl = SmartSeller.class)。
e) 註解類能夠沒有成員,沒有成員的註解稱爲標識註解,解釋程序以標識註解存在與否進行相應的處理;
註解定義包含四個元註解,分別爲@Target,@Retention,@Documented,@Inherited。各元註解的做用以下:
1) @Target
表示該註解用於什麼地方,可能的 ElemenetType 參數包括:
Ø ElemenetType.CONSTRUCTOR 構造器聲明。
Ø ElemenetType.FIELD 域聲明(包括 enum 實例)。
Ø ElemenetType.LOCAL_VARIABLE 局部變量聲明。
Ø ElemenetType.METHOD 方法聲明。
Ø ElemenetType.PACKAGE 包聲明。
Ø ElemenetType.PARAMETER 參數聲明。
Ø ElemenetType.TYPE 類,接口(包括註解類型)或enum聲明。
2) @Retention
表示在什麼級別保存該註解信息。可選的 RetentionPolicy 參數包括:
Ø RetentionPolicy.SOURCE 註解將被編譯器丟棄。
Ø RetentionPolicy.CLASS 註解在class文件中可用,但會被VM丟棄。
Ø RetentionPolicy.RUNTIME VM將在運行期也保留註釋,所以能夠經過反射機制讀取註解的信息。
舉一個例子,如@Override裏面的Retention設爲SOURCE,編譯成功了就不要這一些檢查的信息,相反,@Deprecated裏面的Retention設爲RUNTIME,表示除了在編譯時會警告咱們使用了哪一個被 Deprecated的方法,在執行的時候也能夠查出該方法是否被Deprecated。
3) @Documented
將此註解包含在 javadoc 中
4) @Inherited
容許子類繼承父類中的註解
下面是一個使用註解註解的實例。
@Description(value="使用註解的實例")
public class TestAnnotation {
}
使用註解的語法:@<註解名>(<成員名1>=<成員值1>,<成員名1>=<成員值1>,...)
若是成員是數組類型,能夠經過{}進行賦值,如boolean數組的成員能夠設置爲{true,false,true}。下面是幾個註解標註的例子:
1) 多成員的註解
@AnnoExample(id= 2868724, synopsis = "Enable time-travel", engineer = "Mr. Peabody")
2) 一個成員的註解,成員名爲value
能夠省略成員名和賦值符號:@Copyright("Right Reserved")
@Copyright("2011 bookegou.com All Right Reserved")
3) 無成員的註解
@Override
@Override
4) 成員爲字符串數組的註解
@SuppressWarnings(value={"unchecked","fallthrough"})
@SuppressWarnings(value={"unchecked","fallthrough"})
5) 成員爲註解數組類型的註解
@Reviews({@Review(grade=Review.Grade.EXCELLENT,reviewer="df"),
@Review(grade=Review.Grade.UNSATISFACTORY,reviewer="eg",
comment="This method needs an @Override annotation")})
@Reviews({@Review(grade=Review.Grade.EXCELLENT,reviewer="df"),
@Review(grade=Review.Grade.UNSATISFACTORY,reviewer="eg",
comment="This method needs an @Override annotation")})
@Reviews註解擁有一個@Review註解數組類型的成員,@Review註解類型有三個成員,其中reviewer、comment都是String類型,但comment有默認值,grade是枚舉類型的成員。
下面是一個解析註解的實例。
public class ParseAnnotation {
public static void main(String[] args) throws Exception{
final Class cls = Class.forName("com.annotation.TestAnnotation");
final Method[] method = cls.getMethods();
// 判斷是否有指定註解類型的註解
if(cls.isAnnotationPresent(Description.class)) {
// 根據註解類型返回指定類型的註解
Description des = (Description)cls.getAnnotation(Description.class);
System.out.println("註解描述:" + des.value());
}
}
}
輸出結果以下:
註解描述:使用註解的實例
前面提到過,註解不會直接影響程序的運行,可是第三方程序或工具能夠利用代碼中的註解完成特殊的任務,間接控制程序的運行。對於RetentionPolicy.RUNTIME保留期限的註解,咱們能夠經過反射機制訪問類中的註解。
在JDK5.0裏,Package、Class、Constructor、 Method以及Field等反射對象都新增了訪問註解信息的方法:<T extends Annotation>T getAnnotation(Class<T> annotationClass),該方法支持經過泛型直接返回註解對象。