在创建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对...)”
- packagesz.starbex.bill.annotation;
- importjava.lang.annotation.Retention;
- importjava.lang.annotation.RetentionPolicy;
- importjava.lang.annotation.Target;
- importjava.lang.annotation.ElementType;
- @Retention(RetentionPolicy.RUNTIME)
- @Target(ElementType.METHOD)
- public@interfaceSimpleAnnotation{
- Stringvalue();
- }
//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
- packagesz.starbex.bill.annotation;
- importsz.starbex.bill.annotation.SimpleAnnotation;
- publicclassUsingSimpleAnnotation{
- @SimpleAnnotation(value="Pass:ThismethodwillPass")
- publicvoidpass(){
- if(10>5)System.out.println("测试通过");
- }
- @SimpleAnnotation("Fail:ThismethodwillFail")
- publicvoidfail(){
- if(10<5)System.out.println("测试失败");
- }
- }
//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
- packagesz.starbex.bill.annotation;
- importsz.starbex.bill.annotation.SimpleAnnotation;
- importjava.lang.reflect.Method;
- publicclassSimpleAccessAnnotation{
- staticvoidaccessAnnotationTest(ClassusingAnnnotationClass){
- try{
-
- Method[]methods=usingAnnnotationClass.getDeclaredMethods();
- for(Methodmethod:methods){
- System.out.println(method.getName());
- SimpleAnnotation
- simpleAnnotation=method.getAnnotation(SimpleAnnotation.class);
- if(simpleAnnotation!=null){
- System.out.print(simpleAnnotation.value()+"==");
- Stringresult=invoke(method,usingAnnnotationClass);
- System.out.println(result);
- }
- }
- }catch(Exceptione){
-
- e.printStackTrace();
- }
- }
- staticStringinvoke(Methodm,Objecto){
- Stringresult="passed";
- try{
- m.invoke(m,newObject[]{});
- }catch(Exceptione){
-
- result="failed";
- }
- returnresult;
- }
-
- publicstaticvoidmain(String[]args){
-
- accessAnnotationTest(UsingSimpleAnnotation.class);
- }
- }
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);
}
}
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:
- packagesz.starbex.bill.annotation;
- importjava.util.ArrayList;
- importjava.util.List;
- publicclassSimpleOverrideAnnotation{
- publicstaticvoidmain(String[]args){
- SimpleOverrideAnnotationtest=newSimpleOverrideAnnotation();
- System.out.println(test.toString());
- }
- @Override
- publicStringtoString(){
- return"自己的类自己输出";
- }
- @Deprecated
- publicvoiddoSomething(){
- System.out.println("方法已过时");
- }
- @SuppressWarnings(value={"unchecked"})
- publicvoidtestSuppressWarnings(){
- ListtestList=newArrayList();
- testList.add("KKKK");
- }
- }
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
- packagesz.starbex.bill.annotation;
- public@interfaceTrademark{
- Stringname();
- Stringowner();
- }
package sz.starbex.bill.annotation;
public @interface Trademark {
String name();
String owner();
}
b.License的annotation
- packagesz.starbex.bill.annotation;
- importjava.lang.annotation.*;
- @Retention(RetentionPolicy.RUNTIME)
- @Target({ElementType.TYPE,ElementType.PACKAGE})
- public@interfaceLicense{
- Stringname();
- Stringnotice();
- booleanredistributable();
- Trademark[]trademarks();
- }
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.测试类
- packagesz.starbex.bill.annotation;
- @License(name="Bill",
- notice="许可证",
- redistributable=true,
- trademarks={@Trademark(name="Mercedes",owner="Swedish"),
- @Trademark(name="Daewoo",owner="Korean")
- }
- )
- publicclassTestLicenseAnnotation{
- publicstaticvoidmain(String[]args){
- TestLicenseAnnotationtest=newTestLicenseAnnotation();
- Licenselicense=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(Trademarkmark:marks){
- System.out.println("商标名称:"+mark.name());
- System.out.println("商标的使用者:"+mark.owner());
- }
- }
- }
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());
}
}
}