《Java知识应用》Java CGLib动态代理使用和原理说明

一、CGLib jar包下载

百度网盘:

链接:https://pan.baidu.com/s/1O_5o_vtPWEZ3Hy0CHlZDug
提取码:5wf6

CGLib要使用还需要额外的asm.jar

链接:https://pan.baidu.com/s/1874lFlpOLsdzPUs7O9Ol-g
提取码:wf68 

二、CGLib应用案例

package demo.knowledgepoints.cglib;

public class BaseDemo {

    private String Name;

    public String getName() {
        return Name;
    }

    public void setName(String name) {
        Name = name;
    }

    @Override
    public String toString() {
        return "BaseDemo{" +
                "Name='" + Name + '\'' +
                '}';
    }
}
package demo.knowledgepoints.cglib;

import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;

public class MyMethodInterceptor implements MethodInterceptor {

    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        System.out.println("=============执行自己想要的内容start================");
        System.out.println("method.getName():" + method.getName());
        Object object = methodProxy.invokeSuper(o,objects);
        System.out.println("=============执行自己想要的内容end================");
        return object;
    }
}
package demo.knowledgepoints.cglib;

import net.sf.cglib.core.DebuggingClassWriter;
import net.sf.cglib.proxy.Enhancer;

public class CGLibTest {

    public static void main(String[] args) {
        System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "src\\demo\\knowledgepoints\\cglib");

        /**
         * 该类为CGLib设置动态代理的核心,你设置一个怎么样的动态代理
         */
        Enhancer enhancer = new Enhancer();
        /*******设置需要被代理的类**************/
        enhancer.setSuperclass(BaseDemo.class);
        /*******设置代理类**************/
        enhancer.setCallback(new MyMethodInterceptor());
        /*******创建代理类**************/
        BaseDemo proxyBaseDemo = (BaseDemo)enhancer.create();

        proxyBaseDemo.setName("李磊");

    }
}

运行结果:

这里会出现一个比较有意思的情况,如果是dubug运行会出现如下打印信息

简单解释一下:因为IDEA duebug下,你会需要查询信息,而这些信息其实就是IDEA默认在调用你对象的toString方法。IDEA执行的toString当然也被代理了。

三、CGLib动态代理原理

CGLib动态代理原理和JDK动态原理本质区别很大。

CGLib动态代理原理:是通过子类继承来实现动态代理的。上面的应用程序我们已经将CGLib的代理类生成到本地:

我们可以看看反编译后里面的代码。

public class BaseDemo$$EnhancerByCGLIB$$3c73e677 extends BaseDemo implements Factory{
    final String CGLIB$toString$0() {
        return super.toString();
    }

    public final String toString() {
        MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
        if (this.CGLIB$CALLBACK_0 == null) {
            CGLIB$BIND_CALLBACKS(this);
            var10000 = this.CGLIB$CALLBACK_0;
        }

        return var10000 != null ? (String)var10000.intercept(this, CGLIB$toString$0$Method, CGLIB$emptyArgs, CGLIB$toString$0$Proxy) : super.toString();
    }

    final String CGLIB$getName$1() {
        return super.getName();
    }

    public final String getName() {
        MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
        if (this.CGLIB$CALLBACK_0 == null) {
            CGLIB$BIND_CALLBACKS(this);
            var10000 = this.CGLIB$CALLBACK_0;
        }

        return var10000 != null ? (String)var10000.intercept(this, CGLIB$getName$1$Method, CGLIB$emptyArgs, CGLIB$getName$1$Proxy) : super.getName();
    }

    final void CGLIB$setName$2(String var1) {
        super.setName(var1);
    }

    public final void setName(String var1) {
        MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
        if (this.CGLIB$CALLBACK_0 == null) {
            CGLIB$BIND_CALLBACKS(this);
            var10000 = this.CGLIB$CALLBACK_0;
        }

        if (var10000 != null) {
            var10000.intercept(this, CGLIB$setName$2$Method, new Object[]{var1}, CGLIB$setName$2$Proxy);
        } else {
            super.setName(var1);
        }
    }
}

上述代码是我取了其中比较重要的信息,真实代理类,还会多一些代码。

从上面的文件内容可以看出:

1. 继承了BaseDemo 

2. 实现Factory 接口,该接口可以创建对象等功能。

3. 重写了父类方法,并且还是会调用原父类方法。

更多使用方法见CGLib API :http://devdoc.net/javamisc/cglib-3.2.5/

posted @ 2020-04-04 23:36  加速丨世界  阅读(861)  评论(0编辑  收藏  举报