上一篇说到的静态代理,但是有新的接口,就需要新的代理,那么我们需要一个动态代理。java.lang.reflect包里,有个封装类Proxy,正好解决这个问题。
有很多很多的人都说过Proxy,无非就是这行代码的作用,Proxy.newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)根据参数(接口),以反射机制生成动态代理,执行相应接口方法。
1、参数(接口)
/** * 公共接口 * @author Biligle * */ public interface IPublicManager { /** * 排水 */ void out(); /** * 发电 */ void power(); /** * 净化 */ void clean(String params); }
/** * 生成动态代理,执行接口方法 * @author Biligle * */ public class ProxyUtil { public <T> Object create(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.common(method,args); return null; } }); } }
/** * 代理模式统一执行方法 * @author Biligle * */ public class BasicVoid { static void common(Method method, Object[] args){ System.out.println("接收到" + method.getName() + "接口" + "+parmas" + ":" + args[0]); System.out.println("给" + method.getName() + "接口方法返回相应数据"); } }测试
public class Test { public static void main(String[] args) { ProxyUtil p = new ProxyUtil(); IPublicManager iPublic = (IPublicManager) p.create(IPublicManager.class); iPublic.clean("纯净水"); } }
测试结果:
接收到clean接口+parmas:纯净水 给clean接口方法返回相应数据
大家应该发现了,我们没有去实现clean方法,而是用BasicVoid.common(method,args)做了统一处理,这样的好处是,我们又少写了一个实现类。
下面,我们写一下处理逻辑,这里需要一个接口,来给clean返回一些相应数据。
对BasicVoid修改如下:
/** * 代理模式统一执行方法 * @author Biligle * */ public class BasicVoid { 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(Method method, Object[] args){ data = visit(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(String method){ return method; } /** * 获取数据的监听 */ interface VisitListener { /** * 回调数据 * @param obj */ void callData(Object obj); } }对ProxyUtil修改如下:
/** * 生成动态代理,执行接口方法 * @author Biligle * */ public class ProxyUtil implements BasicVoid.VisitListener { public <T> Object create(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(method, args).call(ProxyUtil.this); return null; } }); } @Override public void callData(Object obj) { System.out.println("返给了" + obj); } }
测试结果
返给了clean
好了,最后在强调一下代理模式的核心概念
根据参数(接口IPublicManager.class),以反射机制生成动态代理,执行相应接口方法(clean)。