1 反射取得Annotation信息
从JDK 1.5之后Java开发提供了Annotation技术支持,这种技术为项目编写带来了新的模型,而后经过了十多年的发展,Annotation技术得到了非常广泛的应用,并且已经在所有的项目开发之中都会存在。
在进行类或方法定义的时候都可以使用一系列的Annotation进行声明,于是如果要想获取这些Annotation的信息,那么就可以直接通过反射来完成。在java.lang.reflect里面 有一个AccessibleObject类,在本类中提供有获取Annotation类的方法:
(1)获取全部Annotation:public Annotation[] getAnnotations()
(2)获取指定Annotation:public <T extends Annotation> T getAnnotation(Class<T> annotationClass)
范例:定义一个接口,并在接口上使用Annotation
package org.lks.demo;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.Arrays;
public class JavaReflectDemo {
public static void main(String[] args) {
Annotation[] annotation = IMessage.class.getAnnotations();
System.out.println(Arrays.toString(annotation));
try {
Object obj = MessageImpl.class.getDeclaredConstructor().newInstance();
Method method = obj.getClass().getMethod("send");
Annotation[] annotationClass = method.getAnnotations();
System.out.println(Arrays.toString(annotationClass));
}catch(Exception e) {}
}
}
@FunctionalInterface
@Deprecated(since="1.5")
interface IMessage{
void send();
}
@SuppressWarnings("oriented")
@Deprecated
class MessageImpl implements IMessage{
@Override
public void send() {
System.out.println("[message send]: hello!");
}
}
不同的Annotation有它的存在范围,下面对比了两个Annotation:
(1)@FunctionalInterface(运行时):
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface FunctionalInterface {}
(2)@SuppressWarnings(源代码时):
@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE, MODULE})
@Retention(RetentionPolicy.SOURCE)
public @interface SuppressWarnings {}
现在发现“@FunctionalInterface”是在运行时生效的得Annotation,所以当程序执行的时候可以获得此Annotation,而“@SuppressWarnings”是在源代码编写时有效。而在RetentionPolicy枚举类中还有一个class得定义,指的是在类定义的时候生效。
2 自定义Annotation
现在已经清楚了Annotation的获取以及Annotation得运行策略,但是最为关键性的因素是如何可以实现自定义的Annotation呢?为此在Java里面提供有新的语法,使用“@Interface”来定义Annotation。
范例:自定义Annotation
package org.lks.demo;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.reflect.Method;
public class JavaReflectDemo {
public static void main(String[] args) {
MessageA msgA = new MessageA();
try {
Method method = msgA.getClass().getDeclaredMethod("send", String.class);
DefaultAnnotation annotation = method.getAnnotation(DefaultAnnotation.class);
method.invoke(msgA, annotation.title());
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
class MessageA{
@DefaultAnnotation(title="lks")
public void send(String msg) {
System.out.println("[message send] " + msg);
}
}
@Retention(RetentionPolicy.RUNTIME) //定义Annotation得运行策略
@interface DefaultAnnotation { //自定义得Annotation
public String title(); //获取数据
public String url() default "org.lks.demo"; //获取数据,默认值
}
使用Annotation之后的最大特点是可以结合反射机制实现程序的处理。
3 工厂设计模式与Annotation
现在已经清楚了Annotation得整体作用,但是Annotation到底在开发之中能做哪些事情呢?为了帮助大家进一步理解Annotation得处理目的,下面将结合工厂设计模式来应用Annotation操作。
package org.lks.demo;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class JavaReflectDemo {
public static void main(String[] args) {
new MessageService().send();
}
}
@Retention(RetentionPolicy.RUNTIME)
@interface UseMessage{
public Class<?> clazz();
}
@UseMessage(clazz=MessageAImpl.class)
class MessageService implements IMessageA{
private IMessageA message;
public MessageService() {
UseMessage use = MessageService.class.getAnnotation(UseMessage.class);
this.message = (IMessageA) Factory.getInstance(use.clazz());
}
@Override
public void send() {
this.message.send();
}
}
class Factory{
public Factory() {}
public static <T> T getInstance(Class<T> clazz) {
try {
return (T) new MessageProxyA().bind(clazz.getDeclaredConstructor().newInstance());
}catch(Exception e) {
e.printStackTrace();
return null;
}
}
}
class MessageProxyA implements InvocationHandler{
private Object target;
public Object bind(Object target) {
this.target = target;
return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
}
public boolean connect() {
System.out.println("[message connected] sending ...");
return true;
}
public void close() {
System.out.println("[message closed] stop ...");
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
try{
if(this.connect()) {
return method.invoke(this.target, args);
}else{
throw new Exception("[ERROR] message can't be send");
}
}finally {
this.close();
}
}
}
interface IMessageA{
void send();
}
class MessageAImpl implements IMessageA{
@Override
public void send() {
System.out.println("[message send] hello ...");
}
}
由于Annotation得存在,所以对于面向接口编程的配置处理将可以直接利用Annotation的属性完成控制,从而使得整体代码变得简洁。