0x01 前言

JDK动态代理与Cglib代理的区别
JDK 动态代理:
拦截器实现InvocationHandler接口,加上反射机制生成一个实现代理接口的匿名类
在调用具体方法前调用InvokeHandler来处理,自身额外操作
Cglib代理:
利用ASM框架,对代理对象类生成的class文件加载进来,通过修改其字节码生成子类来处理

JDK动态代理与Cglib字节码生成的区别?
JDK动态代理只能对实现了接口的类生成代理,而不能针对类
Cglib是针对类实现代理,主要是对指定的类生成一个子类,覆盖其中的方法,并覆盖其中方法的增强,但是因为采用的是继承,所以该类或方法最好不要生成final,对于final类或方法,是无法继承的

0x02 环境

  1. 编辑器为: IntelliJ IDEA
  2. java版本:
  3. java version "1.8.0_271"
  4. Java(TM) SE Runtime Environment (build 1.8.0_271-b09)
  5. Java HotSpot(TM) 64-Bit Server VM (build 25.271-b09, mixed mode)
  6. 使用的架包:
  7. cglib 3.3.0
  8. 代码仓库: https://github.com/pmiaowu/JavaProxyTest

0x03 语法介绍

0x03.1 MethodInterceptor接口

  1. package net.sf.cglib.proxy;
  2. import java.lang.reflect.Method;
  3. public interface MethodInterceptor extends Callback {
  4. /**
  5. * @param var1 被代理的对象
  6. * @param var2 被代理对象的方法
  7. * @param var3 参数集合
  8. * @param var4 生成的代理类
  9. * @return
  10. * @throws Throwable
  11. */
  12. Object intercept(Object var1, Method var2, Object[] var3, MethodProxy var4) throws Throwable;
  13. }

0x04 例子

例如现在有一个人,想去影院看电影,看完电影顺便去上个厕所
但是我们作为电影院的人,还想产生一些额外的收益
比如在影片开始与结束时播发一些广告
或是去洗手间的时候播发一些广告

先建立个人的行为类

  1. package 动态代理2;
  2. public class People {
  3. public void movie() {
  4. System.out.println("您正在观看电影《花园宝宝历险记》");
  5. }
  6. public void toilet() {
  7. System.out.println("您冲进了洗手间");
  8. }
  9. }

在建立个电影院提供用户最爱的广告

  1. package 动态代理2;
  2. import net.sf.cglib.proxy.Enhancer;
  3. import net.sf.cglib.proxy.MethodInterceptor;
  4. import net.sf.cglib.proxy.MethodProxy;
  5. import java.lang.reflect.Method;
  6. public class Cinema implements MethodInterceptor {
  7. private Object target;
  8. public Object bind(Object target) {
  9. this.target = target;
  10. // 工具类
  11. Enhancer en = new Enhancer();
  12. // 设置父类
  13. en.setSuperclass(target.getClass());
  14. // 设置回调函数
  15. en.setCallback(this);
  16. // 创建子类代理对象
  17. return en.create();
  18. }
  19. @Override
  20. public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
  21. System.out.println(" ");
  22. System.out.println("------------------");
  23. System.out.println("该影院叫: " + this.getClass().getSimpleName());
  24. this.advertising1();
  25. Object obj = method.invoke(this.target);
  26. this.advertising2();
  27. return obj;
  28. }
  29. public void advertising1() {
  30. System.out.println("开始广告: 电影准备开始了,肯德基十翅一桶,只需要39元,快来买啊!");
  31. }
  32. public void advertising2() {
  33. System.out.println("结束广告: 电影结束了,肯德基十翅一桶,只需要39元,快买回家吃吧!");
  34. }
  35. }

运行看看结果

  1. package 动态代理2;
  2. public class Test {
  3. public static void main(String[] args) {
  4. People people = new People();
  5. Cinema cinema = new Cinema();
  6. People peopleProxy = (People) cinema.bind(people);
  7. peopleProxy.movie();
  8. peopleProxy.toilet();
  9. }
  10. }
  11. // 执行结果
  12. ------------------
  13. 该影院叫: Cinema
  14. 开始广告: 电影准备开始了,肯德基十翅一桶,只需要39元,快来买啊!
  15. 您正在观看电影《花园宝宝历险记》
  16. 结束广告: 电影结束了,肯德基十翅一桶,只需要39元,快买回家吃吧!
  17. ------------------
  18. 该影院叫: Cinema
  19. 开始广告: 电影准备开始了,肯德基十翅一桶,只需要39元,快来买啊!
  20. 您冲进了洗手间
  21. 结束广告: 电影结束了,肯德基十翅一桶,只需要39元,快买回家吃吧!