反射与Annotation

反射与Annotation

一.反射与Annotation
  从JDK1.5之后,java开发提供了Annotation技术支持,这种技术为项目的编写带来的新的模型,经过了多年的发展,Annotation的技术得到了非常广泛的应用,并且已经在所有的项目开发之中都会存在.
--获取Annotation:在进行类或方法定义的时候都可以使用一系列的Annotation进行色声明,于是如果要想获取这些Annotation的信息,那么就可以直接通过反射来完成.在java.lang.reflect里面,有一个叫做AccessibleObject类,在这个类中提供有获取Annotation的方法:
  获取全部Annotation: public Annotation[] getAnnotations()
  获取指定的Annotation: public <T extends Annotation> T getAnnotation(Class<T> annotationClass)
--范例:定义一个接口,并且在接口上使用Annotation

 1 package 反射.反射与Annotation;
 2 
 3 import java.lang.annotation.Annotation;
 4 
 5 /**
 6  * @author : S K Y
 7  * @version :0.0.1
 8  */
 9 @FunctionalInterface
10 @Deprecated
11 interface IMessage {            //存在两个Annotation注解
12     public void send();
13 }
14 
15 @SuppressWarnings("serial")
16 class MessageImpl implements IMessage {
17     @Override
18     public void send() {
19         System.out.println("消息发送...");
20     }
21 }
22 
23 public class AnnotationDemo {
24     public static void main(String[] args) {
25         //获取接口上的Annotation信息
26         Annotation[] annotations = IMessage.class.getAnnotations();     //获取接口上的所有的Annotation
27         for (Annotation annotation : annotations) {
28             System.out.println(annotation);
29         }
30     }
31 }

--运行结果

@java.lang.FunctionalInterface()
@java.lang.Deprecated()

Process finished with exit code 0

--尝试获取实现类的注解信息

 1 public class AnnotationDemo {
 2     public static void main(String[] args) {
 3         //获取接口上的Annotation信息
 4         Annotation[] annotations = IMessage.class.getAnnotations();     //获取接口上的所有的Annotation
 5         for (Annotation annotation : annotations) {
 6             System.out.println(annotation);
 7         }
 8         System.out.println("=========================");
 9         //获取子类上的Annotation
10         Annotation[] implAnnotations = MessageImpl.class.getAnnotations();
11         for (Annotation implAnnotation : implAnnotations) {
12             System.out.println(implAnnotation);
13         }
14     }
15 }

--运行结果

@java.lang.FunctionalInterface()
@java.lang.Deprecated()
=========================

Process finished with exit code 0

--发现并没有获取到注解@SuppressWarnings("serial"),其原因是该注解无法在程序执行的时候获取.那么尝试获取MessageImpl.send()方法上的Annotation会怎么样呢:

 1 public class AnnotationDemo {
 2     public static void main(String[] args) throws NoSuchMethodException {
 3         //获取接口上的Annotation信息
 4         Annotation[] annotations = IMessage.class.getAnnotations();     //获取接口上的所有的Annotation
 5         for (Annotation annotation : annotations) {
 6             System.out.println(annotation);
 7         }
 8         System.out.println("=========================");
 9         //获取子类上的Annotation
10         Annotation[] implAnnotations = MessageImpl.class.getAnnotations();
11         for (Annotation implAnnotation : implAnnotations) {
12             System.out.println(implAnnotation);
13         }
14         //尝试获取MessageImpl.toString()方法上的Annotation
15         System.out.println("==============================");
16         Method send = MessageImpl.class.getDeclaredMethod("send");
17         Annotation[] sendAnnotations = send.getAnnotations();
18         for (Annotation sendAnnotation : sendAnnotations) {
19             System.out.println(sendAnnotation);
20         }
21     }
22 }

--运行结果

@java.lang.FunctionalInterface()
@java.lang.Deprecated()
=========================
==============================

Process finished with exit code 0

--可以发现也无法在运行时获取到 @Override注解的相关信息.不同的Annotation有他的存在的范围:
  @FunctionalInterface:

    @Documented
    @Retention(RetentionPolicy.RUNTIME)      //描述的是运行是生效
    @Target(ElementType.TYPE)
    public @interface FunctionalInterface {}

  @SuppressWarnings("serial"):

    @Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE})
    @Retention(RetentionPolicy.SOURCE)      //描述的是在源代码时生效
    public @interface SuppressWarnings {
    String[] value();
    }

--可以发现"@FunctionalInterface"是在程序运行时生效的Annotation,所以当程序执行的时候可以获取此Annotation,而"@SuppressWarnings"是在源代码编写的时候有效.管观察RetentionPolicy的定义:

public enum RetentionPolicy {

SOURCE,

CLASS,

RUNTIME
}

--在RetentionPolicy枚举类中还存在一个class的定义指的是在类定义的时候生效.

二.自定义Annotation
  现在已经清楚了Annotation的获取,以及Annotation的运行策略,但是最为关键性的因素是如何可以实现自定义的Annotation.为此在java中提供有新的语法使用"@interface"来定义Annotation.
范例:自定义Annotation

 1 package 反射.反射与Annotation;
 2 
 3 import java.lang.annotation.Retention;
 4 import java.lang.annotation.RetentionPolicy;
 5 import java.lang.reflect.InvocationTargetException;
 6 import java.lang.reflect.Method;
 7 
 8 /**
 9  * @author : S K Y
10  * @version :0.0.1
11  */
12 @Retention(RetentionPolicy.RUNTIME)
13         //定义Annotation运行时的策略
14 @interface DefaultAnnotation {       //自定义的Annotation,
15     public String title();      //获取数据
16 
17     public String url() default "获取数据的默认值";     //获取数据,默认值
18 }
19 
20 class Message {
21     @DefaultAnnotation(title = "sendMessage")   //title不具备默认值,因此必须去显示的定义
22     public void send(String msg) {
23         System.out.println("[消息发送]" + msg);
24     }
25 }
26 
27 public class MyAnnotationDemo {
28     public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
29         Method method = Message.class.getDeclaredMethod("send", String.class);  //获取指定的方法
30         DefaultAnnotation annotation = method.getAnnotation(DefaultAnnotation.class);//获取指定的Annotation1
31         String title = annotation.title();      //直接调用Annotation中的方法
32         String url = annotation.url();
33         System.out.println(title + " " + url);
34         String msg = annotation.title() + " " + url;
35         method.invoke(Message.class.getDeclaredConstructor().newInstance(),msg);        //利用反射实现消息的发送
36     }
37 }

--运行结果

sendMessage 获取数据的默认值
[消息发送]sendMessage 获取数据的默认值

Process finished with exit code 0

--使用Annotation之后的最大特点是可以结合反射机制实现程序的处理.

三.工厂设计模式与Annotation整合
  在清楚了Annotation的整体作用之后,但是Annotation在开发之中,到底可以完成什么样的功能.为了更好的理解Annotation的处理操作的目的,下面将结合工厂设计模式来应用Annotation操作.

 1 package 反射.Annotation与工厂设计模式整合;
 2 
 3 
 4 import java.lang.reflect.InvocationHandler;
 5 import java.lang.reflect.Method;
 6 import java.lang.reflect.Proxy;
 7 
 8 /**
 9  * @author : S K Y
10  * @version :0.0.1
11  */
12 interface IMessage {
13     public void send(String msg);
14 }
15 
16 class MessageImpl implements IMessage {
17     @Override
18     public void send(String msg) {
19         System.out.println("[消息发送]" + msg);
20     }
21 }
22 
23 class MessageProxy implements InvocationHandler {
24     private Object target;
25 
26 
27     public Object bind(Object target) {
28         this.target = target;
29         return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
30     }
31 
32     public boolean connect() {
33         System.out.println("[代理操作]进行消息发送通道的连接");
34         return true;
35     }
36 
37     public void close() {
38         System.out.println("[代理操作]关闭连接通道.");
39     }
40 
41     @Override
42     public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
43         try {
44             if (this.connect()) {
45                 return method.invoke(this.target, args);
46             } else {
47                 throw new Exception("[error]消息无法进行发送");
48             }
49         } finally {
50             this.close();
51         }
52     }
53 }
54 
55 class Factory {
56     private Factory() {
57     }
58     public static <T> T getInstance(Class<T> tClass) {       //直接返回一个实例化的操作对象
59         try {
60             return (T) new MessageProxy().bind(tClass.getDeclaredConstructor().newInstance());
61         } catch (Exception e) {
62             e.printStackTrace();
63             return null;
64         }
65     }
66 }
67 class MessageService{
68     private IMessage message;
69 
70     public MessageService() {
71         this.message = Factory.getInstance(MessageImpl.class);
72     }
73     public void send(String msg){
74         this.message.send(msg);
75     }
76 }
77 public class AnnotationFactoryDemo {
78     public static void main(String[] args) throws IllegalAccessException, InstantiationException {
79        MessageService service = new MessageService();
80        service.send("hello");
81 
82     }
83 }

--运行结果

[代理操作]进行消息发送通道的连接
[消息发送]hello
[代理操作]关闭连接通道.

Process finished with exit code 0

--上述代码的实现每次都需要在MessageService类中给出MessageImpl.class的声明,使用注解形式来简化代码

 1 package 反射.Annotation与工厂设计模式整合;
 2 
 3 
 4 import java.lang.annotation.Retention;
 5 import java.lang.annotation.RetentionPolicy;
 6 import java.lang.reflect.InvocationHandler;
 7 import java.lang.reflect.Method;
 8 import java.lang.reflect.Proxy;
 9 
10 /**
11  * @author : S K Y
12  * @version :0.0.1
13  */
14 interface IMessage {
15     public void send(String msg);
16 }
17 
18 class MessageImpl implements IMessage {
19     @Override
20     public void send(String msg) {
21         System.out.println("[消息发送]" + msg);
22     }
23 }
24 
25 class MessageProxy implements InvocationHandler {
26     private Object target;
27 
28 
29     public Object bind(Object target) {
30         this.target = target;
31         return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
32     }
33 
34     public boolean connect() {
35         System.out.println("[代理操作]进行消息发送通道的连接");
36         return true;
37     }
38 
39     public void close() {
40         System.out.println("[代理操作]关闭连接通道.");
41     }
42 
43     @Override
44     public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
45         try {
46             if (this.connect()) {
47                 return method.invoke(this.target, args);
48             } else {
49                 throw new Exception("[error]消息无法进行发送");
50             }
51         } finally {
52             this.close();
53         }
54     }
55 }
56 
57 class Factory {
58     private Factory() {
59     }
60     public static <T> T getInstance(Class<T> tClass) {       //直接返回一个实例化的操作对象
61         try {
62             return (T) new MessageProxy().bind(tClass.getDeclaredConstructor().newInstance());
63         } catch (Exception e) {
64             e.printStackTrace();
65             return null;
66         }
67     }
68 }
69 @Retention(RetentionPolicy.RUNTIME)
70 @interface UseMessage{
71     public Class<?> thisClass();
72 }
73 @UseMessage(thisClass = MessageImpl.class)
74 class MessageService{
75     private IMessage message;
76 
77     public MessageService() {
78         UseMessage annotation = MessageService.class.getAnnotation(UseMessage.class);
79         this.message = (IMessage) Factory.getInstance(annotation.thisClass());
80     }
81     public void send(String msg){
82         this.message.send(msg);
83     }
84 }
85 public class AnnotationFactoryDemo {
86     public static void main(String[] args) throws IllegalAccessException, InstantiationException {
87        MessageService service = new MessageService();
88        service.send("hello");
89 
90     }
91 }

--这样我们就可以依据注解来修改整个程序的功能实现.由于Annotation的存在,对于面向接口的配置处理可以直接利用Annotation的属性完成控制,从而使得整体代码变得简洁.