Java代理
Java中代理有静态代理和动态代理。
静态代理的代理关系在编译时就确定了,而动态代理的代理关系是在编译期确定的。静态代理实现简单,适合于代理类较少且确定的情况,而动态代理则给我们提供了更大的灵活性。Java中动态代理有JDK原生动态代理和CGLIB动态代理两种。
SRE实战 互联网时代守护先锋,助力企业售后服务体系运筹帷幄!一键直达领取阿里云限量特价优惠。示例:

1 package com.marchon.proxytest; 2 3 public interface IUserService { 4 public String getUserName(); 5 public Integer getAge(String userName); 6 }IUserService

1 package com.marchon.proxytest; 2 3 /** 4 * 被代理对象 5 * 6 * @author zsm 7 * 8 */ 9 public class UserServiceImpl implements IUserService { 10 11 @Override 12 public String getUserName() { 13 String res = this.getClass() + ":hello"; 14 System.out.println(res); 15 return res; 16 } 17 18 @Override 19 public Integer getAge(String userName) { 20 Integer age = 20; 21 System.out.println(age); 22 return age; 23 } 24 25 }UserServiceImpl

1 package com.marchon.proxytest; 2 3 /** 4 * 代理对象(静态代理)<br> 5 * 缺点:<br> 6 * 1、代理类和被代理类实现相同的接口,代码重复、得为每个接口都实现相应的实现从而维护成本高 2、代理对象只服务于被代理对象,即每个被代理对象都得实现相应的代理对象 7 * 8 * @author zsm 9 * 10 */ 11 class UserServiceStaticProxy implements IUserService { 12 private IUserService proxiedObj; 13 14 public UserServiceStaticProxy(IUserService proxiedObj) { 15 if (proxiedObj instanceof UserServiceStaticProxy) { 16 throw new RuntimeException("illegal proxiedObj proxied object"); 17 } 18 19 this.proxiedObj = proxiedObj; 20 } 21 22 @Override 23 public String getUserName() { 24 System.out.println("before"); 25 String res = proxiedObj.getUserName(); 26 System.out.println("after"); 27 return res; 28 29 } 30 31 @Override 32 public Integer getAge(String userName) { 33 System.out.println("before"); 34 Integer age = proxiedObj.getAge(userName); 35 System.out.println("after"); 36 return age; 37 } 38 39 } 40 41 public class Main_StaticProxy { 42 public static void main(String[] args) { 43 IUserService proxiedObj = new UserServiceImpl(); 44 45 // UserServiceStaticProxy proxy = new UserServiceStaticProxy(proxiedObj); 46 IUserService proxyObject = new UserServiceStaticProxy(proxiedObj); 47 proxyObject.getUserName(); 48 proxyObject.getAge("zhangsan"); 49 } 50 }StaticProxy

1 package com.marchon.proxytest; 2 3 import java.io.FileOutputStream; 4 import java.io.IOException; 5 import java.lang.reflect.InvocationHandler; 6 import java.lang.reflect.Method; 7 import java.lang.reflect.Proxy; 8 9 import sun.misc.ProxyGenerator; 10 11 /** 12 * 代理对象(动态代理)<br> 13 * 动态代理:在程序运行期间根据需要动态创建代理类及其实例来完成具体的功能。动态代理主要分为JDK动态代理和cglib动态代理两大类 14 * 15 * @author zsm 16 * 17 */ 18 19 class JdkDynamicProxyTemplate implements InvocationHandler { 20 private Object proxiedObj; 21 22 public JdkDynamicProxyTemplate(Object proxiedObj) { 23 this.proxiedObj = proxiedObj; 24 } 25 26 @Override 27 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { 28 System.out.println("before"); 29 Object res = method.invoke(proxiedObj, args); 30 System.out.println("after"); 31 32 return res; 33 } 34 35 } 36 37 public class Main_DynamicProxy {// 参阅:https://www.jianshu.com/p/269afd0a52e6 38 public static void main(String[] args) { 39 IUserService proxiedObj = new UserServiceImpl(); 40 41 JdkDynamicProxyTemplate proxyTemplate = new JdkDynamicProxyTemplate(proxiedObj); 42 43 // 第一个参数是指定代理类的类加载器(我们传入当前测试类的类加载器) 44 // 第二个参数是代理类需要实现的接口(我们传入被代理类实现的接口,这样生成的代理类和被代理类就实现了相同的接口) 45 // 第三个参数是invocation handler,用来处理方法的调用。这里传入我们自己实现的handler 46 IUserService proxyObject = (IUserService) Proxy.newProxyInstance(proxiedObj.getClass().getClassLoader(), 47 proxiedObj.getClass().getInterfaces(), proxyTemplate);// 创建包含被代理对象各方法的代理对象,显然可以猜到:该代理对象包含所传接口中(这里为IUserService)定义的各方法、代理对象的各方法实现为直接调用proxyTemplate相应的各方法实现。可以使用sum.misc下的ProxyGenerator生成动态代理类的字节码文件,再反编译出动态代理类源码 48 49 proxyObject.getUserName(); 50 proxyObject.getAge("zhangsan"); 51 52 // 获取代理类字节码文件 53 String path = "$Proxy0.class"; 54 byte[] classFile = ProxyGenerator.generateProxyClass("$Proxy0", proxiedObj.getClass().getInterfaces()); 55 FileOutputStream out = null; 56 57 try { 58 out = new FileOutputStream(path); 59 out.write(classFile); 60 out.flush(); 61 } catch (Exception e) { 62 e.printStackTrace(); 63 } finally { 64 try { 65 out.close(); 66 } catch (IOException e) { 67 e.printStackTrace(); 68 } 69 } 70 71 // 72 new TmpStaticProxy(proxyTemplate).getUserName(); 73 74 } 75 } 76 77 /** 78 * 79 * 上述生成的动态代理生成的代理类实际是类似于本类 80 * 81 * @author zsm 82 * 83 */ 84 class TmpStaticProxy implements IUserService {//真正由动态代理生成的代理类还extends Proxy 85 private JdkDynamicProxyTemplate invokeHandler; 86 87 public TmpStaticProxy(JdkDynamicProxyTemplate invokeHandler) { 88 this.invokeHandler = invokeHandler; 89 } 90 91 @Override 92 public String getUserName() { 93 Object[] args = null; 94 Method getUserNameMethod = IUserService.class.getMethods()[0];// public abstract java.lang.String 95 // com.marchon.proxytest.IUserService.getUserName() 96 try { 97 return (String) invokeHandler.invoke(this, getUserNameMethod, args); 98 } catch (Throwable e) { 99 e.printStackTrace(); 100 return null; 101 } 102 103 } 104 105 @Override 106 public Integer getAge(String userName) { 107 Object[] args = new Object[] { userName }; 108 try { 109 Method getAgeMethod = IUserService.class.getMethods()[1];// public abstract java.lang.Integer 110 // com.marchon.proxytest.IUserService.getAge(java.lang.String) 111 return (Integer) invokeHandler.invoke(this, getAgeMethod, args); 112 } catch (Throwable e) { 113 e.printStackTrace(); 114 return null; 115 } 116 117 } 118 119 }DynamicProxy
由上可见,JDK动态代理实际上是自动生成一个静态代理类并创建相应实例。代理类默认继承Porxy类,因为Java中只支持单继承,所以JDK动态代理只能去实现接口;代理类的方法都会去调用InvocationHandler的invoke()方法,故此需重写InvocationHandler的invoke()方法。
参考资料:
https://www.jianshu.com/p/269afd0a52e6
https://www.cnblogs.com/liuyun1995/p/8144628.html

更多精彩