使用CGLib实现动态代理

本文介绍了在Java中如何使用CGLib实现动态代理,因为Java的动态代理需要基于接口,而CGLib则允许对类进行动态扩展。文章详细讲解了CGLib的核心类Enhancer和MethodInterceptor,通过示例展示了如何创建代理对象并实现方法拦截,以在调用外部类方法时打印入参和结果。此外,还提及CGLib在Spring AOP中的应用及其性能优势。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、背景
    在上一篇博客中(java动态代理:http://blog.youkuaiyun.com/wenhuayuzhihui/article/details/51700670)提到,java的动态代理是必须基于接口的,而在编程中,使用到的外部类并不是基于接口编程的比比皆是,这有如何实现动态代理?使用可以基于类实现动态代理的CGLib!

二、简介
    CGLib(Code Generation Library)是一个强大、高性能的Code生成类库,它可以在程序运行期间动态扩展类或接口;它的底层是使用java字节码操作框架ASM实现;

三、使用
    CGLib核心类:

1、net.sf.cglib.proxy.Enhancer:主要增强类,通过字节码技术动态创建委托类的子类实例;

2、net.sf.cglib.proxy.MethodInterceptor:常用的方法拦截器接口,需要实现intercept方法,实现具体拦截处理;

public java.lang.Object intercept(java.lang.Object obj,
                                  java.lang.reflect.Method method,
                                  java.lang.Object[] args,
                                  MethodProxy proxy)
                           throws java.lang.Throwable
obj:动态生成的代理对象
method : 实际调用的方法
args:调用方法入参
proxy:
net.sf.cglib.proxy.MethodProxy:java Method类的代理类,可以实现委托类对象的方法的调用;常用方法:methodProxy.invokeSuper(proxy, args);在拦截方法内可以调用多次

我们继续以java动态代理实例的需求演示CGLib动态代理(调用外部类方法是,打印入参,完成后,打印结果),假设外部类没有基于接口编程,我们无法再使用java的动态代理实现这个需求,只能使用CGLib实现:
/**
 * 简单的外部类
 * @author hwz
 *
 */
public class OtherOuterClass {

    /**
     * 字符串翻转
     * @param str
     * @return
     */
    public String methodOne(String str) {
        return new StringBuilder(str).reverse().toString();
    }

    /**
     * 两个整数乘积
     * @param a
     * @param b
     * @return
     */
    public int methodSecond(int a, int b) {
        return a*b;
    }
}
/**
 * 代理方法拦截器
 * @author hwz
 *
 */
public class CglibProxy implements MethodInterceptor {

    private Enhancer enhancer = new Enhancer();

    public Object getProxy(Class clazz) {
        enhancer.setSuperclass(clazz);
        enhancer.setCallback(this);
        return enhancer.create();
    }

    @Override
    public Object intercept(Object obj, Method method, Object[] args,
            MethodProxy proxy) throws Throwable {
        //打印入参日志
        StringBuilder builder = new StringBuilder();
        if (args != null) {
            for (int i=0; i<args.length; ++i) {
                builder.append(",arg" + i + "=" + args[i].toString());
            }
        }
        System.out.println("Enter " + method.toString() + ",args:" + builder.toString());

        //Object result = method.invoke(obj, args); //直接使用obj调用方法,会发生和java动态代理一样的无限循环调用
        Object result = proxy.invokeSuper(obj, args);

        //打印结果日志
        System.out.println("Leave " + method.toString() + ",result=" + result.toString());
        return result;
    }
}
/**
 * 测试类
 * @author hwz
 *
 */
public class CglibProxyTest {

    public static void main(String[] args) {

        CglibProxy cglibProxy = new CglibProxy();
        OtherOuterClass proxyObj = (OtherOuterClass) cglibProxy.getProxy(OtherOuterClass.class);

        proxyObj.methodOne("abcdef");
        proxyObj.methodSecond(2, 4);
    }
}
在spring的AOP中,就是使用到java的动态代理和CGLib,默认情况下,基于接口的切面是使用java动态代理;
有比较表明CGLib的性能高于java本身的动态代理,后续我们再比较分析;




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值