00 27Java高级之反射与Annotation

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的属性完成控制,从而使得整体代码变得简洁。

发布了122 篇原创文章 · 获赞 11 · 访问量 4222

猜你喜欢

转载自blog.csdn.net/weixin_43762330/article/details/104770858
00