反射与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
package cn.mldn.demo;
import java.io.Serializable;
import java.lang.annotation.*;
import java.lang.reflect.Method;
public class reflect_Annotation {
public static void main(String[] args) throws Exception{
{ //获取接口的Annotation信息
Annotation annotation[] = IMessage.class.getAnnotations(); //获取全部Annotation
for(Annotation temp: annotation) {
System.out.println(temp);
}
}
System.out.println("***********************************");
{ //获取子类的Annotation信息
Annotation annotation[] = MessageImpl.class.getAnnotations(); //获取全部Annotation
for(Annotation temp: annotation) {
System.out.println(temp);
}
}
System.out.println("***********************************");
{ //获取子类.toString()方法的Annotation信息
Method methods = MessageImpl.class.getDeclaredMethod("send", String.class);
Annotation annotation[] = methods.getAnnotations(); //获取全部Annotation
for(Annotation temp: annotation) {
System.out.println(temp);
}
}
}
}
@FunctionalInterface
@Deprecated(since="1.0")
interface IMessage{ //有两个Annotation
public void send(String msg);
}
@SuppressWarnings("serial") //这个Annotation无法在程序执行时获取
class MessageImpl implements IMessage,Serializable{
@Override //这个Annotation无法在程序执行时获取
public void send(String msg) {
System.out.println("[消息发送]" + msg);
}
}
不同的Annotation有存在的范围。下面对比两个Annotation:
@FunctionalInterface(运行时生效) | @SuppressWarnings(源代码生效) |
---|---|
@Doucment @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) public @interface FunctionalInterface{} | @Target({TYPE,FIELD,METHOD,PARAMETER,CONSTRUCTOR,LOCAL_VARIABLE,MODULE}) @Retention(RetentionPolicy.SOURCE) public @interface SuppressWarnings{} |
运行时生效是在程序运行时生效的Annotation,而另外一个则为源代码编写时有效。而RentationPolice枚举类中还有一个Class定义,指的是在类定义的时候生效。
自定义Annotation
最为关键性的是实现自定义的Annotation,为此Java中提供新的语法,使用“@interface”来定义Annotation。
自定义Annotation
package cn.mldn.demo;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.reflect.Method;
public class reflect_Annotation {
public static void main(String[] args) throws Exception{
Method method = MessageT.class.getMethod("send", String.class);
DefaultAnnotation annotation = method.getAnnotation(DefaultAnnotation.class); //获取指定Annotation
System.out.println(annotation.title()); //调用annotation中的方法
System.out.println(annotation.url());
String msg = annotation.title() + "-" + annotation.url();
method.invoke(MessageT.class.getDeclaredConstructor().newInstance(), msg);
}
}
class MessageT{
@DefaultAnnotation(title = "test")
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 "www.baidu.com"; //获取数据,默认值
}
使用Annotation之后最大特点是可以结合反射机制实现程序的处理。
工厂设计模式与Annotation整合
为了进一步了解Annotation在开发中处理的目的,结合工厂设计模式应用Annotation操作。
工厂、代理以及Annotation相结合
package cn.mldn.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 reflect_Annotation {
public static void main(String[] args) throws Exception{
MessageService messageService = new MessageService();
messageService.send("www.baidu.com");
}
}
@Retention(RetentionPolicy.RUNTIME)
@interface UseMessage{
public Class<?> clazz();
}
@UseMessage(clazz = NetMessageImpl.class)
class MessageService{
private IMessage message;
public MessageService() {
UseMessage use = MessageService.class.getAnnotation(UseMessage.class);
this.message = (IMessage)Factory.getInstance(use.clazz()); //直接通过Annotation获取,使用Annotation实现类的使用
}
public void send(String msg) {
this.message.send(msg);
}
}
class Factory{
private Factory() {}
public static <T> T getInstance(Class<T> clazz) { //直接返回一个实例化对象
try {
return (T) new MessageProxyz().bind(clazz.getDeclaredConstructor().newInstance());
} catch(Exception e) {
e.printStackTrace();
return null;
}
}
}
interface IMessage{
public void send(String msg);
}
class MessageImpl implements IMessage{
@Override
public void send(String msg) {
System.out.println("[Message send]" + msg);
}
}
class NetMessageImpl implements IMessage{
@Override
public void send(String msg) {
System.out.println("[NetMessage send]" + msg);
}
}
class MessageProxyz 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("[Proxy]消息通道建立");
return true;
}
public void close() {
System.out.println("[Proxy]消息通道关闭");
}
@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]消息发送失败");
}
} finally{
this.close();
}
}
}
由于Annotation的存在,所以面向接口的编程配置处理可以直接利用Annotation的属性进行控制,从而使得整体代码变得简洁。