spring 如何通过cglib 生成动态代理

文章目录

目标

理解spring中如何通过cglib的方式生成动态代理。 我们都知道,spring中存在两种动态代理的方式,第一个是jdk动态代理的方式,本质是通过反射实现,第二个是cglib的方式,这个是需要操作字节码实现。第一种方式虽然效率会更高,但是却存在硬伤,代理类必须是基于接口的。而方式二则没有这些限制。我们之前有一篇文章是分析jdk动态代理方式实现,这篇文章则重点是cglib方式如何实现动态代理。
本文将会通过将运行期间的对象保存到本地,生成java的字节码,窥探cglib的运行机制。

源码分析

入口类,从这里创建cglib对象

public class testAopCglibKProxy {
    public static void main(String[] args) {
        new testAopCglibKProxy().testCglibProxy();
    }
   public void testCglibProxy() {
       System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY,"/Users/apple/logs");
       System.out.println("before Proxy......");
       //目标对象(原始对象)
       UserServiceImpl userService = new UserServiceImpl();
       userService.saveUser("zby", "1234567890");
       System.out.println("引入Cglib  Proxy代理库 后......");
       //代理对象,也就是被增强后的对象 下面这句代码是重点。
       UserServiceImpl proxyUserService = (UserServiceImpl) CglibProxyGenerator.generatorCglibProxy(userService, new CustomAspect());
       proxyUserService.saveUser("zby", "1234567890");
   }
}

cglib的生成器

public class CglibProxyGenerator {
    /**
     * @param target 需要被代理的委托类对象,Cglib需要继承该类生成子类
     * @param aspect 切面对象,改对象方法将在切点方法之前或之后执行
     * @return
     */
    public static Object generatorCglibProxy(final Object target, final IAspect aspect) {        
    	//3.1 new Enhancer 创建生成器
        Enhancer enhancer = new Enhancer();
        //3.2 设置需要代理的父类
        enhancer.setSuperclass(target.getClass());
        //3.3 设置回调 ,具体这个回调是怎么执行,有什么用,我们后文分析
        enhancer.setCallback(new MethodInterceptor() {
            @Override
            public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
                // 执行切面方法
                aspect.startTransaction();
                // 具体逻辑代码执行,返回值为方法执行结果
                Object result = methodProxy.invokeSuper(proxy, args);
                // 执行切面方法
                aspect.endTrasaction();
                // 返回方法执行结果
                return result;
            }
        });
        // 3.4 创建代理对象
        return enhancer.create();
    }
}

下面贴出目标对象&切面对象代码

// 切面对象,也就是需要给目标对象进行增强的一些逻辑内容,比如事物控制等
public class CustomAspect implements IAspect {
    @Override
    public void startTransaction() {
        System.out.println("cglib. I get datasource here and start transaction");
    }

    public void endTrasaction() {
        System.out.println("cglib I get datasource here and end transaction");
    }
}
//原始对象,也就是目标对象。没有增强之前的对象
public class UserServiceImpl {
    public void saveUser(String username, String password) {
        System.out.println("cglib save user[username=" + username + ",password=" + password + "]");
    }
}

现在我们展示运行起来后生成的代理对象,虽然只能拿到class文件,但是编辑器可以帮助我们反编译为java代码。
在这里插入图片描述

最后就是代码对象反编译的java代码了。

// extends UserServiceImpl 重点 代理对象继承了目标对象
public class UserServiceImpl$$EnhancerByCGLIB$$b4be90dd extends UserServiceImpl implements Factory {
    private boolean CGLIB$BOUND;
    public static Object CGLIB$FACTORY_DATA;
    private static final ThreadLocal CGLIB$THREAD_CALLBACKS;
    private static final Callback[] CGLIB$STATIC_CALLBACKS;
    private MethodInterceptor CGLIB$CALLBACK_0;
    private static Object CGLIB$CALLBACK_FILTER;
    private static final Method CGLIB$saveUser$0$Method;
    private static final MethodProxy CGLIB$saveUser$0$Proxy;
    private static final Object[] CGLIB$emptyArgs;
    private static final Method CGLIB$equals$1$Method;
    private static final MethodProxy CGLIB$equals$1$Proxy;
    private static final Method CGLIB$toString$2$Method;
    private static final MethodProxy CGLIB$toString$2$Proxy;
    private static final Method CGLIB$hashCode$3$Method;
    private static final MethodProxy CGLIB$hashCode$3$Proxy;
    private static final Method CGLIB$clone$4$Method;
    private static final MethodProxy CGLIB$clone$4$Proxy;

    static void CGLIB$STATICHOOK1() {
        CGLIB$THREAD_CALLBACKS = new ThreadLocal();
        CGLIB$emptyArgs = new Object[0];
        Class var0 = Class.forName("org.dromara.hmily.demo.springcloud.order.test.UserServiceImpl$$EnhancerByCGLIB$$b4be90dd");
        Class var1;
        //目标对象UserServiceImpl 中定义的方法
        CGLIB$saveUser$0$Method = ReflectUtils.findMethods(new String[]{"saveUser", "(Ljava/lang/String;Ljava/lang/String;)V"}, (var1 = Class.forName("org.dromara.hmily.demo.springcloud.order.test.UserServiceImpl")).getDeclaredMethods())[0];
        //目标对象UserServiceImpl 中定义的方法
        CGLIB$saveUser$0$Proxy = MethodProxy.create(var1, var0, "(Ljava/lang/String;Ljava/lang/String;)V", "saveUser", "CGLIB$saveUser$0");
        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");
    }

    final void CGLIB$saveUser$0(String var1, String var2) {
        super.saveUser(var1, var2);
    }
	//这里重写了父类的方法 
    public final void saveUser(String var1, String var2) {
        MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
        
        if (var10000 == null) {
            CGLIB$BIND_CALLBACKS(this);
            var10000 = this.CGLIB$CALLBACK_0;
        }

        if (var10000 != null) {
        	//前面我们构造Enhance对象的时候往里面填充了MethodInterceptor对象。这个MethodInterceptor就在这个时候会被调用
            var10000.intercept(this, CGLIB$saveUser$0$Method, new Object[]{var1, var2}, CGLIB$saveUser$0$Proxy);
        } else {
            super.saveUser(var1, var2);
        }
    }
    //。。省略
    public static MethodProxy CGLIB$findMethodProxy(Signature var0) {
        String var10000 = var0.toString();
        switch(var10000.hashCode()) {
        case -630724063:
            if (var10000.equals("saveUser(Ljava/lang/String;Ljava/lang/String;)V")) {
                return CGLIB$saveUser$0$Proxy;
            }
            break;
        case -508378822:
            if (var10000.equals("clone()Ljava/lang/Object;")) {
                return CGLIB$clone$4$Proxy;
            }
            break;
        case 1826985398:
            if (var10000.equals("equals(Ljava/lang/Object;)Z")) {
                return CGLIB$equals$1$Proxy;
            }
            break;
        case 1913648695:
            if (var10000.equals("toString()Ljava/lang/String;")) {
                return CGLIB$toString$2$Proxy;
            }
            break;
        case 1984935277:
            if (var10000.equals("hashCode()I")) {
                return CGLIB$hashCode$3$Proxy;
            }
        }

        return null;
    }

    private static final void CGLIB$BIND_CALLBACKS(Object var0) {
        UserServiceImpl$$EnhancerByCGLIB$$b4be90dd var1 = (UserServiceImpl$$EnhancerByCGLIB$$b4be90dd)var0;
        if (!var1.CGLIB$BOUND) {
            var1.CGLIB$BOUND = true;
            Object var10000 = CGLIB$THREAD_CALLBACKS.get();
            if (var10000 == null) {
                var10000 = CGLIB$STATIC_CALLBACKS;
                if (var10000 == null) {
                    return;
                }
            }

            var1.CGLIB$CALLBACK_0 = (MethodInterceptor)((Callback[])var10000)[0];
        }

    }

    static {
        CGLIB$STATICHOOK1();
    }
}

小结

从代理对象反编译源码可以知道,代理对象继承于HelloService,拦截器调用intercept()方法,
intercept()方法由自定义MyMethodInterceptor实现,所以,最后调用MyMethodInterceptor中
的intercept()方法,从而完成了由代理对象访问到目标对象的动态代理实现。

至此大致明白了cglib的一个流程。以及实现过程的一些关键因素,但是内部的一些细节仍旧是迷惑的,比如字节码如何生成,等。

猜你喜欢

转载自blog.csdn.net/ygy982883422/article/details/105909439