设计模式之代理模式(下) CGLIB动态代理

Spring Wu 215 2018-03-14

CGLIB动态代理

  • CGLIB动态代理非常强大、性能还挺厉害(点这里查看JDK与CGLIB的性能对比(引用))。
  • 它的主要原理是:CGLIB通过字节码技术动态的生成业务类的子类,覆盖业务类的方法。并进行代理,因为采用的是继承方式,所以无法使用对final修饰的类进行代理。

光看原理肯定还是不是那么了解的,所以我们还是来写代码吧!

首先编写一个业务类

/**
 * 人员信息服务
 * @author wushuaiping
 * @date 2018/3/14 下午10:44
 */
public class EmployeeServiceImpl {
    public void insert(Employee employee){
        System.out.println("我调用了业务方法往数据库插入了一条数据~");
    }
}

再编写CGLIB动态代理的代码

  1. 首先需要去实现MethodInterceptor 方法拦截器。提供了intercept,方便在目标方法上进行切入。
  2. 再写一个获取代理对象的方法,该方法中需要使用到Enhancer,CGLIB通过该增强器底层的字节码技术生成业务类的子类。并创建该子类的对象。
    除了通过enhancer.create()通过无参构造器创建业务类代理对象以为还可以使用enhancer.create(Class[] argumentTypes, Object[] arguments)通过有参构造器来创建对象。具体方式请点击(引用)

/**
 *  CGLIB动态代理
 * @author wushuaiping
 * @date 2018/3/14 下午10:50
 */
public class CGLIBProxy implements MethodInterceptor{

    private Object target;

    public Object newInstance(Object object){
        this.target = object;
        // 增强器
        Enhancer enhancer = new Enhancer();
        /* 生成被代理业务类(EmployeeServiceImpl)的子类;
         * 就是因为这里继承的关系,被代理业务类就不能使用final修饰。
         */
        enhancer.setSuperclass(this.target.getClass());
        // 被代理业务类所有方法都会通过这里来调用
        enhancer.setCallback(this);
        // 创建代理对象 这个是创建无参构造器代理对象的方式
        return enhancer.create();
    }

    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        before();
        // 去调用父类中的方法
        methodProxy.invokeSuper(o, objects);
        after();
        return null;
    }

    private void before(){
        System.out.println("操作前的日志记录~~");
    }

    private void after(){
        System.out.println("操作后的日志记录~~");
    }
}

Test case

  1. 先后创建代理对象以及被代理的业务类对象
  2. 然后使用代理对象调用newInstance获取业务类代理类的对象。
  3. 调用业务类代理对象的业务方法
public static void main(String[] args) {
        CGLIBProxy proxy = new CGLIBProxy();
        EmployeeServiceImpl employeeService = new EmployeeServiceImpl();
        EmployeeServiceImpl proxySer = (EmployeeServiceImpl)proxy.newInstance(employeeService);
        proxySer.insert(new Employee());
    }

运行结果

操作前的日志记录~~
我调用了业务方法往数据库插入了一条数据~
操作后的日志记录~~

来讲讲优缺点吧:

  • CGLIB的功能还是蛮强大的,可以不用实现接口也可进行动态代理。但是缺点也很明显,因为底层通过继承业务类的方式来进行代理,所以业务类不能使用final修饰。

# 设计模式