手记

Cglib方法实现动态代理

前言:在看了《模式的秘密---代理模式》的教学视频后,发现了cglib也能产生动态代理,但老师只是做介绍演示,没有过多深入的讲解原理,所以在老师视频讲解的基础上,加上一些我学习cglib实现动态代理的心得。

除了使用JDK方式产生动态代理外,Java还给我们提供了另外一种产生动态代理的方法,那就是使用cglib。

cglib是这样实现动态代理的:

  • ①.针对类来实现代理
  • ②对指定目标类产生一个子类 ,通过方法拦截技术拦截所有父类方法的调用。

cglib的实现机制与Java 动态代理不同,它是通过继承实现的 ,它也是动态创建了一个类,但这个类的父类是被代理的类,代理类重写了父类的所有public非final方法,改为调用Callback中的相关方法,在本例中,调用CglibProxy的intercept方法。

具体实现步骤如下:

1.我们先新建一个普通的Java项目,然后,在使用这个方法之前,我们需要给项目导入所需的jar包。

cglib-nodep-2.2.jar

2.建立被代理类

package cglibProxy;

public class Person {

    public void work(){
        System.out.println("工作中..");
    }
}

简单起见,我们这里只给Person类实现一个work()方法,用于模拟业务实现。

3.接下来就是最重要的一点,建立代理类,代理类需要实现以下接口:

 interface MethodInterceptor{}

这个接口需要我们导入jar包后才会出现,顾名思义,也就是方法拦截器。
代理类的实现细节如下:

package cglibProxy;

import java.lang.reflect.Method;

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

public class CglibProxy implements MethodInterceptor {

    private Enhancer enhancer = new Enhancer();

    public Object getProxy(Class clazz){
        //设置创建子类的类,即指定为哪个类产生代理类
        enhancer.setSuperclass(clazz);

        /*设置回调函数
         * setCallback设置被代理类的public非final方法被调用时的处理类
         * 这个例子中我们设置的方法为Person中的work()方法
         * 当work()方法被调用时,由该类进行处理
         * */
        enhancer.setCallback(this);
        //创建子类实例
        return enhancer.create();
    }

    /*
     * 作用:拦截所有目标类方法的调用
     * 参数:
     *      1. obj   -->目标类的实例对象
     *      2. method-->目标方法的反射对象
     *      3. args  -->方法的参数
     *      4. proxy -->代理类的实例对象
     * */
    @Override
    public Object intercept(Object obj, Method method, Object[] args,
            MethodProxy proxy) throws Throwable {

        System.out.println("代理类开始介入..");
        //代理类调用父类的方法
        proxy.invokeSuper(obj, args);
        System.out.println("代理类介入结束");
        return null;
    }

}

这里出现了一个比较少见的类Enhancer,查阅官方API,有这么一段注解:

/*Generates dynamic subclasses to enable method interception.
 This class started as a substitute for the standard Dynamic Proxy 
 support included with JDK 1.3, but one that allowed the proxies 
interfaces. The dynamically generated subclasses override 
the non-final methods of the superclass and have hooks which 
callback to user-defined interceptor implementations.*/

翻译过来大概意思就是:

/*生成动态子类以启用方法拦截。
这个类开始替代了JDK 1.3中包含的标准动态代理支持,
但是允许代理扩展一个具体的基类,以及实现接口。
动态生成的子类覆盖超类的非最终方法,
并具有回调到用户定义的拦截器实现的钩子。*/

其实Enhancer类是CGLib中的一个字节码增强器,它可以方便的对你想要处理的类进行扩展。
我们通过在代理类中聚合一个Enhancer类的一个实例对象,然后调用Enhancer实例对象的相应方法,对父类的调用方法进行拦截。

代理类返回代理对象由getProxy()方法实现,其中:


enhancer.setSuperclass(clazz);
/*官方API对该类的注解如下:
*Set the class which the generated class will extend.
*翻译:
*设置生成的类将要继承的类
*这样比较难懂,从方法名中我们可以看出,这其实就是设置代理类的父类
*/

与JDK动态代理不同,CglibProxy中没有被代理的对象,它通过MethodProxy类的实例对象proxy的invokeSuper方法调用被代理类的方法:

proxy.invokeSuper(obj, args);

但是,要注意的是,它不能这样调用被代理类的方法:

proxy.invoke(obj, args);

因为proxy是代理对象,调用这个方法还会调用到CglibProxy的intercept方法,造成死循环。

3.最后,我们建立测试类

package cglibProxy;

public class Test {

    public static void main(String[] args) {

        //在main方法中,没有创建被代理的对象,创建的对象直接就是代理对象。
        CglibProxy proxy = new CglibProxy();
        //getProxy()方法返回代理方法产生的实例对象
        Person person = (Person)proxy.getProxy(Person.class);
        //代理对象调用wokr()方法
        person.work();
    }

}

运行结果:

代理类开始介入..
工作中..
代理类介入结束

动态代理是实现面向切面的编程(AOP – Aspect Oriented Programming)的基础,所以,了解动态代理的实现方法和机制是很有必要的,通过一个简单的实例,可以对动态代理有初步的认识,为以后的深入学习打下基础。
注:个人博客上也有发布。

3人推荐
随时随地看视频
慕课网APP