动态代理是相对静态代理而说的,比较废话一句。其核心就是Proxy.newProxyInstance生产代理类,同时指定这个代理实例的回调接口java.lang.reflect.InvocationHandler。先上代码,再做分析:
1 /** 2 * User服务接口类 3 */ 4 interface UserService{ 5 /** 6 * 添加一个用户 7 * @return 8 */ 9 public boolean add(String name); 10 }
1 /** 2 * User服务接口实现类 3 */ 4 class UserServiceImpl implements UserService{ 5 6 @Override 7 public boolean add(String name) { 8 System.out.println(String.format("添加一个名为:%s的用户", name)); 9 return true; 10 } 11 }
1 /** 2 * 代理工具类,用其他类提供代理 3 */ 4 class DynamicProxyUtil implements InvocationHandler{ 5 /** 6 * 被代理的对象 7 */ 8 private Object proxyObject; 9 /** 10 * 将被代理对象传入,以便生产代理类 11 * @param proxyObject 12 * @return 13 */ 14 public Object generateProxyClass(Object proxyObject){ 15 this.proxyObject=proxyObject;//将被代理对象引入该类 16 //根据被代理对象的类信息生产代理类 17 Class<?> clazz = proxyObject.getClass(); 18 /*Proxy.newProxyInstanc方法实现原理:jvm会根据传入的接口及其实现类动态生成如:$Proxy.class字节码类,默认只在内存中,可使用 19 System.getProperties().setProperty("sun.misc.ProxyGenerator.saveGeneratedFiles", "true")将类文件保存在本地磁盘 20 $Proxy0 实现要代理的对象接口及其托管对被代理对象所有方法调用 21 public final class $Proxy0 extends java.lang.reflect.Proxy implements UserService 22 */ 23 return Proxy.newProxyInstance(clazz.getClassLoader(), clazz.getInterfaces(), this); 24 } 25 @Override 26 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { 27 System.out.println(String.format("方法%s调用前,传入参数%s", method.getName(),Arrays.toString(args))); 28 Object result = method.invoke(this.proxyObject, args); 29 System.out.println(String.format("方法%s调用前,返回值%s", method.getName(),result)); 30 return result; 31 } 32 33 }
1 /** 2 * 测试类 3 */ 4 public class ClientTest { 5 public static void main(String[] args) { 6 7 UserService userService = new UserServiceImpl(); 8 //用代理工具类生成一个UserService服务代理 9 System.getProperties().setProperty("sun.misc.ProxyGenerator.saveGeneratedFiles", "true"); 10 DynamicProxyUtil dynamicProxy = new DynamicProxyUtil(); 11 UserService userServiceProxy = (UserService)dynamicProxy.generateProxyClass(userService); 12 //通过生成的代理类来调用方法,而不是直接调用userService.add。这样我们就可以动态调用服务方法,以便在代理工具类中动态加入其他业务逻辑代码,如系统日志记录等等 13 //spring aop默认就是使用JdkDynamic实现代理bean的,spring aop还有一种就是cglib动态字节码生成类工具包 14 boolean result = userServiceProxy.add("muzi"); 15 System.out.println(result?"添加成功":"添加失败"); 16 } 17 }
再复习代理模式定义:为其他对象提供一种代理以控制对这个对象的访问。在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。
其实jdk动态代理实现也能简单,就是动态生成一个代理类如:$Proxy0(可通过反编译软件查看保存在本地磁盘上的.class),如下所示:
1 import java.lang.reflect.InvocationHandler; 2 import java.lang.reflect.Method; 3 import java.lang.reflect.Proxy; 4 import java.lang.reflect.UndeclaredThrowableException; 5 /** 6 *该类就是动态生成的类,省略掉无用代码 ,此类自动实现UserService接口,就是 7 *Proxy.newProxyInstance(clazz.getClassLoader(), clazz.getInterfaces(), this); 8 *方法的第二个参数,所以我们可以将生成的代理强制类型转换为UserService接口类型对象,注意而不能转换为UserServiceImpl实现类对象 9 */ 10 public final class $Proxy0 extends Proxy implements UserService { 11 12 public $Proxy0(InvocationHandler invocationhandler) { 13 super(invocationhandler); 14 } 15 16 public final boolean add(String s) { 17 try { 18 //调用InvocationHandler回调接口中的回调方法,此为关键代码,就是DynamicProxyUtil.invoke方法 19 return ((Boolean) super.h.invoke(this, m3, new Object[] { s })).booleanValue(); 20 } catch (Error _ex) { 21 } catch (Throwable throwable) { 22 throw new UndeclaredThrowableException(throwable); 23 } 24 return false; 25 } 26 27 private static Method m3; 28 29 static { 30 try { 31 //根据java反射机制构造UserService中add方法Method类型实例 32 m3 = Class.forName("UserService").getMethod("add", new Class[] { Class.forName("java.lang.String") }); 33 } catch (NoSuchMethodException nosuchmethodexception) { 34 throw new NoSuchMethodError(nosuchmethodexception.getMessage()); 35 } catch (ClassNotFoundException classnotfoundexception) { 36 throw new NoClassDefFoundError(classnotfoundexception.getMessage()); 37 } 38 } 39 }
ps:描述不是很具有条理性,对付着看吧,多跟两趟代码就清楚了
所用到工具下载链接:
jd-gui:http://pan.baidu.com/share/link?shareid=378349&uk=973960637
用技术诱引妹子