Java动态代理-CGLIB(3)

CGLIB 动态代理:

  1. JDK 动态代理,JDK 动态代理的类必须实现一个接口,而且生成的代理类是其接口的实现类,也就是被代理的类的兄弟类,由JDK内部实现,
  2. cglib代理的类,无需强制实现接口,其生成的代理类 是 被代理类的子类,并且重写的被代理类的方法,而且需要额外的引入Jar

简单实现:

  1. 计算一个 sql 调用总时间

代码逻辑:

  1. 引入Maven 配置:
<dependency>
      <groupId>cglib</groupId>
      <artifactId>cglib</artifactId>
      <version>3.2.12</version>
</dependency>
  1. 创建一个需要被代理的类 SqlService:
public class SqlService {
    public void executeSql1() throws InterruptedException {
        System.out.println("Sql 开始执行.....");
        Thread.sleep(1000);
        System.out.println("Sql 执行结束.....");
    }
}
  1. 创建代理类: SqlFacadeCglib
public class SqlFacadeCglib implements MethodInterceptor {

    /**
     * 被代理的对象
     */
    private Object target;

    public SqlFacadeCglib(Object target) {
        this.target = target;
    }

    /**
     *  实现回调方法
     * @param obj 代理的对象
     * @param method 被代理对象的方法
     * @param args  参数集合
     * @param proxy 生成的代理类的方法
     * @return
     * @throws Throwable
     */
    @Override
    public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
        // 开始执行时间
        Long startTime = System.currentTimeMillis();
        // //调用业务类(父类中)的方法
        Object result = proxy.invokeSuper(obj, args);
        // 执行结束
        Long endTime = System.currentTimeMillis();
        System.out.println(target.getClass().getName()+"执行executeSql耗时"+(endTime-startTime)+"ms");
        return result;
    }
}
  1. 创建一个Test:
public class Test {

    public static void main(String[] args) throws InterruptedException, IOException {
        // 将class 文件保存
        System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "F:/mycode/Git/spring-mvc/learn/design-pattern-learn/src/main/java/com/lot/cglibproxy");
        SqlService sqlService = new SqlService();
        SqlFacadeCglib sqlFacadeCglib = new SqlFacadeCglib(sqlService);

        //创建加强器,用来创建动态代理类
        Enhancer enhancer = new Enhancer();
        //为加强器指定要代理的业务类(即:为下面生成的代理类指定父类)
        enhancer.setSuperclass(sqlService.getClass());

        //设置回调:对于代理类上所有方法的调用,都会调用CallBack,而Callback则需要实现intercept()方法进行拦
        enhancer.setCallback(sqlFacadeCglib);
        // 创建动态代理类对象并返回
        SqlService sqlServiceProxy = (SqlService)enhancer.create();
        // 调用
        sqlServiceProxy.executeSql1();

    }
}

执行结果:

  1. 控制台打印:
CGLIB debugging enabled, writing to 'F:/mycode/Git/spring-mvc/learn/design-pattern-learn/src/main/java/com/lot/cglibproxy'
Sql 开始执行.....
Sql 执行结束.....
com.lot.cglibproxy.SqlService执行executeSql耗时1018ms
  1. Debug 时 看到 sqlServiceProxy 定义:
    在这里插入图片描述
  2. 根据Debug的显示 结合 System.setProperty() 写入文件的位置,我们找到 生成的代理类:SqlService¥¥EnhancerByCGLIB¥¥ecb184ce : (简略后代码) :
public class SqlService$$EnhancerByCGLIB$$ecb184ce extends SqlService implements Factory {

    static void CGLIB$STATICHOOK1() {
        CGLIB$THREAD_CALLBACKS = new ThreadLocal();
        // 参数集合
        CGLIB$emptyArgs = new Object[0];
        Class var0 = Class.forName("com.lot.cglibproxy.SqlService$$EnhancerByCGLIB$$ecb184ce");
        Class var1;
        Method[] var10000 = ReflectUtils.findMethods(new String[]{"equals", "(Ljava/lang/Object;)Z", "toString", "()Ljava/lang/String;", "hashCode", "()I", "clone", "()Ljava/lang/Object;"}, (var1 = Class.forName("java.lang.Object")).getDeclaredMethods());
        CGLIB$equals$1$Method = var10000[0];
        CGLIB$equals$1$Proxy = MethodProxy.create(var1, var0, "(Ljava/lang/Object;)Z", "equals", "CGLIB$equals$1");
        CGLIB$toString$2$Method = var10000[1];
        CGLIB$toString$2$Proxy = MethodProxy.create(var1, var0, "()Ljava/lang/String;", "toString", "CGLIB$toString$2");
        CGLIB$hashCode$3$Method = var10000[2];
        CGLIB$hashCode$3$Proxy = MethodProxy.create(var1, var0, "()I", "hashCode", "CGLIB$hashCode$3");
        CGLIB$clone$4$Method = var10000[3];
        CGLIB$clone$4$Proxy = MethodProxy.create(var1, var0, "()Ljava/lang/Object;", "clone", "CGLIB$clone$4");
        // 被代理类的 executeSql1() 方法
        CGLIB$executeSql1$0$Method = ReflectUtils.findMethods(new String[]{"executeSql1", "()V"}, (var1 = Class.forName("com.lot.cglibproxy.SqlService")).getDeclaredMethods())[0];
        // 生成代理类的 executeSql1() 方法
        CGLIB$executeSql1$0$Proxy = MethodProxy.create(var1, var0, "()V", "executeSql1", "CGLIB$executeSql1$0");
    }
    public final void executeSql1() throws InterruptedException {
        MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
        if (this.CGLIB$CALLBACK_0 == null) {
            CGLIB$BIND_CALLBACKS(this);
            var10000 = this.CGLIB$CALLBACK_0;
        }

        if (var10000 != null) {
            // 执行 SqlFacadeCglib.intercept() 方法
            var10000.intercept(this, CGLIB$executeSql1$0$Method, CGLIB$emptyArgs, CGLIB$executeSql1$0$Proxy);
        } else {
            super.executeSql1();
        }
    }
    // 省略代码,有兴趣大家可以查看
}

总结:

  1. 在 Test.main() 方法中,使用 Enhancer 加强器和 我们自己定义的类SqlService、SqlFacadeCglib组合,再通过enhancer.create()创建代理类。从代理类的源码中,我们可以看到代理类其实是我们业务类的子类
  2. 当我们在执行 sqlServiceProxy.executeSql1()时 实际上是访问 CGLIB生成的代理类的 executeSql1() 方法,然后在调用 SqlFacadeCglib.intercept() 做一些公共逻辑处理,其中 proxy.invokeSuper(obj, args) 这段代码是执行 我们业务逻辑类中的方法:SqlService.executeSql1()
  3. 其实动态代理的目的就是帮我们整合业务逻辑类,和共有的方法,并生成代理类,大大简化了我们开发工作量,其中 Spring 中对动态代理有很深的使用。

后续:

1、静态代理: https://blog.csdn.net/zhangyong01245/article/details/90519769
2、Java 动态代理实现: https://blog.csdn.net/zhangyong01245/article/details/90598309
3、CGLIB动态代理以及逻辑: https://blog.csdn.net/zhangyong01245/article/details/90644933

以上是博主自己的理解与想法, 如有异议请大家留言,博主一定会第一时间解决


版权声明:本文为zhangyong01245原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
THE END
< <上一篇
下一篇>>