在创建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(); } |
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("测试失败"); } } |
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); } } |
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) |
| @Retention | 1. SOURCE//按照规定使用注释,但是并不将它保留到编译后的类文件中 2. CLASS//将注释保留在编译后的类文件中,但是在运行时忽略它 3. RUNTIME//将注释保留在编译后的类文件中,并在第一次加载类时读取它 |
| @Documented | Documented 表示注释应该出现在类的 Javadoc 中 |
| @Inherited | 一个Annotation将被继承 |
三个标准的Annotation 在java.lang包中:
| @Deprecated | 对不再使用的方法进行注释 |
| @Override | 指明注释的方法覆盖超类的方法 |
| @SuppressWarnings | 阻止编译器的警告,例:当类型不安全时 |
| 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
一个组合的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());
}
}
}
http://www.wujianrong.com/mt-tb.cgi/5865