java代理模式学习,静态代理,JDK动态代理,CGLIB动态代理

一时失言乱红尘 2022-05-14 07:12 460阅读 0赞

java代理模式学习,静态代理,JDK动态代理,CGLIB动态代理

#

一、理解代理

1、代理,Proxy 。意思是:本来该你做的事儿,别人代替你去做。 比如说:即将十一到来,你要抢回家/旅游的车票,可是你不能时时刻刻在电脑前一遍又一遍的刷着12306。 这时交给了 飞猪 等(此处省去若干个抢票软件!)软件帮助你抢。 飞猪就是你 抢票 这项工作的代理 。

2、代理作用: 日志记录,性能分析,解耦合。。。 自己百度去。

二、静态代理 —- 代码来抢票

1、 定义一个抢票接口 Tickets

  1. /**
  2. * description: 抢票接口 --- 需要抢票需实现该接口
  3. * @version v1.0
  4. * @author w
  5. * @date 2018年9月3日下午9:54:28
  6. */
  7. public interface Tickets {
  8. void buyTickets();
  9. }

2、定义一个User类 实现抢票接口,执行抢票操作

  1. /**
  2. * description: 定义一个User类 实现抢票接口,执行抢票操作
  3. * @version v1.0
  4. * @author w
  5. * @date 2018年9月3日下午9:52:38
  6. */
  7. public class User implements Tickets{
  8. private String name;
  9. public User(String name) {
  10. this.name = name;
  11. }
  12. @Override
  13. public void buyTickets() {
  14. System.out.println(name + " 开始抢票啦~ ");
  15. }
  16. }

3、定义一个FliggyProxy类,实现抢票接口 —- 飞猪来帮你抢票啦

  1. /**
  2. * description: 飞猪 实现抢票接口 --- 飞猪来帮你抢票啦
  3. * @version v1.0
  4. * @author w
  5. * @date 2018年9月3日下午9:58:44
  6. */
  7. public class FliggyProxy implements Tickets {
  8. private User user ;
  9. public FliggyProxy(User user) {
  10. this.user = user;
  11. }
  12. @Override
  13. public void buyTickets() {
  14. System.out.println("充钱,享受1000M专线抢票 ");
  15. user.buyTickets();
  16. System.out.println("抢票成功. 广告:没有什么是充钱解决不的问题.");
  17. }
  18. }

4、定义一个 StaticProxyTest类,执行相关的测试操作

  1. /**
  2. * description: 静态代理 test
  3. * @version v1.0
  4. * @author w
  5. * @date 2018年9月3日下午10:01:26
  6. */
  7. public class StaticProxyTest {
  8. @Test
  9. public void testOne(){
  10. // 创建一个用户,小明 --- 一遍又一遍的刷着12306
  11. User user = new User("小明");
  12. user.buyTickets();
  13. }
  14. @Test
  15. public void testTwo(){
  16. // 创建一个需要抢票的用户 --- 万能小明
  17. User user = new User("万能小明");
  18. // 小明开启飞猪
  19. FliggyProxy fliggy = new FliggyProxy(user);
  20. // fliggy 开始抢票啦
  21. fliggy.buyTickets();
  22. }
  23. }

5、运行结果:

  1. testOne:小明 开始抢票啦~
  2. testTwo
  3. 充钱,享受1000M专线抢票
  4. 万能小明 开始抢票啦~
  5. 抢票成功. 广告:没有什么是充钱解决不的问题.

6、根据代码运行结果可以小明抢票的操作,交给飞猪后,很快就抢到了。 但是 飞猪的功能太单一,只能帮忙抢票。比如下次要抢月饼呢,再下次要抢手机呢? 要实现这些功能,我们就要写n多个的 xxProxy。 作为程序员,总想着一劳永逸,能否只写一个呢? 答案是有的,继续往下。

三、JDK动态代理

1、定义一个 FliggyDynamic 类,实现 java.lang.reflect.InvocationHandler 接口

  1. import java.lang.reflect.InvocationHandler;
  2. import java.lang.reflect.Method;
  3. /**
  4. * description: JDK动态代理。 飞猪动态帮助无数人开启抢票模式
  5. * @version v1.0
  6. * @author w
  7. * @date 2018年9月3日下午10:06:21
  8. */
  9. public class FliggyDynamic implements InvocationHandler {
  10. /**
  11. * 需要抢票的用户 --- 目标代理对象
  12. */
  13. private Object target ;
  14. /**
  15. * 构造方法,初始化目标代理对象
  16. */
  17. public FliggyDynamic(Object target) {
  18. this.target = target;
  19. }
  20. @Override
  21. public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
  22. System.out.println("充钱,享受1000M专线抢票 ");
  23. Object result = method.invoke(target, args);
  24. System.out.println("抢票成功. 广告:没有什么是充钱解决不的问题.");
  25. return result;
  26. }
  27. }

2、定义一个 DynamicTest类,执行相关的测试操作

  1. /**
  2. * description: JDK 动态代理Test
  3. * @version v1.0
  4. * @author w
  5. * @date 2018年9月3日下午10:09:02
  6. */
  7. public class DynamicTest {
  8. @Test
  9. public void test(){
  10. User user = new User("万年小明");
  11. FliggyDynamic dynamic = new FliggyDynamic(user);
  12. Tickets proxy = (Tickets)Proxy.newProxyInstance(user.getClass().getClassLoader(),
  13. user.getClass().getInterfaces(), dynamic);
  14. proxy.buyTickets();
  15. }
  16. }

3、运行结果:

  1. 充钱,享受1000M专线抢票
  2. 万年小明 开始抢票啦~
  3. 抢票成功. 广告:没有什么是充钱解决不的问题.

4、定义 FliggyDynamicRefactor类,实现 InvocationHandler 接口,增加泛型。 (可选)

  1. 重构获取代理对象方法: Proxy.newProxyInstance .... 避免每次都进行强制类型转换。
  2. /**
  3. * description: JDK动态代理 。 重构 Proxy.newProxyInstance , 避免每次都进行强制类型转换。
  4. * @version v1.0
  5. * @author w
  6. * @date 2018年9月3日下午10:52:07
  7. */
  8. public class FliggyDynamicRefactor<T> implements InvocationHandler{
  9. /**
  10. * 目标代理对象 target
  11. */
  12. private T target ;
  13. public FliggyDynamicRefactor(T target) {
  14. this.target = target;
  15. }
  16. /**
  17. * description: 获取代理对象
  18. * @return
  19. * T
  20. * @version v1.0
  21. * @author w
  22. * @date 2018年9月3日 下午10:55:59
  23. */
  24. @SuppressWarnings("unchecked")
  25. public T getProxy(){
  26. return (T) Proxy.newProxyInstance(target.getClass().getClassLoader(),
  27. target.getClass().getInterfaces(), this);
  28. }
  29. @Override
  30. public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
  31. System.out.println("充钱,享受1000M专线抢票 ");
  32. Object result = method.invoke(target, args);
  33. System.out.println("抢票成功. 广告:没有什么是充钱解决不的问题.");
  34. return result;
  35. }
  36. }

5、定义 DynamicRefactorTest 类,对重构后的代码进行测试 (可选)

  1. /**
  2. * description: JDK 动态代理 重构后的 FliggyDynamicRefactor Test
  3. * @version v1.0
  4. * @author w
  5. * @date 2018年9月3日下午10:09:02
  6. */
  7. public class DynamicRefactorTest {
  8. @Test
  9. public void test(){
  10. FliggyDynamicRefactor<Tickets> refactor = new FliggyDynamicRefactor<Tickets>(new User("李雷"));
  11. refactor.getProxy().buyTickets();
  12. }
  13. }

6、运行结果:

  1. 充钱,享受1000M专线抢票
  2. 李雷 开始抢票啦~
  3. 抢票成功. 广告:没有什么是充钱解决不的问题.

7、使用JDK提供的动态代理,可以解决静态代理中要写 n多个 xxProxy类的问题。但是可以发现,JDK动态代理只能针对接口的代理。 若一个类,没有实现任何接口,那么JDK的动态代理也就无用武之地了。 有解决办法吗?有,继续看 CGLIB的动态代理 —— 针对类的代理。

四、CGLIB动态代理

1、 依赖jar包: cglib-3.2.6.jar

2、定义一个 Car 类,不实现任何 接口的普普通通类

  1. /**
  2. * description: 定义一个普通的 Car类
  3. * @version v1.0
  4. * @author w
  5. * @date 2018年9月3日下午11:27:09
  6. */
  7. public class Car {
  8. public void runing(){
  9. System.out.println("老司机开车啦~ ");
  10. }
  11. }

3、定义一个 CglibProxy类,实现 net.sf.cglib.proxy.MethodInterceptor 接口

  1. import net.sf.cglib.proxy.Enhancer;
  2. import net.sf.cglib.proxy.MethodInterceptor;
  3. import net.sf.cglib.proxy.MethodProxy;
  4. /**
  5. * description: 使用 CGLIB 实现动态代理
  6. * @version v1.0
  7. * @author w
  8. * @date 2018年9月3日下午11:12:55
  9. */
  10. public class CglibProxy implements MethodInterceptor{
  11. @SuppressWarnings("unchecked")
  12. public <T> T getProxy(Class<T> clzz){
  13. return (T) Enhancer.create(clzz, this);
  14. }
  15. @Override
  16. public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
  17. System.out.println("前方注意~老司机来了,请速让道。。 ");
  18. Object result = proxy.invokeSuper(obj, args);
  19. System.out.println("老司机已通过前方 over ..");
  20. return result;
  21. }
  22. }

4、定义 CglibProxyTest类,针对CglibProxy的测试

  1. /**
  2. * description: 针对 CglibProxy 的测试
  3. * @version v1.0
  4. * @author w
  5. * @date 2018年9月3日下午11:46:34
  6. */
  7. public class CglibProxyTest {
  8. @Test
  9. public void test(){
  10. CglibProxy proxy = new CglibProxy();
  11. Car car = proxy.getProxy(Car.class);
  12. car.runing();
  13. }
  14. }

5、运行结果:

  1. 前方注意~老司机来了,请速让道。。
  2. 老司机开车啦~
  3. 老司机已通过前方 over ..

6、可以看到,使用 CGLIB解决了JDK的动态代理只能针对接口代理的问题。 普通的java类都可以进行代理。

五、总结

1、代理模式,实现代码功能增强,且不影响原代码,解耦合。

2、静态代理,针对每一个代理对象都需要都需要一个代理类。

3、JDK动态代理,只能针对接口代理,若目标代理类未实现接口,则无法代理。

4、CGLIB动态代理,可以对普通类进行代理,但目标代理类需提供无参构造方法。

参考资料: http://www.importnew.com/26116.html

  1. [深入理解CGLIB动态代理机制][CGLIB]

发表评论

表情:
评论列表 (有 0 条评论,460人围观)

还没有评论,来说两句吧...

相关阅读