Java中代理有静态代理动态代理

静态代理的代理关系在编译时就确定了,而动态代理的代理关系是在编译期确定的。静态代理实现简单,适合于代理类较少且确定的情况,而动态代理则给我们提供了更大的灵活性。Java中动态代理有JDK原生动态代理CGLIB动态代理两种。

SRE实战 互联网时代守护先锋,助力企业售后服务体系运筹帷幄!一键直达领取阿里云限量特价优惠。

示例:

Java代理 随笔 第1张
1 package com.marchon.proxytest;
2 
3 public interface IUserService {
4     public String getUserName();
5     public Integer getAge(String userName);
6 }
IUserService Java代理 随笔 第3张
 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 Java代理 随笔 第5张
 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 Java代理 随笔 第7张
  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

扫码关注我们
微信号:SRE实战
拒绝背锅 运筹帷幄