代理技术简介(三):CGlib动态代理

本文介绍如何使用CGLib库实现动态代理,无需接口即可为任意类生成代理对象,适用于JDK动态代理无法覆盖的场景。通过示例代码展示了CGLib的基本用法及其实现原理。

在前面的文章:代理技术简介(二):JDK动态代理,介绍了JDK动态代理,用了这个DynamicProxy以后,觉得它还是非常好的,好的地方是,接口变了,这个动态代理类不用做改动。而静态代理就不一样了,接口变了,实现类还需要动,代理类也需要动。但是JDK动态代理也并不是”万灵丹”,也有局限性,它也有搞不定的时候,比如要代理一个没有任何接口的类,它就没有用武之地了。

那么,能否代理没有接口的类呢?答案是肯定的,那就是CGlib这个类库。虽然它看起来不太起眼,但是SpringHibernate这样高端的开源框架都用到了它。它是一个在运行期间动态生成字节码的工具,也就是动态生成代理类了。说起来很高深,实际用起来一点也不难,下面再写一个CGlibProxy:
我使用的maven工程进行构建,先引入依赖:

<dependency>
    <groupId>cglib</groupId>
    <artifactId>cglib</artifactId>
        <version>3.1</version>
</dependency>

编写CGlibProxy

import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

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

public class CGlibProxy implements MethodInterceptor {

    @SuppressWarnings("unchecked")
    public <T> T getProxy(Class<T> cls){
        return (T) Enhancer.create(cls, this);
    }

    @Override
    public Object intercept(Object obj, Method method, Object[] arg,
            MethodProxy proxy) throws Throwable {
        before();
        Object result = proxy.invokeSuper(obj, arg);
        after();
        return result;
    }

    private void before() {
        System.out.println("Before...");
    }

    private void after() {
        System.out.println("After...");
    }
}

需要实现CGLib给我们提供的MethodInterceptor接口,并填充intercept方法。方法中最后一个MethodProxy类型的参数proxy值得注意,CGLib给我们提供的是方法级别的代理,也可以理解为对方法的拦截(这不就是传说中的”方法拦截器”吗?)。这个功能对于我们来说,如同雪中送炭。我们直接调用proxyinvokeSuper方法,将被代理的对象obj以及方法参数args传入其中即可。

DynamicProxy类似,在CGLibProxy中也添加一个泛型的getProxy方法,便于我们可以快速地获取自动生成的代理对象。下面用一个main方法来描述:

import org.light4j.proxy.dynamicProxy.CGLibProxy;
import org.light4j.proxy.impl.HelloImpl;

public class Main {
    public static void main(String[] args) {
        CGLibProxy cgLibProxy = new CGLibProxy();
        Hello helloProxy = cgLibProxy.getProxy(HelloImpl.class);

        helloProxy.say("longjiazuo");
    }
}

仍然通过两行代码就可以返回代理对象,与JDK动态代理不同的是,这里不需要任何的接口信息,对谁都可以生成动态代理对象(不管它是”矮穷挫”,还是”高富帅”)。

由于我一向都追求完美,用两行代码返回代理对象还是有些多余的,不想总是去new这个CGLibProxy对象,最好new一次,以后随时拿随时用,于是想到了”单例模式”:

import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

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

public class CGLibProxy implements MethodInterceptor {

    private static CGLibProxy instance = new CGLibProxy();

    private CGLibProxy(){
    }

    public static CGLibProxy getInstance(){
        return instance;
    }

    @SuppressWarnings("unchecked")
    public <T> T getProxy(Class<T> cls){
        return (T) Enhancer.create(cls, this);
    }

    @Override
    public Object intercept(Object obj, Method method, Object[] arg,
            MethodProxy proxy) throws Throwable {
        before();
        Object result = proxy.invokeSuper(obj, arg);
        after();
        return result;
    }

    private void before() {
        System.out.println("Before...");
    }

    private void after() {
        System.out.println("After...");
    }
}

加上了以上几行代码就解决问题了,需要说明的是,这里有一个private的构造方法,就是为了限制外界不能再去new它了,换句话说,这个类被”阉割”了。

下面用一个main方法来证明我的简单主义思想:

import org.light4j.proxy.dynamicProxy.CGLibProxy;
import org.light4j.proxy.impl.HelloImpl;

public class Main {
    public static void main(String[] args) {
        Hello helloProxy = CGLibProxy.getInstance().getProxy(HelloImpl.class);

        helloProxy.say("longjiazuo");
    }
}

没错,只需一行代码就可以获取代理对象了!
到此,通过三篇文章的分析,先后介绍了无代理,静态代理,JDK动态代理,CGLib动态代理,其实代理的世界远不止这么小,还有很多实际的应用场景。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值