cglib动态代理--简单原理

1、cglib动态代理

  1. 引入cglib.jar+asm.jar包。不同于JDK动态代理,cglib代理是通过继承方式实现的(方法不能是final修饰的)

  2. 创建代理类:

    /**
     * @ClassName Sweetheart
     * @Description TODO 代理类
     * @Version 1.0
     **/
    public class Sweetheart implements MethodInterceptor {
    
        //底层通过继承实现
        public Object getInstance(Class<?> targetProxy) {
            //Enhancer相当于Proxy工具
            Enhancer enhancer = new Enhancer();
            //把被代理类设置成父类
            enhancer.setSuperclass(targetProxy);
            //回调下面的intercept();
            enhancer.setCallback(this);
            return enhancer.create();
        }
    
        @Override
        public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
            //方法增强
            before();
            Object o1 = methodProxy.invokeSuper(o, objects);
            after();
            return o1;
        }
    
        private void before() {
            System.out.println("打理公司");
        }
    
        private void after() {
            System.out.println("管理人员");
        }
    }
    
    
  3. 被代理类

    /**
     * @ClassName Boss
     * @Description TODO  被代理对象
     * @Version 1.0
     **/
    public class Boss {
    
        public void managementCompany() {
            System.out.println("管理公司");
        }
    
    }
    
    
  4. 测试

    /**
     * @ClassName CgLibProxyTest
     * @Description TODO
     * @Version 1.0
     **/
    public class CgLibProxyTest {
    
        public static void main(String[] args) {
            Sweetheart sweetheart = new Sweetheart();
    
            Boss boss = (Boss) sweetheart.getInstance(Boss.class);
    
            boss.managementCompany();
        }
    
    }
    
  5. 测试结果

    上班帮boss整理文件,端茶倒水
    管理公司
    下班帮boss关门
    
  6. 利用cglib提供的.class生成工具,看看本地生成的文件
    1).

    	/**
    	 * @ClassName CgLibProxyTest
    	 * @Description TODO
    	 * @Version 1.0
    	 **/
    	public class CgLibProxyTest {
    	
    	    public static void main(String[] args) {
    	        System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "G:\\cglib_proxy_classes");
    	
    	        Sweetheart sweetheart = new Sweetheart();
    	
    	        Boss boss = (Boss) sweetheart.getInstance(Boss.class);
    	
    	        System.out.println(boss.getClass());
    	
    	        boss.managementCompany();
    	
    	    }
    	
    	}
    

    2). 会在G:\cglib_proxy_classes 文件夹下生成三个文件

    	CGLIB debugging enabled, writing to 'G:\cglib_proxy_classes' 
    	class com.ByteDance.cglibproxy.Boss$$EnhancerByCGLIB$$c39f714e
    	上班帮boss整理文件,端茶倒水
    	管理公司
    	下班帮boss关门
    

    本地生成的三个文件
    3). 用jad工具反编译一下
    在这里插入图片描述
    先看看生成的代理对象:
    ***Bossc39f714e.jad***

    // Decompiled by Jad v1.5.8g. Copyright 2001 Pavel Kouznetsov.
    // Jad home page: http://www.kpdus.com/jad.html
    // Decompiler options: packimports(3) 
    // Source File Name:   <generated>
    
    package com.ByteDance.cglibproxy;
    
    import java.lang.reflect.Method;
    import net.sf.cglib.core.ReflectUtils;
    import net.sf.cglib.core.Signature;
    import net.sf.cglib.proxy.*;
    
    // Referenced classes of package com.ByteDance.cglibproxy:
    //            Boss
    
    public class Boss$$EnhancerByCGLIB$$c39f714e extends Boss
        implements Factory
    {
    
        static void CGLIB$STATICHOOK1()
        {
            Method amethod[];
            Method amethod1[];
            CGLIB$THREAD_CALLBACKS = new ThreadLocal();
            CGLIB$emptyArgs = new Object[0];
            Class class1 = Class.forName("com.ByteDance.cglibproxy.Boss$$EnhancerByCGLIB$$c39f714e");
            Class class2;
            amethod = ReflectUtils.findMethods(new String[] {
                "equals", "(Ljava/lang/Object;)Z", "toString", "()Ljava/lang/String;", "hashCode", "()I", "clone", "()Ljava/lang/Object;"
            }, (class2 = Class.forName("java.lang.Object")).getDeclaredMethods());
            Method[] _tmp = amethod;
            CGLIB$equals$1$Method = amethod[0];
            CGLIB$equals$1$Proxy = MethodProxy.create(class2, class1, "(Ljava/lang/Object;)Z", "equals", "CGLIB$equals$1");
            CGLIB$toString$2$Method = amethod[1];
            CGLIB$toString$2$Proxy = MethodProxy.create(class2, class1, "()Ljava/lang/String;", "toString", "CGLIB$toString$2");
            CGLIB$hashCode$3$Method = amethod[2];
            CGLIB$hashCode$3$Proxy = MethodProxy.create(class2, class1, "()I", "hashCode", "CGLIB$hashCode$3");
            CGLIB$clone$4$Method = amethod[3];
            CGLIB$clone$4$Proxy = MethodProxy.create(class2, class1, "()Ljava/lang/Object;", "clone", "CGLIB$clone$4");
            amethod1 = ReflectUtils.findMethods(new String[] {
                "managementCompany", "()V"
            }, (class2 = Class.forName("com.ByteDance.cglibproxy.Boss")).getDeclaredMethods());
            Method[] _tmp1 = amethod1;
            CGLIB$managementCompany$0$Method = amethod1[0];
            CGLIB$managementCompany$0$Proxy = MethodProxy.create(class2, class1, "()V", "managementCompany", "CGLIB$managementCompany$0");
        }
    
        final void CGLIB$managementCompany$0()
        {
            super.managementCompany();
        }
    
        public final void managementCompany()
        {
            CGLIB$CALLBACK_0;
            if(CGLIB$CALLBACK_0 != null) goto _L2; else goto _L1
    _L1:
            JVM INSTR pop ;
            CGLIB$BIND_CALLBACKS(this);
            CGLIB$CALLBACK_0;
    _L2:
            JVM INSTR dup ;
            JVM INSTR ifnull 37;
               goto _L3 _L4
    _L3:
            break MISSING_BLOCK_LABEL_21;
    _L4:
            break MISSING_BLOCK_LABEL_37;
            this;
            CGLIB$managementCompany$0$Method;
            CGLIB$emptyArgs;
            CGLIB$managementCompany$0$Proxy;
            intercept();
            return;
            super.managementCompany();
            return;
        }
    
        final boolean CGLIB$equals$1(Object obj)
        {
            return super.equals(obj);
        }
    
        public final boolean equals(Object obj)
        {
            CGLIB$CALLBACK_0;
            if(CGLIB$CALLBACK_0 != null) goto _L2; else goto _L1
    _L1:
            JVM INSTR pop ;
            CGLIB$BIND_CALLBACKS(this);
            CGLIB$CALLBACK_0;
    _L2:
            JVM INSTR dup ;
            JVM INSTR ifnull 57;
               goto _L3 _L4
    _L3:
            this;
            CGLIB$equals$1$Method;
            new Object[] {
                obj
            };
            CGLIB$equals$1$Proxy;
            intercept();
            JVM INSTR dup ;
            JVM INSTR ifnonnull 50;
               goto _L5 _L6
    _L5:
            JVM INSTR pop ;
            false;
              goto _L7
    _L6:
            (Boolean);
            booleanValue();
    _L7:
            return;
    _L4:
            return super.equals(obj);
        }
    
        final String CGLIB$toString$2()
        {
            return super.toString();
        }
    
        public final String toString()
        {
            CGLIB$CALLBACK_0;
            if(CGLIB$CALLBACK_0 != null) goto _L2; else goto _L1
    _L1:
            JVM INSTR pop ;
            CGLIB$BIND_CALLBACKS(this);
            CGLIB$CALLBACK_0;
    _L2:
            JVM INSTR dup ;
            JVM INSTR ifnull 40;
               goto _L3 _L4
    _L3:
            this;
            CGLIB$toString$2$Method;
            CGLIB$emptyArgs;
            CGLIB$toString$2$Proxy;
            intercept();
            (String);
            return;
    _L4:
            return super.toString();
        }
    
        final int CGLIB$hashCode$3()
        {
            return super.hashCode();
        }
    
        public final int hashCode()
        {
            CGLIB$CALLBACK_0;
            if(CGLIB$CALLBACK_0 != null) goto _L2; else goto _L1
    _L1:
            JVM INSTR pop ;
            CGLIB$BIND_CALLBACKS(this);
            CGLIB$CALLBACK_0;
    _L2:
            JVM INSTR dup ;
            JVM INSTR ifnull 52;
               goto _L3 _L4
    _L3:
            this;
            CGLIB$hashCode$3$Method;
            CGLIB$emptyArgs;
            CGLIB$hashCode$3$Proxy;
            intercept();
            JVM INSTR dup ;
            JVM INSTR ifnonnull 45;
               goto _L5 _L6
    _L5:
            JVM INSTR pop ;
            0;
              goto _L7
    _L6:
            (Number);
            intValue();
    _L7:
            return;
    _L4:
            return super.hashCode();
        }
    
        final Object CGLIB$clone$4()
            throws CloneNotSupportedException
        {
            return super.clone();
        }
    
        protected final Object clone()
            throws CloneNotSupportedException
        {
            CGLIB$CALLBACK_0;
            if(CGLIB$CALLBACK_0 != null) goto _L2; else goto _L1
    _L1:
            JVM INSTR pop ;
            CGLIB$BIND_CALLBACKS(this);
            CGLIB$CALLBACK_0;
    _L2:
            JVM INSTR dup ;
            JVM INSTR ifnull 37;
               goto _L3 _L4
    _L3:
            this;
            CGLIB$clone$4$Method;
            CGLIB$emptyArgs;
            CGLIB$clone$4$Proxy;
            intercept();
            return;
    _L4:
            return super.clone();
        }
    
        public static MethodProxy CGLIB$findMethodProxy(Signature signature)
        {
            String s = signature.toString();
            s;
            s.hashCode();
            JVM INSTR lookupswitch 5: default 120
        //                   -508378822: 60
        //                   421908091: 72
        //                   1826985398: 84
        //                   1913648695: 96
        //                   1984935277: 108;
               goto _L1 _L2 _L3 _L4 _L5 _L6
    _L2:
            "clone()Ljava/lang/Object;";
            equals();
            JVM INSTR ifeq 121;
               goto _L7 _L8
    _L8:
            break MISSING_BLOCK_LABEL_121;
    _L7:
            return CGLIB$clone$4$Proxy;
    _L3:
            "managementCompany()V";
            equals();
            JVM INSTR ifeq 121;
               goto _L9 _L10
    _L10:
            break MISSING_BLOCK_LABEL_121;
    _L9:
            return CGLIB$managementCompany$0$Proxy;
    _L4:
            "equals(Ljava/lang/Object;)Z";
            equals();
            JVM INSTR ifeq 121;
               goto _L11 _L12
    _L12:
            break MISSING_BLOCK_LABEL_121;
    _L11:
            return CGLIB$equals$1$Proxy;
    _L5:
            "toString()Ljava/lang/String;";
            equals();
            JVM INSTR ifeq 121;
               goto _L13 _L14
    _L14:
            break MISSING_BLOCK_LABEL_121;
    _L13:
            return CGLIB$toString$2$Proxy;
    _L6:
            "hashCode()I";
            equals();
            JVM INSTR ifeq 121;
               goto _L15 _L16
    _L16:
            break MISSING_BLOCK_LABEL_121;
    _L15:
            return CGLIB$hashCode$3$Proxy;
    _L1:
            JVM INSTR pop ;
            return null;
        }
    
        public static void CGLIB$SET_THREAD_CALLBACKS(Callback acallback[])
        {
            CGLIB$THREAD_CALLBACKS.set(acallback);
        }
    
        public static void CGLIB$SET_STATIC_CALLBACKS(Callback acallback[])
        {
            CGLIB$STATIC_CALLBACKS = acallback;
        }
    
        private static final void CGLIB$BIND_CALLBACKS(Object obj)
        {
            Boss$$EnhancerByCGLIB$$c39f714e boss$$enhancerbycglib$$c39f714e = (Boss$$EnhancerByCGLIB$$c39f714e)obj;
            if(boss$$enhancerbycglib$$c39f714e.CGLIB$BOUND) goto _L2; else goto _L1
    _L1:
            Object obj1;
            boss$$enhancerbycglib$$c39f714e.CGLIB$BOUND = true;
            obj1 = CGLIB$THREAD_CALLBACKS.get();
            obj1;
            if(obj1 != null) goto _L4; else goto _L3
    _L3:
            JVM INSTR pop ;
            CGLIB$STATIC_CALLBACKS;
            if(CGLIB$STATIC_CALLBACKS != null) goto _L4; else goto _L5
    _L5:
            JVM INSTR pop ;
              goto _L2
    _L4:
            (Callback[]);
            boss$$enhancerbycglib$$c39f714e;
            JVM INSTR swap ;
            0;
            JVM INSTR aaload ;
            (MethodInterceptor);
            CGLIB$CALLBACK_0;
    _L2:
        }
    
        public Object newInstance(Callback acallback[])
        {
            CGLIB$SET_THREAD_CALLBACKS(acallback);
            CGLIB$SET_THREAD_CALLBACKS(null);
            return new Boss$$EnhancerByCGLIB$$c39f714e();
        }
    
        public Object newInstance(Callback callback)
        {
            CGLIB$SET_THREAD_CALLBACKS(new Callback[] {
                callback
            });
            CGLIB$SET_THREAD_CALLBACKS(null);
            return new Boss$$EnhancerByCGLIB$$c39f714e();
        }
    
        public Object newInstance(Class aclass[], Object aobj[], Callback acallback[])
        {
            CGLIB$SET_THREAD_CALLBACKS(acallback);
            JVM INSTR new #2   <Class Boss$$EnhancerByCGLIB$$c39f714e>;
            JVM INSTR dup ;
            aclass;
            aclass.length;
            JVM INSTR tableswitch 0 0: default 35
        //                   0 28;
               goto _L1 _L2
    _L2:
            JVM INSTR pop ;
            Boss$$EnhancerByCGLIB$$c39f714e();
              goto _L3
    _L1:
            JVM INSTR pop ;
            throw new IllegalArgumentException("Constructor not found");
    _L3:
            CGLIB$SET_THREAD_CALLBACKS(null);
            return;
        }
    
        public Callback getCallback(int i)
        {
            CGLIB$BIND_CALLBACKS(this);
            this;
            i;
            JVM INSTR tableswitch 0 0: default 30
        //                   0 24;
               goto _L1 _L2
    _L2:
            CGLIB$CALLBACK_0;
              goto _L3
    _L1:
            JVM INSTR pop ;
            null;
    _L3:
            return;
        }
    
        public void setCallback(int i, Callback callback)
        {
            switch(i)
            {
            case 0: // '\0'
                CGLIB$CALLBACK_0 = (MethodInterceptor)callback;
                break;
            }
        }
    
        public Callback[] getCallbacks()
        {
            CGLIB$BIND_CALLBACKS(this);
            this;
            return (new Callback[] {
                CGLIB$CALLBACK_0
            });
        }
    
        public void setCallbacks(Callback acallback[])
        {
            this;
            acallback;
            JVM INSTR dup2 ;
            0;
            JVM INSTR aaload ;
            (MethodInterceptor);
            CGLIB$CALLBACK_0;
        }
    
        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$managementCompany$0$Method;
        private static final MethodProxy CGLIB$managementCompany$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 
        {
            CGLIB$STATICHOOK1();
        }
    
        public Boss$$EnhancerByCGLIB$$c39f714e()
        {
            CGLIB$BIND_CALLBACKS(this);
        }
    }
    
    
     	首先代理对象会找managementCompany()方法  
     	→  通过回调找拦截器的invoke()方法  
     	→  methodProxy.invokeSuper()  
     	→  final void CGLIB$managementCompany$0() 
     	→  调用被代理对象super.managementCompany()
     	
     	这里可以看到具体是由MethodProxy这个类进行实现的,看看这个类的源码
    
    public class MethodProxy {
        private Signature sig1;
        private Signature sig2;
        private MethodProxy.CreateInfo createInfo;
        private final Object initLock = new Object();
        private volatile MethodProxy.FastClassInfo fastClassInfo;
    
        public static MethodProxy create(Class c1, Class c2, String desc, String name1, String name2) {
            MethodProxy proxy = new MethodProxy();
            proxy.sig1 = new Signature(name1, desc);
            proxy.sig2 = new Signature(name2, desc);
            proxy.createInfo = new MethodProxy.CreateInfo(c1, c2);
            return proxy;
        }
    
        private void init() {
            if (this.fastClassInfo == null) {
                synchronized(this.initLock) {
                    if (this.fastClassInfo == null) {
                        MethodProxy.CreateInfo ci = this.createInfo;
                        MethodProxy.FastClassInfo fci = new MethodProxy.FastClassInfo();
                        fci.f1 = helper(ci, ci.c1);
                        fci.f2 = helper(ci, ci.c2);
                        fci.i1 = fci.f1.getIndex(this.sig1);
                        fci.i2 = fci.f2.getIndex(this.sig2);
                        this.fastClassInfo = fci;
                        this.createInfo = null;
                    }
                }
            }
    
        }
    
        private static FastClass helper(MethodProxy.CreateInfo ci, Class type) {
            Generator g = new Generator();
            g.setType(type);
            g.setClassLoader(ci.c2.getClassLoader());
            g.setNamingPolicy(ci.namingPolicy);
            g.setStrategy(ci.strategy);
            g.setAttemptLoad(ci.attemptLoad);
            return g.create();
        }
    
        private MethodProxy() {
        }
    
        public Signature getSignature() {
            return this.sig1;
        }
    
        public String getSuperName() {
            return this.sig2.getName();
        }
    
        public int getSuperIndex() {
            this.init();
            return this.fastClassInfo.i2;
        }
    
        FastClass getFastClass() {
            this.init();
            return this.fastClassInfo.f1;
        }
    
        FastClass getSuperFastClass() {
            this.init();
            return this.fastClassInfo.f2;
        }
    
        public static MethodProxy find(Class type, Signature sig) {
            try {
                Method m = type.getDeclaredMethod("CGLIB$findMethodProxy", MethodInterceptorGenerator.FIND_PROXY_TYPES);
                return (MethodProxy)m.invoke((Object)null, sig);
            } catch (NoSuchMethodException var3) {
                throw new IllegalArgumentException("Class " + type + " does not use a MethodInterceptor");
            } catch (IllegalAccessException var4) {
                throw new CodeGenerationException(var4);
            } catch (InvocationTargetException var5) {
                throw new CodeGenerationException(var5);
            }
        }
    
        public Object invoke(Object obj, Object[] args) throws Throwable {
            try {
                this.init();
                MethodProxy.FastClassInfo fci = this.fastClassInfo;
                return fci.f1.invoke(fci.i1, obj, args);
            } catch (InvocationTargetException var4) {
                throw var4.getTargetException();
            } catch (IllegalArgumentException var5) {
                if (this.fastClassInfo.i1 < 0) {
                    throw new IllegalArgumentException("Protected method: " + this.sig1);
                } else {
                    throw var5;
                }
            }
        }
    
        public Object invokeSuper(Object obj, Object[] args) throws Throwable {
            try {
                this.init();
                MethodProxy.FastClassInfo fci = this.fastClassInfo;
                return fci.f2.invoke(fci.i2, obj, args);
            } catch (InvocationTargetException var4) {
                throw var4.getTargetException();
            }
        }
    
        private static class CreateInfo {
            Class c1;
            Class c2;
            NamingPolicy namingPolicy;
            GeneratorStrategy strategy;
            boolean attemptLoad;
    
            public CreateInfo(Class c1, Class c2) {
                this.c1 = c1;
                this.c2 = c2;
                AbstractClassGenerator fromEnhancer = AbstractClassGenerator.getCurrent();
                if (fromEnhancer != null) {
                    this.namingPolicy = fromEnhancer.getNamingPolicy();
                    this.strategy = fromEnhancer.getStrategy();
                    this.attemptLoad = fromEnhancer.getAttemptLoad();
                }
    
            }
        }
    
        private static class FastClassInfo {
            FastClass f1;
            FastClass f2;
            int i1;
            int i2;
    
            private FastClassInfo() {
            }
        }
    }
    
    
    	可以看到具体是由fci.f2.invoke(fci.i2, obj, args); 调用代理方法的,
    	这个FastClassInfo中的f1和f2分别是下面两个文件,一个是代理类,一个是被代理类
    

    FastClass f1 代理类
    FastClass f1
    FastClass f2 被代理类
    FastClass f2

    FastClass会为代理方法生成一个index,并且当做入参,这样就会快速找到对应的代理方法,而不需要通过反射来获取,
    因此cglib在调用方法的时候效率比JDK代理要高;  f1和f2不是在生成代理类时就有,而是在MethodProxy第一次调用invoke()
    或者invokeSuper()时通过它的init()生成的,init()会先在缓存找。 
    

2.Spring中应用

	Spring中的ProxyFactoryBean最核心的getObject(),在spring中默认是生成singleton的代理bean,多实例的比较复杂
 public Object getObject() throws BeansException {
     initializeAdvisorChain();
     if (isSingleton()) {
         return getSingletonInstance();
     } else {
         if (this.targetName == null) {
             logger.warn("Using non-singleton proxies with singleton targets is often undesirable. " + "Enable prototype proxies by setting the 'targetName' property.");
         }
         return newPrototypeInstance();
     }
 }
spring通过AopProxy下的JdkDynamicAopProxy和CglibAopProxy来实现动态代理,
	1、如果bean实现了接口,则用JdkDynamicAopProxy
	2、如果bean没有实现接口,则用CglibAopProxy

在spring中,可用通过配置强制指定使用CglibAopProxy,如
	1、<aop:aspectj-autoproxy proxy-target-class="true"/>,强制用cglib
	2、@EnableAspectJAutoProxy(proxyTargetClass = true),强制用cglib  (只要引入了AOP依赖后,默认开启)
	3、yml加 
			spring:
			  aop:
				proxy-target-class: true  ,强制用cglib
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值