JDK5--Annotation学习:基础(二)
轉載自:http://www.iteye.com/topic/1123823
引述要學習Spring框架的技術內幕,必須事先掌握一些基本的Java知識,正所謂“登高必自卑,涉遠必自邇”。以下幾項Java知識和Spring框架息息相關,不可不學(我將通過一個系列分別介紹這些Java基礎知識,希望對大家有所幫助。):
[1] Java反射知識-->Spring IoC :http://www.iteye.com/topic/1123081
[2] Java動態代理-->Spring AOP :http://www.iteye.com/topic/1123293
[3] 屬性編輯器,即PropertyEditor-->Spring IoC:http://www.iteye.com/topic/1123628
[4] XML基礎知識-->Spring配置:http://www.iteye.com/topic/1123630
[5] 注解-->Spring配置:http://www.iteye.com/topic/1123823
[6] 線程本地變更,即ThreadLocal-->Spring事務管理:http://www.iteye.com/topic/1123824
[7] 事務基礎知識-->Spring事務管理:http://www.iteye.com/topic/1124043
[8] 國際化信息-->MVC:http://www.iteye.com/topic/1124044
[9] HTTP報文-->MVC:http://www.iteye.com/topic/1124408
有必要對JDK 5.0新增的注解(Annotation)技術進行簡單的學習,因為Spring 支持@AspectJ,而@AspectJ本身就是基于JDK 5.0的注解技術。所以學習JDK 5.0的注解知識有助于我們更好地理解和掌握Spring的AOP技術。
了解注解
對于Java開發人員來說,在編寫代碼時,除了源程序以外,我們還會使用Javadoc標簽對類、方法或成員變量進行注釋,以便使用Javadoc工具生成和源代碼配套的Javadoc文檔。這些@param、@return等Javadoc標簽就是注解標簽,它們為第三方工具提供了描述程序代碼的注釋信息。使用過Xdoclet的朋友,對此將更有感觸,像Struts、Hibernate都提供了Xdoclet標簽,使用它們可以快速地生成對應程序代碼的配置文件。
JDK5.0注解可以看成是Javadoc標簽和Xdoclet標簽的延伸和發展。在JDK5.0中,我們可以自定義這些標簽,并通過Java語言的反射機制中獲取類中標注的注解,完成特定的功能。
注解是代碼的附屬信息,它遵循一個基本原則:注解不能直接干擾程序代碼的運行,無論增加或刪除注解,代碼都能夠正常運行。Java語言解釋器會忽略這些注解,而由第三方工具負責對注解進行處理。第三方工具可以利用代碼中的注解間接控制程序代碼的運行,它們通過Java反射機制讀取注解的信息,并根據這些信息更改目標程序的邏輯,而這正是Spring AOP對@AspectJ提供支持所采取的方法。
一個簡單的注解類
通常情況下,第三方工具不但負責處理特定的注解,本身還提供了這些注解的定義,所以我們通常僅需關注如何使用注解就可以了。但定義注解類本身并不困難,Java提供了定義注解的語法。下面,我們馬上著手編寫一個簡單的注解類,如代碼清單7-1所示:
代碼清單7-1? NeedTest注解類
?
package com.baobaotao.aspectj.anno; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target;@Retention(RetentionPolicy.RUNTIME) //①聲明注解的保留期限 @Target(ElementType.METHOD)//②聲明可以使用該注解的目標類型 public @interface NeedTest {//③定義注解boolean value() default true;//④聲明注解成員 }
Java新語法規定使用@interface修飾符定義注解類,如③所示,一個注解可以擁有多個成員,成員聲明和接口方法聲明類似,這里,我們僅定義了一個成員,如④所示。成員的聲明有以下幾點限制:
- 成員以無入參無拋出異常的方式聲明,如boolean value(String str)、boolean value() throws Exception等方式是非法的;
- 可以通過default為成員指定一個默認值,如String level() default "LOW_LEVEL"、int high() default 2是合法的,當然也可以不指定默認值;
- 成員類型是受限的,合法的類型包括原始類型及其封裝類、String、Class、enums、注解類型,以及上述類型的數組類型。如ForumService value()、List foo()是非法的。
在①和②處,我們所看到的注解是Java預定義的注解,稱為元注解(Meta-Annotation),它們被Java編譯器使用,會對注解類的行為產生影響。@Retention(RetentionPolicy. RUNTIME)表示NeedTest這個注解可以在運行期被JVM讀取,注解的保留期限類型在java.lang.annotation.Retention類中定義,介紹如下:
- SOURCE:注解信息僅保留在目標類代碼的源碼文件中,但對應的字節碼文件將不再保留;
- CLASS:注解信息將進入目標類代碼的字節碼文件中,但類加載器加載字節碼文件時不會將注解加載到JVM中,也即運行期不能獲取注解信息;
- RUNTIME:注解信息在目標類加載到JVM后依然保留,在運行期可以通過反射機制讀取類中注解信息。 ??
?Target(ElementType.METHOD)表示NeedTest這個注解只能應用到目標類的方法上,注解的應用目標在java.lang.annotation.ElementType類中定義:
- TYPE:類、接口、注解類、Enum聲明處,相應的注解稱為類型注解;
- FIELD:類成員變量或常量聲明處,相應的注解稱為域值注解;
- METHOD:方法聲明處,相應的注解稱為方法注解;
- PARAMETER:參數聲明處,相應的注解稱為參數注解;
- CONSTRUCTOR:構造函數聲明處,相應的注解稱為構造函數注解;
- LOCAL_VARIABLE:局部變量聲明處,相應的注解稱為局域變量注解;
- ANNOTATION_TYPE:注解類聲明處,相應的注解稱為注解類注解,ElementType. TYPE包括ElementType.ANNOTATION_TYPE;
- PACKAGE:包聲明處,相應的注解稱為包注解。
如果注解只有一個成員,則成員名必須取名為value(),在使用時可以忽略成員名和賦值號(=),如@NeedTest(true)。注解類擁有多個成員時,如果僅對value成員進行賦值則也可不使用賦值號,如果同時對多個成員進行賦值,則必須使用賦值號,如DeclareParents (value = "NaiveWaiter", defaultImpl = SmartSeller.class)。注解類可以沒有成員,沒有成員的注解稱為標識注解,解釋程序以標識注解存在與否進行相應的處理;此外,所有的注解類都隱式繼承于java.lang.annotation.Annotation,但注解不允許顯式繼承于其他的接口。
我們希望使用NeedTest注解對業務類的方法進行標注,以便測試工具可以根據注解情況激活或關閉對業務類的測試。在編寫好NeedTest注解類后,就可以在其他類中使用它了。
使用注解
我們在ForumService中使用NeedTest注解,標注業務方法是否需要測試,如代碼清單7-2所示:
代碼清單7-2? ForumService:使用注解
如果注解類和目標類不在同一個包中,需要通過import引用的注解類。在①和②處,我們使用NeedTest分別對deleteForum()和deleteTopic()方法進行標注。在標注注解時,可以通過以下格式對注解成員進行賦值:
如果成員是數組類型,可以通過{}進行賦值,如boolean數組的成員可以設置為{true,false,true}。下面是幾個注解標注的例子:
示例1,多成員的注解:
示例2,一個成員的注解,成員名為value。可以省略成員名和賦值符號:
示例3,無成員的注解:
示例4,成員為字符串數組的注解:
示例5,成員為注解數組類型的注解:
@Reviews注解擁有一個@Review注解數組類型的成員,@Review注解類型有三個成員,其中reviewer、comment都是String類型,但comment有默認值,grade是枚舉類型的成員。
由于NeedTest注解的保留限期是RetentionPolicy.RUNTIME類型,因此當ForumService被加載到JVM時,仍就可通過反射機制訪問到ForumService各方法的注解信息。
訪問注解
前面提到過,注解不會直接影響程序的運行,但是第三方程序或工具可以利用代碼中的注解完成特殊的任務,間接控制程序的運行。對于RetentionPolicy.RUNTIME保留期限的注解,我們可以通過反射機制訪問類中的注解。
在JDK5.0里,Package、Class、Constructor、Method以及Field等反射對象都新增了訪問注解信息的方法:<T extends Annotation>T getAnnotation(Class<T> annotationClass),該方法支持通過泛型直接返回注解對象。
下面,我們就通過反射來訪問注解,得出ForumService 類中通過@NeedTest注解所承載的測試需求,如代碼清單7-3所示:
代碼清單7-3? TestTool:訪問代碼中的注解
??
package com.baobaotao.aspectj.anno; import java.lang.reflect.Method; public class TestTool {public static void main(String[] args) {//①得到ForumService對應的Class對象Class clazz = ForumService.class; //②得到ForumSerivce對應的Method數組Method[] methods = clazz.getDeclaredMethods(); System.out.println(methods.length);for (Method method : methods) {//③獲取方法上所標注的注解對象NeedTest nt = method.getAnnotation(NeedTest. class);if (nt != null) {if (nt.value()) {System.out.println(method.getName() + "()需要測試");} else {System.out.println(method.getName() + "()不需要測試");}}}} }
在③處,通過方法的反射對象,我們獲取了方法上所標注的NeedTest注解對象,接著就可以訪問注解對象的成員,從而得到ForumService類方法的測試需求。運行以上代碼,輸出以下的信息:
deleteTopic()不需要測試
總結
以上是生活随笔為你收集整理的JDK5--Annotation学习:基础(二)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: JDK5--Annotation学习:基
- 下一篇: tomcat quartz 被触