在創建EJB組件時,必需提供一些定義,使得EJB組件使用一些服務例如:安全服務,持久化服務,事務服務。EJB容器可以提供這些服務,這樣EJB只要實現業務邏輯就可以了。但是說到底EJB容器使用EJB組件的元數據來提供這些服務,在以前EJB的元數據是以XML配置文件形式出現的,這些配置文件與EJB源文件是分開的。
EJB的部署人員無法了解EJB本身的信息,如果EJB組件的創建者用注釋(Annotation)的方法將這些配置服務的信息和代碼放在一起,這樣EJB的部署者就可以了解EJB的信息,EJB的home接口可以使用Annotation自動生成,當然到目前為止更好的是在簡單的Java Object上使用Annotations。
一 什麼是Annotation
在已經發布的JDK1.5(tiger)中增加新的特色叫 Annotation。Annotation提供一種機制,將程序的元素如:類,方法,屬性,參數,本地變量,包和元數據聯系起來。這樣編譯器可以將元數據存儲在Class文件中。這樣虛擬機和其它對象可以根據這些元數據來決定如何使用這些程序元素或改變它們的行為。
二 定義一個簡單的Annotation並使用它
1.定義Annotation
定義一個Annotation是什麼簡單的,它采取的是類似於Interface的定義方式: “@+annotation類型名稱+(..逗號分割的name-value對...)”
//Example 1
package sz.starbex.bill.annotation;
import Java.lang.annotation.Retention;
import Java.lang.annotation.RetentionPolicy;
import Java.lang.annotation.Target;
import Java.lang.annotation.ElementType;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface SimpleAnnotation {
String value();
}
@Retention這個meta-annotation表示我們創建的SimpleAnnotation這個Annotation將會存儲在Class文件中,並在Java
VM運行時加載它。@Target這個meta-annotation表示我們創建的SimplwAnnotation將會為描述方法,而@interface SimpleAnnotation是我們自定義的Annotation,它有一個成員叫value,返回值是String。
2.使用Annotation
//Example 2
package sz.starbex.bill.annotation;
import sz.starbex.bill.annotation.SimpleAnnotation;
public class UsingSimpleAnnotation {
@SimpleAnnotation(value="Pass:This method will Pass")//注意name=value的用法
public void pass(){
if(10>5) System.out.println("測試通過");
}
@SimpleAnnotation("Fail:This method will Fail")//注意name=value的用法
public void fail(){
if(10<5) System.out.println("測試失敗");
}
}
一個Annotation用於程序元素(在本例中是method),在method方法之前用(@Annotation名稱(name=value,name=value.....)。在本例中是@SimpleAnnotation(value="Pass:This method will Pass")。每個annotation具有一個名字和成員個數>=0,當只有一個單一的成員時,這個成員就是value。我們也可以這樣寫 @SimpleAnnotation("Fail:This method will Fail")。至此@SimpleAnnotation將Pass和Fail聯系起來了。
3.在運行時訪問Annotation
一旦Annotation與程序元素聯系起來,我們可以通過反射訪問它們並可以取得它們的值。我們使用一個新的interface:java.lang.reflect.AnnotatedElement。Java.lang.reflect.AnnotatedElement接口中的方法有:
a. boolean isAnnotationPresent(Class annotationType)
如果指定類型的注釋存在於此元素上,則返回 true,否則返回 false。
b. T getAnnotation(Class annotationType)
如果存在該元素的指定類型的注釋,則返回這些注釋,否則返回 null。
c. Annotation[] getAnnotations()
返回此元素上存在的所有注釋。
d. Annotation[] getDeclaredAnnotations()
返回直接存在於此元素上的所有注釋。
你要注意 isAnnotationPresent和getAnnotation方法,它們使用了Generics,請參考我的Java 范型的Blog。
下面我們列出一些實現了AnnotatedElement 接口的類
1. Java.lang.reflect.AccessibleObject
2. Java.lang.Class
3. Java.lang.reflect.Constructor
4. Java.lang.reflect.FIEld
5. Java.lang.reflect.Method
6. Java.lang.Package
下面的Example程序說明了如何在運行環境訪問Annotation
package sz.starbex.bill.annotation;
import sz.starbex.bill.annotation.SimpleAnnotation;
import Java.lang.reflect.Method;
public class SimpleAccessAnnotation {
static void AccessAnnotationTest(Class usingAnnnotationClass){
try {
//Object usingAnnnotationClass=Class.forName(usingAnnotationClassName).newInstance();
Method [] methods=usingAnnnotationClass.getDeclaredMethods();//取得對方法
for(Method method:methods){
System.out.println(method.getName());
SimpleAnnotation
simpleAnnotation=method.getAnnotation(SimpleAnnotation.class);//得到方法的Annotation
if(simpleAnnotation!=null){
System.out.print(simpleAnnotation.value()+"==");
String result=invoke(method,usingAnnnotationClass);
System.out.println(result);
}
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
static String invoke(Method m, Object o) {
String result = "passed";
try {
m.invoke(m,new Object[]{});
} catch (Exception e) {
// TODO Auto-generated catch block
result = "failed";
}
return result;
}
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
AccessAnnotationTest(UsingSimpleAnnotation.class);
}
}
以上是簡單的簡紹Annotation,讓大家對Annotation有一個初步的了解,下面二會簡紹Annotation的定義和語法。
Java中的Annotation解析之二
一、Java 中的Annotation的定義
Java中的Annotation
Java定義了幾個標准的meta-annotation,在新Package中Java.lang.annotation 中包含了以下meta-annotation:
meta-annotation 說明
@Target 1. annotation的target是一個被標注的程序元素。target說明了annotation所修飾的對象范圍:annotation可被用於packages、types(類、接口、枚舉、annotation類型)、類型成員(方法、構造方法、成員變量、枚舉值)、方法參數和本地變量(如循環變量、catch參數)。在annotation類型的聲明中使用了target可更加明晰其修飾的目標。
meta-annotation
說明
@Target
1. annotation的target是一個被標注的程序元素。target說明了annotation所修飾的對象范圍:annotation可被用於packages、types(類、接口、枚舉、annotation類型)、類型成員(方法、構造方法、成員變量、枚舉值)、方法參數和本地變量(如循環變量、catch參數)。在annotation類型的聲明中使用了target可更加明晰其修飾的目標。
2. ElementType的定義
TYPE// Class, interface, or enum (but not annotation)
FIELD// FIEld (including enumerated values)
METHOD// Method (does not include constructors)
PARAMETER// Method parameter
CONSTRUCTOR// Constructor
LOCAL_VARIABLE// Local variable or catch clause
ANNOTATION_TYPE// Annotation Types (meta-annotations)
PACKAGE// Java package
@Retention
1. SOURCE//按照規定使用注釋,但是並不將它保留到編譯後的類文件中
2. CLASS//將注釋保留在編譯後的類文件中,但是在運行時忽略它
3. RUNTIME//將注釋保留在編譯後的類文件中,並在第一次加載類時讀取它
@Documented
Documented 表示注釋應該出現在類的 Javadoc 中
@Inherited
一個Annotation將被繼承
三個標准的Annotation 在Java.lang包中:
@Deprecated
對不再使用的方法進行注釋
@Override
指明注釋的方法覆蓋超類的方法
@SuppressWarnings
阻止編譯器的警告,例:當類型不安全時
下例來說明這三個標准的Annotation:
package sz.starbex.bill.annotation;
import Java.util.ArrayList;
import Java.util.List;
public class SimpleOverrideAnnotation {
public static void main(String[] args) {
SimpleOverrideAnnotation test = new SimpleOverrideAnnotation();
System.out.println(test.toString());
}
@Override
public String toString() {
return "自己的類自己輸出";
}
@Deprecated
public void DOSomething() {
System.out.println("方法已過時" );
}
@SuppressWarnings(value={"unchecked"})
public void testSuppressWarnings(){
List testList=new ArrayList();
testList.add("KKKK");//沒有使用范型,類型不安全
}
}
二、Annotation使用實例
一個組合的Annotation,注釋類的
a. 商標Annotation
package sz.starbex.bill.annotation;
public @interface Trademark {
String name();
String owner();
}
b.License的annotation
package sz.starbex.bill.annotation;
import Java.lang.annotation.*;
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.PACKAGE})
public @interface License {
String name();
String notice();
boolean redistributable();
Trademark[] trademarks();
}
c.測試類
package sz.starbex.bill.annotation;
@License(name="Bill",
notice="許可證",
redistributable=true,
trademarks={@Trademark(name="Mercedes",owner="Swedish"),
@Trademark(name="Daewoo",owner="Korean")
}
)
public class TestLicenseAnnotation {
public static void main(String[] args) {
TestLicenseAnnotation test=new TestLicenseAnnotation();
License license=test.getClass().getAnnotation(License.class);
System.out.println("License發放人:"+license.name());
System.out.println("License注意事項:"+license.notice());
System.out.println("License許可:"+license.redistributable());
Trademark [] marks=license.trademarks();
for(Trademark mark:marks){
System.out.println("商標名稱:"+mark.name());
System.out.println("商標的使用者:"+mark.owner());
}
}
}