使用CGLIB动态代理

wangjianme 13年前

11、使用CGLIB动态代理

    Cglib是一个优秀的动态代理框架,它的底层使用ASM在内存中动态的生成被代理类的子类。使用CGLIB即使被代理类没有实现任何接口也可以实现动态代理功能。CGLIB具有简单易用,它的运行速度要远远快于JDKProxy动态代理:

使用CGLIB需要导入以下两个jar文件:

    asm.jar – CGLIB的底层实现。

    cglib.jar – CGLIB的核心jar包。

CGLIB的核心类:

    net.sf.cglib.proxy.Enhancer – 主要的增强类

net.sf.cglib.proxy.MethodInterceptor – 主要的方法拦截类,它是Callback接口的子接口,需要用户实现

net.sf.cglib.proxy.MethodProxy – JDKjava.lang.reflect.Method类的代理类,可以方便的实现对源对象方法的调用,如使用:

    Object o = methodProxy.invokeSuper(proxy, args);//虽然第一个参数是被代理对象,也不会出现死循环的问题。

费话少说,上代码:

1、使用CGLIB的代理:

以下测试代理一个没有实现任何接口的Person类:

    @Test

    public void testProxy1() throws Exception {

       final Person p1 = new Person();             //Person类没有实现任何接口

       Enhancer en = new Enhancer();               //声明增加类实例

       en.setSuperclass(Person.class);             //设置被代理类字节码,CGLIB根据字节码生成被代理类的子类

       en.setCallback(new MethodInterceptor() {    //设置回调函数,即一个方法拦截

           public Object intercept(Object target, Method method,

                  Object[] args, MethodProxy proxy) throws Throwable {

              Object o = method.invoke(p1,args);    //注意参数p1,仍然为外部声明的源对象,且MethodJDKMethod反射

              System.err.println("After...");

              return o;

           }

       });

       Person p = (Person) en.create();             //通过create方法返回Person类的代理

       System.err.println(p.getClass());//被代理的对象

       p.sayHi("Hello");

    }

2、以下测试代理一个拥有接口的类:

IAnimal是接口,Dog是实现类,具体代码如下:

    @Test

    public void testProxy2() throws Exception {

       final Dog dog = new Dog();             //声明被代理对象

       Enhancer en = new Enhancer();          //声明CGLIB增强类

       en.setSuperclass(IAnimal.class);       //设置接口类,也可以设置成dog实现类,会影响create返回的对象

       en.setCallback(new MethodInterceptor() {

           public Object intercept(Object target, Method method,

                  Object[] args, MethodProxy proxy) throws Throwable {

              System.err.println("Before...");

              Object o = method.invoke(dog, args);

              System.err.println("After...");

              return o;

           }

       });

       //Dog dog2 = (Dog) en.create();//必须转型为接口,否则抛出ClassCastException

       IAnimal dog2 = (IAnimal)en.create();

       dog2.eat();

    }

说明:

由于上例中,设置了en.setSuperclass(IAnimal.class),所以en.create()方法,返回的对象,必须要转换成IAnimal接口。如果转换成Dog则会抛出ClassCastException

3、将CGLIB再做一个简单的包装:

 

class CglibProxy implements MethodInterceptor{

    private Object srcTarget;

    private CglibProxy(Object o){

       this.srcTarget = o;

    }

    @SuppressWarnings("unchecked")

    public static <T>T proxyTarget(T t){

       Enhancer en = new Enhancer();

       en.setSuperclass(t.getClass());

       en.setCallback(new CglibProxy(t));

       T tt = (T) en.create();

       return tt;

    }

    @Override

    public Object intercept(Object obj, Method method, Object[] args,

           MethodProxy proxy) throws Throwable {

       System.err.println("拦截前...");

       Object o = method.invoke(srcTarget, args);

       System.err.println("拦截后....");

       return o;

    }

}

包装以后的调用代码如下,主要是快速的实现获取被代理类:

        Person p = CglibProxy.proxyTarget(new Person());

       p.sayHi("HJello");

       IAnimal dog = CglibProxy.proxyTarget(new Dog());

       dog.eat();

4、使用静态方法代理一个没有接口的对象

以下代码,包含在一个测试方法或是main方法中运行:

       final Person src = new Person();

        //直接使用静态方法代理一个对象

       Person p = (Person) Enhancer.create(Person.class,new MethodInterceptor(){

           public Object intercept(Object proxyedObj, Method method, Object[] args,

                  MethodProxy proxy) throws Throwable {

              System.err.println("Hello");

              //使用原生的方法调用,注意里面的src

              //Object oo = method.invoke(src, args);

              //使用MethodProxy调用父类的代码,同样有效

              Object oo = proxy.invokeSuper(proxyedObj, args);

              return oo;

           }

       });

       System.err.println(p.getClass());

       p.abc();