设计模式(四):代理模式(下)-CGLIB动态代理(CGLIBDynamicProxy)

star2017 1年前 ⋅ 295 阅读

基于静态代理和动态代理需要绑定接口的局限性,而对类的代理在某些场景下确实是需要的,所以某些大牛就创造了CGLIB这个动态代理类库。

CGLIB底层是基本ASM字节码处理框架,该库允许在程运行时对字节码进行修改和动态生成新的类。

CGLIB所创建的动态代理对象的性能比JDK所创建的动态代理对象的性能高(大概10倍),但CGLIB在创建代理对象时所花费的时间却比JDK动态代理多(大概8倍)。

对于singleton的代理对象或者具有实例池的代理,因无须频繁创建对象,比较适用CGLIB动态代理技术;反之则适合采用JDK动态代理技术。

CGLIB

  CGLIB 生成的动态代理,是在运行期间通过 Java 的反射机制,生成被代理目标类的子类,同时实现了net.sf.cglib.proxy.Factory接口,这个接口是CGLIB自己加入的。

  CGLIB 是通过继承实现代理,所以被代理的目标类不能被final关键字修饰,因为final修饰的父类是不能被继承的;目标类的方法不能被final,static,private修饰, final,static的方法不能被重载,否则就不会被拦截, private修饰不能被外部调用。

  CGLIB 的核心是MethodInterceptor接口,目标对象的所有方法都会转给MethodInterceptor.intercept()方法来执行,该方法会拦截所有父类方法的调用,同时织入横切逻辑(在该方法里写增强的功能,如加入日志、安全检查等)。

使用步骤

  1. 业务类
  2. 创建MethodInterceptor接口的实现类(我称之为CGLIB工厂类),将目标类对象传入该工厂类的构造方法,新建一个创建代理对象的方法,重写intercept方法,在该方法编写增强功能。
  3. 外部调用时生成CGLIB工厂类的对象,在构造方法里传入被代理的目标类对象,在工厂类对象调用方法创建代理对象并返回。
  4. 代理对象调用目标类的方法。

intercept方法

intercept(Object obj, Method method, Object[] paramArr, MethodProxy methodProxy)方法解析

  1. Object obj:第一个参数表示目标类对象。
  2. Method method:第二个参数为目标为的反射对象。
  3. Object[] objArr:第三个参数为方法的参动入参。
  4. MethodProxy methodProxy:第四个参数为代理类对象。

示例代码

  1. 业务类
/**
 * 不需要实现接口的业务类
 *
 */
public class UserService {

    public void queryInfo(int id) {
        System.out.println("根据ID查询信息。。。 " + id);
    }

    public final void updateInfo(int id, String name) {
        System.out.println("根据ID和名称更新信息 。。。" + id);
    }
}
  1. CGLIB拦截类
public class CglibInterceptor implements MethodInterceptor {
    //被代理的目标类
    private Object target;
    public CglibInterceptor(Object target) {
        this.target = target;
    }

    //创建代理对象
    public Object getInstance() {
        Enhancer enhancer = new Enhancer();
        //指定需要创建子类的父类
        enhancer.setSuperclass(target.getClass());
        //回调方法
        enhancer.setCallback(this);
        //创建代理对象
        return enhancer.create();
    }

    @Override
    public Object intercept(Object obj, Method method, Object[] paramArr, MethodProxy methodProxy) throws Throwable {
        System.out.println("transaction begin...");
        //执行方法,调的是父类的方法,代理对象是目标对象的子类
        methodProxy.invokeSuper(obj, paramArr);
        System.out.println("transaction end...");
        return null;
    }
}
  1. 外部调用CGLIB业务类
public class CGLIBMain {

    public static void main(String[] args) {
        //创建目标类对象
        UserService userServiceImpl = new UserService();
        //自定拦截
        CglibInterceptor customizeMethodInterceptor = 
                new CglibInterceptor(userServiceImpl);
        UserService instance = (UserService) customizeMethodInterceptor.getInstance();
        instance.queryInfo(11);
    }
}

参考
动态代理之Cglib浅析
ImportNew CGLIB专题

更多内容请访问:IT源点

相关文章推荐

全部评论: 0

    我有话说: