自定义Java注解

Annotation(注解)是JDK5.0版本开始引入的,是附加在代码中的一些元信息,用于一些工具在编译、运行时进行解析和使用,起到说明、配置的功能。注解不会直接影响到程序的语义,只是作为注解(标识)存在,可以通过反射机制编程实现对这些元数据的访问。

在Java开发过程中,我们过去比较常见的方式是将软件的各种配置参数存贮在XML文件中,程序运行时从XML配置文件中读取出各配置参数进行运行时环境配置。这个方式使用程序运行灵活的同时也带来一个问题:就是XML配置文件越来越多,不易管理。注解引进后,减少配置、使用注解替代部分XML配置慢慢变成一种趋势。从某种角度来讲,注解具有XML配置的功能,它可有不同的预定义属性,属性值可以在声明该标时指定。在代码中使用注解,就相当于把一部分元数据从XML文件移到了代码本身,并在代码中进行管理和维护。这使得配置文件变得越来越少,而规范约定和注解代替了一些繁琐的配置信息。我们可以在许多Java开源项目中看到这种“零配置”的思维。

那么如何来自定义和使用注解呢(这里主要说明运行时使用注解)? 

要实现一个自定义注解,首先需要通过关键字@interface来定义一个注解标记。例:

@Retention(RetentionPolicy.RUNTIME)

@Target(ElementType.METHOD)

public @interface MyAnnotation {

    String name() default "abc";

    MyEnum type() default MyEnum.A;

    enum MyEnum {

        A, B

    }

}

在上例中,通过元注解来描述该注解的使用范围( @Target )、生命周期( @Retention ),并定义了一个注解标记。我们对@Target、@Retention进行一个简单说明:

@Target 用于描述注解的使用范围(即:被描述的注解可以用在什么地方),其取值有:

取值

描述

CONSTRUCTOR

构造器声明

FIELD

域声明

LOCAL_VARIABLE

局部变量声明

METHOD

方法声明

PACKAGE

包声明

PARAMETER

参数声明

TYPE

类或接口声明

 

@Retention 用于描述注解的生命周期(即:被描述的注解在什么范围内有效),其取值有:

取值

描述

SOURCE

注解将被编译器丢弃

CLASS

注解在class文件中可用,但会被VM丢弃

RUNTIME

将在运行期保留注解,可通过反射机制读取注解的信息

 

定义好注解标记后,我们就可以在代码中使用这个注解了,如:

@ MyAnnotation (type="B”, name="Hello World")

public void anyMethod() {

         ... ...

}

 

但要使用注解标记工作起来,我们还需要编写这个注解标记的处理器(注解处理器是一段用于解释或处理自定义注解标记的代码),它是通过java的反射机制来进行解析。如下:

public class MyAnnotationTest {

    @MyAnnotation(name = "a", type = MyAnnotation.MyEnum.B)

    public void execute() {

        System.out.println("method");

    }

    public static void main(String[] args) throws SecurityException, NoSuchMethodException, IllegalArgumentException, IllegalAccessException, InvocationTargetException {

        MyAnnotationTest annotationTest = new MyAnnotationTest();

        //获取MyAnnotationTest的Class实例

        Class<MyAnnotationTest> c = MyAnnotationTest.class;

        //获取需要处理的方法Method实例

        Method method = c.getMethod("execute", new Class[]{});

        //判断该方法是否包含MyAnnotation注解

        if (method.isAnnotationPresent(MyAnnotation.class)) {

            //获取该方法的MyAnnotation注解实例

            MyAnnotation myAnnotation = method.getAnnotation(MyAnnotation.class);

            //执行该方法

            method.invoke(annotationTest, new Object[]{});

            //获取myAnnotation

            String value = myAnnotation.name();

            System.out.println(value);

        }

        //获取方法上的所有注解

        Annotation[] annotations = method.getAnnotations();

        for (Annotation annotation : annotations) {

            System.out.println(annotation);

        }

    }

}

 以上代码仅仅是示意如何使用反射来得到注解信息。

在实际的应用中,我们可以采用注解来描述数据,大致过程如此:创建一个JavaBean,使用注解来描述这个JavaBean的语义。这个用法类似于用XML来描述一个数据,每个字段注解对应于XML的属性元素,字段的取值对应于XML的属性值,当然数据本身也可用XML来进行描述。这种方式常见于接口间的数据描述,最常见的如数据库连接信息。

另一种用法,就是类似于使用XML来配置运行时所需要的数据,比如我们常见的Spring MVC的注解配置方式,如:

       @RequestMapping(value = {"xxx"}, method = {org.springframework.web.bind.annotation.RequestMethod.POST})

表示POST请求输入为xxx时,调用该方法。如果我们在XML中进行配置,就类似于:

       <value>xxx</value><method>POST</method><invoke>xxx.xxx(xxx类的xxx方法)</invoke>

这种方式在过去的开发中,我们是常见的。比如网管软件开发时,对多网元多版本进行控制时,我们过去就常将网元类型、版本和它的处理方法配置在一个配置文件中,而这种方式也可用注解方式来解决。

另外,就是在某些API方法中使用注解对API的调用条件进行限制等。

当然这些处理都需要一个注解标记处理框架。需要注意的是,Annoation的表达能力有限,不如XML的强,所以在应用时应该考虑使用那种方式更简便。

 

 

附:

java5.0在java.lang包中定义了3种标准的annotation类型:A. Override,B. Deprecated,C. SuppressWarnings。并且还定义了4个标准的meta-annotation类型,它们被用来提供对其它annotation类型作说明:@Target、@Retention、@Documented、@Inherited。

posted @ 2013-03-27 22:57  Jevo  阅读(290)  评论(0编辑  收藏  举报