一、回顾
上篇文章,动态代理模式:代理访问接口对象,根据参数,反射出代理类,执行接口方法。
二、注解
通过反射,得到实例,执行注解方法。为什么使用注解呢?
1、一方面减少配置文件,如果自身做过java,肯定知道Spring框架中的@Service,只要在实现类加入@Service,在配置文件写入
<!-- 自动扫描注解的bean -->
<context:component-scan base-package="service" />
就会自动扫描了。
2、另一方面提高代码效率。比如我们需要创建一个实例,第一想到的是:new一个,这种需求很多的话,一个注解方式,获取实例,就可以大大节省代码量。
@Autowired //注入类,获取实例
private UserDao userDao;
三、代码演示
1、普通使用
/**
* 注解类
*/
@Target(ElementType.METHOD)//作用目标:对方法的注解
@Retention(RetentionPolicy.RUNTIME)//注解保留在运行时的环境中
@Documented//说明该注解将被包含在javadoc中
public @interface GET {
String value() default "";//默认返回""
}
/**
* 使用类
*/
public class GetUtil {
@GET("www.baidu.com")
void v(){}
}
/**
* 测试类
*/
public class Test {
public static void main(String[] args) {
System.out.println(getGet(GetUtil.class));
}
public static Object getGet(Class<?> clazz){
String result = "";
Method[] m = clazz.getDeclaredMethods();
for(Method ms : m){
if(ms.isAnnotationPresent(GET.class)){//true:包含GET注解
GET get = ms.getAnnotation(GET.class);//获取注解(反射),获取失败,返回null
if(get != null){
result= "正在访问后台接口" + get.value();//执行注解方法,假设访问了某个后台接口
}
}
}
return result;
}
}
2、结合动态代理模式使用(如果对动态代理有些模糊,建议先阅读上篇文章或者忽略下面代码)
/**
* 注解类
* @author Biligle
*
*/
@Target(ElementType.METHOD)//作用目标:对方法的注解
@Retention(RetentionPolicy.RUNTIME)//注解保留在运行时的环境中
@Documented//说明该注解将被包含在javadoc中
public @interface GET {
String value() default "";//默认返回""
}
/**
* 公共接口,注解使用类
* @author Biligle
*
*/
public interface IPublicManager {
/**
* 排水
*/
void out();
/**
* 发电
*/
void power();
/**
* 净化
*/
@GET("www.huanbao.com/jinghua.json")
void clean(String params);
}
/**
* 生成动态代理,执行接口方法
* @author Biligle
*
*/
public class ProxyUtil implements BasicVoid.VisitListener {
public <T> Object create(final Class<T> service){
if(!service.isInterface()){
new IllegalArgumentException("API声明必须是接口");
}else if(service.getInterfaces().length > 0){
new IllegalArgumentException("API接口不能扩展其他接口");
}
/**
* ClassLoader loader:类加载器
Class<?>[] interfaces:得到全部的接口
InvocationHandler h:
*/
return Proxy.newProxyInstance(service.getClassLoader(), new Class[]{service}, new InvocationHandler() {
/**
* proxy 代理对象
* method 接口方法
* args 接口方法的参数
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
//无论代理去执行哪个method,首先统一执行一个方法common,之后,在分别执行各自方法
//简言之,这里可以添加公共方法
BasicVoid.get().common(service,method, args).call(ProxyUtil.this);
return null;
}
});
}
@Override
public void callData(Object obj) {
System.out.println("-----------------------------------------------");
System.out.println(obj);
System.out.println("-----------------------------------------------");
}
}
/**
* 代理模式统一执行方法(都是环保公司的业务)
* @author Biligle
* @param <T>
*
*/
public class BasicVoid<T> {
private BasicVoid(){}
private static VisitListener listener;
private static Object data;
public static BasicVoid basicVoid = null;
public static BasicVoid get(){
if(basicVoid == null){
basicVoid = new BasicVoid();
}
return basicVoid;
}
public BasicVoid common(Class<T> service, Method method, Object[] args){
data = visit(service,method.getName());
return basicVoid;
}
/**
* 传入接口,用于监听返回数据
* @param l
* @return
*/
public BasicVoid call(VisitListener l){
listener = l;
listener.callData(data);
return basicVoid;
}
/**
* 统一标准访问,并返回相应数据
* @param method
* @return
*/
private Object visit(Class<T> service, String method){
String lastResult = "";
String base = "统一访问环保公司官网";
Method[] m = service.getDeclaredMethods();
for (Method ms : m) {
if(ms.isAnnotationPresent(GET.class)){//true:包含GET注解
GET get = ms.getAnnotation(GET.class);//获取注解(反射),获取失败,返回null
if(get != null){
String invokes = "正在访问后台接口" + get.value();//执行注解方法,假设访问了某个后台接口
String result = "这是" + method + "()的访问结果";
lastResult = "执行" + "'" + method + "()'" + "方法" + "\n" + base + "www.huanbao.com" + "\n" + invokes + "......" + "\n" + result;
}
}
}
return lastResult;
}
/**
* 获取数据的监听
*/
interface VisitListener {
/**
* 回调数据
* @param obj
*/
void callData(Object obj);
}
}
/**
* 测试类
* @author Biligle
*
*/
public class Test {
public static void main(String[] args) {
ProxyUtil p = new ProxyUtil();
IPublicManager iPublic = (IPublicManager) p.create(IPublicManager.class);
iPublic.clean("纯净水");
}
}