一、代理介绍

1.1、代理的种类

  • 静态代理
  • 动态代理

二、JDK 代理

2.1、jdk 代理相关类

  • InvocationHandler 代理执行接口 ```java //代理执行接口 public interface InvocationHandler { public Object invoke(Object proxy, Method method, Object[] args)
    1. throws Throwable;
    }
  1. - Proxy 用于提供静态方法创建动态代理类和实例
  2. <a name="etUmc"></a>
  3. ### 2.2、jdk 代理使用
  4. <a name="B5lcR"></a>
  5. #### 2.2.1、创建接口
  6. ```java
  7. public interface Car {
  8. void running();
  9. }

2.2.2、创建实现类

  1. public class Taxi implements Car{
  2. @Override
  3. public void running() {
  4. System.out.println("The taxi is running.");
  5. }
  6. }

2.2.3、创建代理执行类

  1. /**
  2. * 代理工厂
  3. */
  4. public class JDKProxyFactory implements InvocationHandler {
  5. private Object target;
  6. public JDKProxyFactory(Object target) {
  7. super();
  8. this.target = target;
  9. }
  10. // 创建代理对象
  11. public Object createProxy() {
  12. // 1.得到目标对象的类加载器
  13. ClassLoader classLoader = target.getClass().getClassLoader();
  14. // 2.得到目标对象的实现接口
  15. Class<?>[] interfaces = target.getClass().getInterfaces();
  16. // 3.第三个参数需要一个实现invocationHandler接口的对象
  17. Object newProxyInstance = Proxy.newProxyInstance(classLoader, interfaces, this);
  18. return newProxyInstance;
  19. }
  20. // 第一个参数:代理对象.一般不使用;第二个参数:需要增强的方法;第三个参数:方法中的参数
  21. @Override
  22. public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
  23. System.out.println("这是增强方法前......");
  24. Object invoke = method.invoke(target, args);
  25. System.out.println("这是增强方法后......");
  26. return invoke;
  27. }
  28. }

2.2.4、运行

  1. Car car=new Taxi();
  2. JDKProxyFactory jdkProxyFactory=new JDKProxyFactory(car);
  3. Car proxy = (Car) jdkProxyFactory.createProxy();
  4. proxy.running();

2.3、查看jdk 生成的代理类

  • 生成的代理类名称

    1. //全限定类名.$Proxy序号
    2. com.sun.proxy.$Proxy0
  • 添加 vm 参数,输出代理类 ```shell -Dsun.misc.ProxyGenerator.saveGeneratedFiles=true

会在项目中的【com.sun.proxy】目录中找到这个.class文件

  1. - 代理类源码
  2. ```java
  3. package com.sun.proxy;
  4. import cn.hdj.springbootaopdemo.proxy.jdk.Car;
  5. import java.lang.reflect.InvocationHandler;
  6. import java.lang.reflect.Method;
  7. import java.lang.reflect.Proxy;
  8. import java.lang.reflect.UndeclaredThrowableException;
  9. public final class $Proxy4 extends Proxy implements Car {
  10. private static Method m1;
  11. private static Method m3;
  12. private static Method m2;
  13. private static Method m0;
  14. public $Proxy4(InvocationHandler var1) throws {
  15. super(var1);
  16. }
  17. public final boolean equals(Object var1) throws {
  18. try {
  19. return (Boolean)super.h.invoke(this, m1, new Object[]{var1});
  20. } catch (RuntimeException | Error var3) {
  21. throw var3;
  22. } catch (Throwable var4) {
  23. throw new UndeclaredThrowableException(var4);
  24. }
  25. }
  26. public final void running() throws {
  27. try {
  28. super.h.invoke(this, m3, (Object[])null);
  29. } catch (RuntimeException | Error var2) {
  30. throw var2;
  31. } catch (Throwable var3) {
  32. throw new UndeclaredThrowableException(var3);
  33. }
  34. }
  35. public final String toString() throws {
  36. try {
  37. return (String)super.h.invoke(this, m2, (Object[])null);
  38. } catch (RuntimeException | Error var2) {
  39. throw var2;
  40. } catch (Throwable var3) {
  41. throw new UndeclaredThrowableException(var3);
  42. }
  43. }
  44. public final int hashCode() throws {
  45. try {
  46. return (Integer)super.h.invoke(this, m0, (Object[])null);
  47. } catch (RuntimeException | Error var2) {
  48. throw var2;
  49. } catch (Throwable var3) {
  50. throw new UndeclaredThrowableException(var3);
  51. }
  52. }
  53. static {
  54. try {
  55. m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
  56. m3 = Class.forName("cn.hdj.springbootaopdemo.proxy.jdk.Car").getMethod("running");
  57. m2 = Class.forName("java.lang.Object").getMethod("toString");
  58. m0 = Class.forName("java.lang.Object").getMethod("hashCode");
  59. } catch (NoSuchMethodException var2) {
  60. throw new NoSuchMethodError(var2.getMessage());
  61. } catch (ClassNotFoundException var3) {
  62. throw new NoClassDefFoundError(var3.getMessage());
  63. }
  64. }
  65. }

三、CGLib 代理

3.1、相关类

  • MethodInterceptor

方法拦截器

  • Enhancer

增强类,用于生成动态代理子类

  • FastClass

主要思想就是在为了避免方法调用时,过度使用反射造成调用慢的问题
给每一个方法一个签名,遇到这个签名时,直接显示调用实现类的实现方法,

3.2、cglib 使用

  • 创建代理 ```java public class CglibProxyFactory implements MethodInterceptor { //得到目标对象 private Object target;

    //使用构造方法传递目标对象 public CglibProxyFactory(Object target) {

    1. super();
    2. this.target = target;

    }

    //创建代理对象 public Object createProxy(){

    1. //1.创建Enhancer
    2. Enhancer enhancer = new Enhancer();
    3. //2.传递目标对象的class
    4. enhancer.setSuperclass(target.getClass());
    5. //3.设置回调操作
    6. enhancer.setCallback(this);
    7. return enhancer.create();

    }

  1. //参数一:代理对象;参数二:需要增强的方法;参数三:需要增强方法的参数;参数四:需要增强的方法的代理
  2. @Override
  3. public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
  4. System.out.println("这是增强方法前......");
  5. Object invoke = methodProxy.invoke(target, args);
  6. System.out.println("这是增强方法后......");
  7. return invoke;
  8. }

}

  1. - 测试
  2. ```java
  3. Car car=new Taxi();
  4. CglibProxyFactory factory=new CglibProxyFactory(car);
  5. Car proxy = (Car) factory.createProxy();
  6. proxy.running();

3.3、查看生成的代理类

  • 配置 输出代理类

    1. System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "./target");
  • 生成的代理类 ```

    命名

    类名EnhancerByCGLIB内存地址

目标代理类

TaxiEnhancerByCGLIBc0b91a45

目标代理类的 FastClass

TaxiEnhancerByCGLIBc0b91a45FastClassByCGLIB287524b5

目标类 的 FastClass代理类

TaxiFastClassByCGLIBc2a0126 ```

四、JDK代理和 CGLib 代理的区别?

  • JDK Proxy 是 Java 语言自带的功能,无需通过加载第三方类实现;
  • Java 对 JDK Proxy 提供了稳定的支持,并且会持续的升级和更新 JDK Proxy,例如 Java 8 版本中的 JDK Proxy 性能相比于之前版本提升了很多;
  • JDK Proxy 是通过拦截器加反射的方式实现的;
  • JDK Proxy 只能代理继承接口的类;
  • JDK Proxy 实现和调用起来比较简单;
  • CGLib 是第三方提供的工具,基于 ASM 实现的,性能比较高;
  • CGLib 无需通过接口来实现,它是通过实现子类的方式来完成调用的。
  • CGLib 执行方法不需要使用反射,本身生成了 FastClass 维护了目标类的的方法和索引的映射

    参考

  • https://juejin.cn/post/6844903926857203725

  • https://www.cnblogs.com/zjfjava/p/13919437.html