CGLIB动态代理

CGLIB动态代理


此文是不知道何时总结的,可能有不严谨的地方,仅供参考备份用,日后再修改。

和基于JDK的动态代理不同的是:

  • JDK争对接口进行动态代理,代理类和委托类共同实现同一个接口,只代理接口中声明的方法;

  • CGLIB动态代理依赖于CGLIB的类库需要配置依赖,实现原理上,CGLIB动态代理争对继承进行代理,代理类继承于委托类;


CGLIB动态代理简单演示

//委托类
public class CglibTest {
    public void show1(){
        System.out.println("show1.....");
    }
}
//代理类的拦截器
public class CglibTestProxy implements MethodInterceptor {
    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        System.out.println("调用了intercept()1");
        Object obj=methodProxy.invokeSuper(o,objects);
        System.out.println("调用了intercept()2");
        return obj;
    }

    public Object getProxyObj(Class<?> clazz){
        Enhancer enhancer=new Enhancer();
        //设置代理类的父类即委托类
        enhancer.setSuperclass(clazz);
        //设置代理类的拦截器即本类
        enhancer.setCallback(this);
        //创建代理类
        return enhancer.create();
    }
}
//测试类
public class ProxyTest {
    public static void main(String[] args) {
        CglibTestProxy cglibTestProxy = new CglibTestProxy();
        CglibTest proxyObj = (CglibTest) cglibTestProxy.getProxyObj(CglibTest.class);
        proxyObj.show1();
    }
}

在这里插入图片描述


在讲CGLIB原理之前,讲一下FastClass:

**为一个对象A创建它的FastClass对象,这个FastClass对象相当于A的方法索引,根据A的方法名生成并关联一个index、每个index对应A的一个方法。后续只要根据这个index以及A的实例,就可以调用fastClass的invoke(instanceOfA, index, args)方法来快速的调用A的方法了。实现了Java反射的“运行时动态调用指定类的方法”的功能,但是使用了不同的机制。**我们知道,java反射调用方法是比较“重”的操作,要经过一系列的权限验证、通过native方法请求jvm去方法区查找方法定义、以及最后的invoke仍然可能要通过JNI调用native方法。而相比之下,FastClass方式则跟一般的一个普通的对象方法调用没啥区别、只是多了一步根据index判断调用委托类的哪个方法这一步骤、性能损耗基本没有。

示例:

//普通类
public class Demo {
    private double num1;
    private double num2;

    public Demo(double num1, double num2) {
        this.num1 = num1;
        this.num2 = num2;
    }

    public Demo() {
    }
	//加方法
    public void add(){
        System.out.println(num1+num2);
    }
	//减方法
    public void subtract(){
        System.out.println(num1-num2);
    }
}
//FastClass类
public class DemoFastClass {
    //方法名与一个索引关联
    public int getIndex(String methodName){
        switch (methodName){
            case "add":return 0;
            case "subtract":return 1;
            default:return -1;
        }
    }
    //实现方法
    public Object invoke(int index,Object obj,Object[] objs){
        Demo demo=(Demo)obj;
        switch (index){
            case 0:demo.add();return null;
            case 1:demo.subtract();return null;
            default:return null;
        }
    }
}
//测试类
public class FastClassTest {
    public static void main(String[] args) {
        Demo demo=new Demo(8,7);
        DemoFastClass demoFastClass=new DemoFastClass();
        int index = demoFastClass.getIndex("add");
        demoFastClass.invoke(index,demo,null);
    }
}

按理来说,用一个类的Class对象就可以构造类的FastClass,再拥有类的方法名就可以执行方法


原理:

生成的代理类(DemoEnhancerByCGLIBfbca2ec6)拥有一个拦截器的引用,委托类中的每一个方法(假设是fangfa())都对应生成的代理类中的两个属性

	//CGLIB$fangfa$0$Method是通过反射机制获取的委托类的fangfa()方法
	private static final Method CGLIB$fangfa$0$Method;
	//CGLIB$fangfa$0$Proxy
    private static final MethodProxy CGLIB$fangfa$0$Proxy;

和两个方法

	//重写了父类方法
	public final void fangfa(){....拦截器.intercept();...}
	public void CGLIB$fangfa$0(){super.fangfa();}

CGLIB$fangfa 0 0 0Proxy的生成过程

Class class1 = Class.forName("Demo$$EnhancerByCGLIB$$fbca2ec6");
Class class2 = Class.forName("Demo")
    //参数1:委托类Class对象;参数2:代理类Class对象;参数3:方法返回值;参数4:委托类中的方法名;参数5:代理类中的方法名
CGLIB$eat$0$Proxy = MethodProxy.create(class2, class1, "()V", "fangfa", "CGLIB$fangfa$0");

MethodProxy类的属性:

private Signature sig1;//委托类的方法信息(方法名,返回值)
private Signature sig2;//代理类类的方法信息(方法名,返回值)
private MethodProxy.CreateInfo createInfo;//委托类和代理类的Class对象
private final Object initLock = new Object();//锁
private volatile MethodProxy.FastClassInfo fastClassInfo;//FastClass信息(委托类和代理类的FastClass的对象和两个方法的索引

MethodProxy的invokeSuper():

//配合下面的init()理解
public Object invokeSuper(Object obj, Object[] args) throws Throwable {
    try {
        //初始化MethodProxy对象,创建FastClass对象和获得对应方法索引
        this.init();
        MethodProxy.FastClassInfo fci = this.fastClassInfo;
        //代理类的FastClass对象实现代理类的CGLIB$fangfa$0()方法,从而实现了super.fangfa()即委托类的fangfa()
        return fci.f2.invoke(fci.i2, obj, args);
    } catch (InvocationTargetException var4) {
        throw var4.getTargetException();
    }
}

init():

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();
                //helper()是构造FastClass的方法,通过委托类和代理类的Class对象构造其FastClass对象
                fci.f1 = helper(ci, ci.c1);//委托类FastClass对象
                fci.f2 = helper(ci, ci.c2);//代理类FastClass对象
                fci.i1 = fci.f1.getIndex(this.sig1);//getIndex方法获得对应的索引值<fangfa()>
                fci.i2 = fci.f2.getIndex(this.sig2);//getIndex方法获得对应的索引值<CGLIB$fangfa$0()>
                this.fastClassInfo = fci;
                this.createInfo = null;
            }
        }
    }
}

在调用代理类中的fangfa()时,会被拦截器拦截转到intercept()中,这是我们实现的intercept()

@Override
//参数1:最终实现方法的实体,是代理类的实例,最终实现了CGLIB$fangfa$0();
//参数2:委托类中的方法即上文中的CGLIB$fangfa$0$Method;
//参数3:方法参数;
//参数4:方法代理即上文中的CGLIB$fangfa$0$Proxy
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
    System.out.println("调用了intercept()1");
    Object obj=methodProxy.invokeSuper(o,objects);
    System.out.println("调用了intercept()2");
    return obj;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
CGLIB是一个强大的开源代码生成库,它可以在运行时扩展Java类和实现接口。CGLIB动态代理CGLIB库的一个重要特性,它通过生成目标类的子类来实现代理。 在CGLIB动态代理中,我们可以使用`MethodInterceptor`接口来定义代理逻辑。`MethodInterceptor`接口有一个`intercept`方法,该方法在目标方法被调用时被触发。在`intercept`方法中,我们可以编写自定义的逻辑来增强目标方法的功能。 下面是一个使用CGLIB动态代理的示例代码: ```java import net.sf.cglib.proxy.Enhancer; import net.sf.cglib.proxy.MethodInterceptor; import net.sf.cglib.proxy.MethodProxy; import java.lang.reflect.Method; public class CglibProxyExample implements MethodInterceptor { public Object createProxy(Object target) { Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(target.getClass()); enhancer.setCallback(this); return enhancer.create(); } @Override public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable { // 在目标方法执行前的逻辑 System.out.println("Before method: " + method.getName()); // 调用目标方法 Object result = proxy.invokeSuper(obj, args); // 在目标方法执行后的逻辑 System.out.println("After method: " + method.getName()); return result; } } ``` 在上述示例中,我们首先创建了一个`CglibProxyExample`类,实现了`MethodInterceptor`接口。然后,我们通过`Enhancer`类创建了一个代理对象,并设置了目标类和代理逻辑。在`intercept`方法中,我们可以在目标方法执行前后添加自定义的逻辑。 使用CGLIB动态代理时,我们可以通过调用`createProxy`方法来创建代理对象。例如: ```java SomeClass target = new SomeClass(); CglibProxyExample proxyExample = new CglibProxyExample(); SomeClass proxy = (SomeClass) proxyExample.createProxy(target); ``` 这样,我们就可以通过`proxy`对象来调用目标类的方法,并在方法执行前后添加自定义的逻辑。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值