反射取得Annotation信息
从JDK1.5之后Java开发提供了Annotation技术支持,这种技术为项目的编写带来了新的模型,而后经过十多年的发展,Annotation技术已经得到了广泛应用,并且在所有的项目中都会存在
在进行类或方法进行的时候都可以使用Annotation进行声明,于是如果要想获取这些Annotation的信息,那么就可以直接通过反射来完成。在java.lang.reflect里面有一个AccessibleObject类在本类中提供有获取Annotation类的方法
‒ 获取全部Annotation:public Annotation[] getAnnotations()
‒ 获取指定Annotation:public T getAnnotation(Class annotationClass)
范例:定义一个接口,并且在接口上使用Annotation
import java.io.Serializable;
import java.lang.annotation.Annotation;
@FunctionalInterface
@Deprecated(since="1.0")
interface IMessage{
public void send(String msg);
}
@SuppressWarnings("serial") // 无法在程序执行的时候获取
class MessageImpl implements IMessage, Serializable {
@Override // 无法在程序执行的时候获取
public void send(String msg){
System.out.println("[消息发送]+msg");
}
}
public class JavaAPIDemo{
public static void main(String args[])throws Exception{
{ // 获取接口上的Annotation信息
Annotation annotations [] = IMessage.class.getAnnotations(); // 获取接口上的全部的Annotation
for(Annotation temp:annotations){
System.out.println(temp);
}
}
System.out.println("-----------------------------");
{ //获取MessageImpl子类上的Annotation
Annotation annotations [] = MessageImpl.class.getAnnotations(); //获取类上全部的Annotation
for(Annotation temp:annotations){
System.out.println(temp);
}
}
System.out.println("-----------------------------");
{ //获取MessageImpl.toString()方法上的Annotation
Method methods = MessageImpl.class.getDeclaredMethod("send",String.class);
Annotation annotations [] = methods.getAnnotations(); //获取类上全部的Annotation
for(Annotation temp:annotations){
System.out.println(temp);
}
}
}
}
不同的Annotation有它的存在范围,下面对比两个Annotation
@FunctionalInterface(运行时)
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface FunctionalInterface {}
@SuppressWarnings(“serial”) (源代码)
@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE, MODULE})
@Retention(RetentionPolicy.SOURCE)
public @interface SuppressWarnings {
String[] value();
}
现在发现"@FunctionalInterface"是在运行时生效的Annotation,所以当程序执行的时候可以获取此Annotation,而"@SuppressWarnings(“serial”)"是在源代码编写的时候有效(.java)。而在RetentionPolicy枚举类中还有一个class的定义,指的是在类定义的时候生效(.class)
不同的Annotation策略决定了能否被Annotation所读取
自定义Annotation
现在已经清楚了Annotation的获取,以及Anotation运行的策略,但是最为关键性的因素是如何可以实现自定义的Annotation呢?为此在Java里面提供了新的语法,使用"@interface"来定义Annotation
范例:自定义Annotation
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.reflect.Method;
@Retention(RetentionPolicy.RUNTIME) // 定义Annotation的运行策略
@interface DefaultAnnotation{
// 自定义的Annotation
public String title(); // 获取数据
public String url() default "www.baidu.com" ;// 获取数据,默认值
}
class Message06{
@DefaultAnnotation(title="BAIDU")
public void send(String msg){
System.out.println("消息发送"+msg);
}
}
public class JavaAPIDemo39 {
public static void main(String args[])throws Exception{
Method method =Message06.class.getMethod("send",String.class);//获取指定方法
DefaultAnnotation anno = method.getAnnotation(DefaultAnnotation.class);
System.out.println(anno.title()); // 直接调用Annotation中的方法
System.out.println(anno.url());
String msg = anno.title() + "("+anno.url()+")";//消息内容
method.invoke(Message06.class.getDeclaredConstructor().newInstance(),msg);
}
}
使用Annotation之后的最大特点是可以结合反射机制实现程序的处理
工厂设计模式与Annotation
现在已经清楚了Annotation的整体作用,但是Annotation到底在开发之中能做哪些事情呢?为了帮助大家进一步理解Annotation的处理目的下面将结合工厂设计模式来应用Annotation操作
范例:与Annotation结合
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 JavaAPIDemo40 {
public static void main(String args[]){
MessageService messageService = new MessageService();
messageService.send("www.mldn.cn");
}
}
@Retention(RetentionPolicy.RUNTIME)
@interface UseMessage {
public Class<?> clazz();
}
@UseMessage(clazz = NetMessageImpl.class) // 利用Annotation实现了类的使用
class MessageService{
// 对主方法调用进行包装,主方法不需要知道那么多,只需要知道对象产生
private IMessage07 message;
public MessageService(){
UseMessage use =MessageService.class.getAnnotation(UseMessage.class);
this.message = (IMessage07)Factory.getInstance(use.clazz()); // 直接通过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 MessageProxy().bind(clazz.getDeclaredConstructor().newInstance());
}catch(Exception e){
e.printStackTrace();
return null;
}
}
}
interface IMessage07{
public void send(String msg);
}
class MessageImpl implements IMessage07{
@Override
public void send(String msg){
System.out.println("[消息发送]"+msg);
}
}
class NetMessageImpl implements IMessage07{
public void send(String msg){
System.out.println("[网络消息发送]"+msg);
}
}
class MessageProxy implements InvocationHandler {
public Object target;
public Object bind(Object target){
this.target = target;
return Proxy.newProxyInstance(target.getClass().getClassLoader(),target.getClass().getInterfaces(),this);
}
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();
}
}
public boolean connect(){
System.out.println("[代理操作]进行消息发送通道的连接");
return true;
}
public void close(){
System.out.println("[代理操作]关闭连接通道");
}
}
由于Annotation的存在,所以对于面向接口的配置处理将可以直接利用Annotation的属性完成控制,从而使得整体代码变得简洁
学习资料
阿里云开发者社区