[Js-设计模式]代理模式,JDK动态代理,CGLIB动态代理,静态代理

代理模式分为静态代理和动态代理

静态代理:在程序运行之前,代理类和 目标类之间的关系就已经确立了

动态代理:在程序运行时才确立代理关系

从编写代码上来讲,一般有代理类的是静态代理,没有代理类只有代理对象(通过代理工具或者工厂生成)的成为动态代理

可以理解静态代理类为公司中的法律顾问,在日常没有官司的时候(即以·程序运行之前)就是存在的,而动态代理对象可以理解为在律师事务所(代理工具或者代理类)工作(创建)的律师(即动态代理对象)

以下用代码来演示动态代理与静态代理,

静态代理:

 1 package com.neu.service;
 2 
 3 // 主业务接口:本接口中的方法将要被代理类增强
 4 public interface ISomeService {
 5     public String doFirst();
 6 
 7     public void doSecond();
 8 }
 9 
10 package com.neu.service;
11 
12 // 目标类:代理类要增强的类
13 public class SomeServiceImpl implements ISomeService {
14 
15     @Override
16     public String doFirst() {
17         System.out.println("执行doFirst()方法");
18         return "abcde";
19     }
20 
21     @Override
22     public void doSecond() {
23         System.out.println("执行doFirst()方法");
24     }
25 
26 }
27 
28 package com.neu.proxy;
29 
30 import com.neu.service.ISomeService;
31 
32 // 静态代理,仅继承要增强的接口方法即可
33 public class ServiceProxy implements ISomeService {
34     private ISomeService target;
35 
36     public ServiceProxy() {
37     }
38 
39     public ServiceProxy(ISomeService target) {
40         super();
41         this.target = target;
42     }
43 
44     @Override
45     public String doFirst() {
46         // 调用目标类的方法,该方法返回小写字母
47         String result = target.doFirst();
48         // 增强:将目标方法返回的小写字母变成大写
49         result = result.toUpperCase();
50         return result;
51     }
52 
53     @Override
54     public void doSecond() {
55         target.doSecond();
56     }
57 
58 }
59 
60 package com.neu.test;
61 
62 import org.junit.Test;
63 
64 import com.neu.proxy.ServiceProxy;
65 import com.neu.service.ISomeService;
66 import com.neu.service.SomeServiceImpl;
67 
68 // 测试类
69 public class MyTest {
70 
71     @Test
72     public void test01() {
73         // ISomeService service = new SomeServiceImpl();
74         ISomeService service = new ServiceProxy(new SomeServiceImpl());
75         String result = service.doFirst();
76         System.out.println(result);
77         service.doSecond();
78     }
79 
80 }
81 /*
82 输出结果:
83 执行doFirst()方法
84 ABCDE
85 执行doFirst()方法
86 */

动态代理代理的方法有很多,下面讲述两种:

JDK动态代理:

 1 package com.neu.test;
 2 
 3 import java.lang.reflect.InvocationHandler;
 4 import java.lang.reflect.Method;
 5 import java.lang.reflect.Proxy;
 6 
 7 import org.junit.Test;
 8 
 9 import com.neu.service.ISomeService;
10 import com.neu.service.SomeServiceImpl;
11 
12 // 测试类
13 public class MyTest {
14 
15     @Test
16     public void test01() {
17         ISomeService target = new SomeServiceImpl();
18         // 由Proxy类的newProxyInstance()方法生成一个动态代理对象
19         ISomeService service = (ISomeService) Proxy.newProxyInstance(target.getClass().getClassLoader(), // 目标类的类加载器
20                 target.getClass().getInterfaces(), // 目标类所实现的所有接口
21                 new InvocationHandler() { // 内部匿名类
22 
23                     // proxy:代理对象
24                     // method:目标方法
25                     // args:目标方法的参数列表
26                     @Override
27                     public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
28                         Object result = method.invoke(target, args);
29                         if (result != null) {
30                             result = ((String) result).toUpperCase();
31                         }
32                         return result;
33                     }
34                 });
35         String result = service.doFirst();
36         System.out.println(result);
37         service.doSecond();
38     }
39 
40 }

Cglib动态代理:(目标类没有实现接口)

 1 package com.neu.service;
 2 
 3 // 目标类:代理类要增强的类,没有实现任何的接口
 4 public class SomeService{
 5 
 6     public String doFirst() {
 7         System.out.println("执行doFirst()方法");
 8         return "abcde";
 9     }
10 
11     public void doSecond() {
12         System.out.println("执行doFirst()方法");
13     }
14 
15 }
16 
17 package com.neu.factory;
18 
19 import java.lang.reflect.Method;
20 
21 import com.neu.service.SomeService;
22 
23 import net.sf.cglib.proxy.Enhancer;
24 import net.sf.cglib.proxy.MethodInterceptor;
25 import net.sf.cglib.proxy.MethodProxy;
26 
27 public class CglibFactory implements MethodInterceptor {
28     private SomeService target;
29 
30     public CglibFactory() {
31     }
32 
33     public CglibFactory(SomeService target) {
34         this.target = target;
35     }
36 
37     public SomeService myCglibCreator() {
38         Enhancer enhancer = new Enhancer();
39         // 因为目标类没有实现接口,所以Cglib采用指定父类,即目标类,来增强父类
40         // Cglib动态代理增强的原理是:子类增强父类,所以也要求目标类不能是final的,因为final类不能被继承
41         enhancer.setSuperclass(SomeService.class);
42         // 设置回调接口对象
43         enhancer.setCallback(this);
44         // create()方法用于创建Cglib动态代理对象,即目标类的子类对象
45         return (SomeService) enhancer.create();
46     }
47 
48     // 回调接口的方法
49     // 执行的条件是:代理对象执行目标方法时会触发该方法执行
50     @Override
51     public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
52         Object invoke = method.invoke(target, args);
53         if (invoke != null) {
54             invoke = ((String) invoke).toUpperCase();
55         }
56         return invoke;
57     }
58 
59 }
60 
61 package com.neu.test;
62 
63 import org.junit.Test;
64 
65 import com.neu.factory.CglibFactory;
66 import com.neu.service.SomeService;
67 
68 // 测试类
69 public class MyTest {
70 
71     @Test
72     public void test01() {
73         SomeService target = new SomeService();
74         SomeService service = new CglibFactory(target).myCglibCreator();
75         String result = service.doFirst();
76         System.out.println(result);
77         service.doSecond();
78     }
79 
80 }

 Cglib动态代理:(目标类已经实现接口,接口和实现类用上面的即可)

 1 package com.neu.factory;
 2 
 3 import java.lang.reflect.Method;
 4 
 5 import com.neu.service.ISomeService;
 6 
 7 import net.sf.cglib.proxy.Enhancer;
 8 import net.sf.cglib.proxy.MethodInterceptor;
 9 import net.sf.cglib.proxy.MethodProxy;
10 
11 public class CglibFactory implements MethodInterceptor {
12     private ISomeService target;
13 
14     public CglibFactory() {
15     }
16 
17     public CglibFactory(ISomeService target) {
18         this.target = target;
19     }
20 
21     public ISomeService myCglibCreator() {
22         Enhancer enhancer = new Enhancer();
23         // 因为目标类没有实现接口,所以Cglib采用指定父类,即目标类,来增强父类
24         // Cglib动态代理增强的原理是:子类增强父类,所以也要求目标类不能是final的,因为final类不能被继承
25         enhancer.setSuperclass(ISomeService.class);
26         // 设置回调接口对象
27         enhancer.setCallback(this);
28         // create()方法用于创建Cglib动态代理对象,即目标类的子类对象
29         return (ISomeService) enhancer.create();
30     }
31 
32     // 回调接口的方法
33     // 执行的条件是:代理对象执行目标方法时会触发该方法执行
34     @Override
35     public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
36         Object invoke = method.invoke(target, args);
37         if (invoke != null) {
38             invoke = ((String) invoke).toUpperCase();
39         }
40         return invoke;
41     }
42 
43 }
44 
45 package com.neu.test;
46 
47 import org.junit.Test;
48 
49 import com.neu.factory.CglibFactory;
50 import com.neu.service.ISomeService;
51 import com.neu.service.SomeServiceImpl;
52 
53 // 测试类
54 public class MyTest {
55 
56     @Test
57     public void test01() {
58         ISomeService target = new SomeServiceImpl();
59         ISomeService service = new CglibFactory(target).myCglibCreator();
60         String result = service.doFirst();
61         System.out.println(result);
62         service.doSecond();
63     }
64 
65 }

 总结:

静态代理只能解决有接口的情况,而且必须有代理类方法是创建一个实现同一个(或者几个接口)的类,实现要增强的方法,在方法中调用目标类的方法(此时,我们可以将目标类作为代理类的属性,从而得以调用目标类的方法),并加以处理

动态代理是不需要有代理类的,只需要代理工具或者代理工厂

JDK动态代理只能处理带有接口的目标类,由 Java 提供的 Proxy 类的 newProxyInstance() 方法生成一个代理对象即可,需要传入的参数是目标类的类加载器,目标类所实现的所有接口,和一个实现了 InvocationHandler 接口的类对象,在该对象的 invoke 方法中对要增强的方法进行处理

Cglib动态代理可以处理带接口和不带接口的目标类,而且实现方式相同(除了代入的类名要换成接口名字hhh),原理是没有接口,就把目标类当成父类,具体实现是写一个 Factory 实现 MethodInterceptor 接口,实现 intercept 方法,一般写法是将目标类作为 Factory 的一个属性,编写 Factory 的一个方法,首先设置父类,然后设置回调接口对象,最后返回 Enhancer 代理对象,这样在程序中我们使用返回的这个代理对象调用目标类要增强的方法时,会触发代理对象的 intercept 对方法结果进行处理

相关依赖的 junit 和 cglib 包的链接 https://pan.baidu.com/s/1EgVFhSmzanfA6sITg3i2fg ,密码是7dxz

原文地址:https://www.cnblogs.com/jiasq/p/8560775.html