cglib的简单使用

一、前言

最近在看Spring的源码,其中有牵扯到cglib的相关内容,遂简单记录下cglib是如何使用的

二、原理(节选自网络)

CGLIB原理:动态生成一个要代理类的子类,子类重写要代理的类的所有不是final的方法。在子类中采用方法拦截的技术拦截所有父类方法的调用,顺势织入横切逻辑。它比使用java反射的JDK动态代理要快。

CGLIB底层:使用字节码处理框架ASM,来转换字节码并生成新的类。不鼓励直接使用ASM,因为它要求你必须对JVM内部结构包括class文件的格式和指令集都很熟悉。

CGLIB缺点:对于final方法,无法进行代理。

三、一个核心类:Enhancer

Enhancer是CGLib的字节码增强器,可以方便的对非final类进行扩展,它动态创建了给定类型的子类但是拦截了所有非final的方法。

3.1、简单使用Enhancer

如何简单的使用Enhancer:,看下面的几个方法:

//设置需要代理的类
public void setSuperclass(Class superclass);
//设置一个Callback
public void setCallback(Callback callback);

Callback可以理解为我们需要对原始类方法做的增强处理。

看下面的一段代码:

public class CglibTest4 {

    public static void main(String[] args) {

        Enhancer enhancer = new Enhancer();

        enhancer.setSuperclass(QService.class);

        enhancer.setCallback(new MethodInterceptor() {
            @Override
            public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
                System.out.println("my callback");
                methodProxy.invokeSuper(o,objects);
                return o;
            }
        });

        QService service = (QService) enhancer.create();

        System.out.println("test1 方法~~~~~~~~~~~~~~");
        service.test1();

        System.out.println("test2 方法~~~~~~~~~~~~~~");
        service.test2();

        System.out.println("getClass 方法~~~~~~~~~~~~~~");
        service.getClass();

        System.out.println("hashCode 方法~~~~~~~~~~~~~~~");
        service.hashCode();


    }
}

class QService {

    public void test1() {
        System.out.println("test1");
    }

    public void test2() {
        System.out.println("test2");
    }
}

结果:
在这里插入图片描述
注意:
Enhancer 生成的代理类拦截了所有非final的方法(上面的例子中,拦截了test1方法、test2方法、hashCode方法,却未拦截getClass方法)

3.2、只拦截部分方法

Enhancer会拦截原始类的所有非final方法,但是我们通常情况下只需要对部分方法(例如业务方法)进行一些增强。这个时候可以给Enhancer设置CallbackFilter。
还是用上面的例子,这次我们只对test1方法和test2方法进行增强。

public class CglibTest4 {

    public static void main(String[] args) {

        Enhancer enhancer = new Enhancer();

        enhancer.setSuperclass(QService.class);

        Callback[] callbacks = new Callback[2];

        callbacks[0] = NoOp.INSTANCE;

        callbacks[1] = (MethodInterceptor) (o, method, objects, methodProxy) -> {
            System.out.println("my callback");
            methodProxy.invokeSuper(o,objects);
            return o;
        };

        enhancer.setCallbackFilter(method -> {
            if (method.getName().equals("test1") || method.getName().equals("test2")){
                return 1;
            }else {
                return 0;
            }
        });

        enhancer.setCallbacks(callbacks);

        QService service = (QService) enhancer.create();

        System.out.println("调用test1 方法~~~~~~~~~~~~~~");
        service.test1();
        System.out.println("");

        System.out.println("调用test2 方法~~~~~~~~~~~~~~");
        service.test2();
        System.out.println("");

        System.out.println("调用getClass 方法~~~~~~~~~~~~~~");
        service.getClass();
        System.out.println("");

        System.out.println("调用hashCode 方法~~~~~~~~~~~~~~~");
        service.hashCode();


    }
}

class QService {

    public void test1() {
        System.out.println("test1");
    }

    public void test2() {
        System.out.println("test2");
    }
}

结果:
在这里插入图片描述
注意以下几点:
1、设置了两个Callback
2、设置了一个CallbackFilter

Enhancer支持设置多个Callback,进行多种不同方式的增强,而CallbackFilter的作用就是帮助代理类找到某个方法需要的Callback。上面的例子中,第一个Callback什么也不会做,而第二个Callback则会针对test1方法和test2方法做一些增强。CallbackFilter是如何为方法匹配所需的Callback呢?是通过CallbackFilter的 int accept(Method var1)方法的返回值确定的,这个返回值对应Callback[]中的下标。

四、几种Callback

4.1、MethodInterceptor

MethodInterceptor,这是一个功能很强大的接口,它可以实现类似于AOP编程中的环绕增强(around-advice)。

第一次使用:

public class CglibTest {

    public static void main(String[] args){
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(MyService.class);

        Callback[] callbacks = new Callback[3];

        callbacks[0] = new MethodInterceptor() {
            @Override
            public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
                System.out.println("default callback");
                methodProxy.invoke(o,objects);
                return o;
            }
        };

        callbacks[1] = new MethodInterceptor() {
            @Override
            public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
                System.out.println("callback1");
                methodProxy.invoke(o,objects);
                return o;
            }
        };

        callbacks[2] = new MethodInterceptor() {
            @Override
            public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
                System.out.println("callback2");
                methodProxy.invoke(o,objects);
                return o;
            }
        };

        enhancer.setCallbacks(callbacks);

        enhancer.setCallbackFilter(new CallbackFilter() {
            @Override
            public int accept(Method method) {
                if(method.getName().equals("method1")){
                   return 1;
                }else if(method.getName().equals("method2")){
                    return 2;
                }
                return 0;
            }
        });

        MyService myService = (MyService) enhancer.create();

        myService.method1();

        myService.method2();
    }

}

class MyService {

    public void method1() {
        System.out.println("method1 execute");
    }

    public void method2() {
        System.out.println("method2 execute");
    }
}

本意是创建三个callback,method1用callback[1]来增强,method2用callback[2]来增强,但是却出现了这样的结果:
在这里插入图片描述
原因是出现了循环调用:callback1()->intercept()->callback1()->intercept()->… 最后导致栈溢出
后来修改成使用invokeSuper()正常运行:

public class CglibTest {

    public static void main(String[] args){
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(MyService.class);

        Callback[] callbacks = new Callback[3];

        callbacks[0] = new MethodInterceptor() {
            @Override
            public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
                System.out.println("default callback");
                methodProxy.invokeSuper(o,objects);
                return o;
            }
        };

        callbacks[1] = new MethodInterceptor() {
            @Override
            public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
                System.out.println("callback1");
                methodProxy.invokeSuper(o,objects);
                return o;
            }
        };

        callbacks[2] = new MethodInterceptor() {
            @Override
            public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
                System.out.println("callback2");
                methodProxy.invokeSuper(o,objects);
                return o;
            }
        };

        enhancer.setCallbacks(callbacks);

        enhancer.setCallbackFilter(new CallbackFilter() {
            @Override
            public int accept(Method method) {
                if(method.getName().equals("method1")){
                   return 1;
                }else if(method.getName().equals("method2")){
                    return 2;
                }
                return 0;
            }
        });

        MyService myService = (MyService) enhancer.create();

        myService.method1();

        myService.method2();
    }

}

class MyService {

    public void method1() {
        System.out.println("method1 execute");
    }

    public void method2() {
        System.out.println("method2 execute");
    }
}

注意:MethodInterceptor的实现方法中应该调用invokeSuper方法,避免出现循环调用

4.2、FixedValue

使用FixedValue可以很容易的替换掉方法的返回值。

public class CglibTest2 {

    public static void main(String[] args) {
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(MService.class);

        enhancer.setCallback(new FixedValue() {
            @Override
            public Object loadObject() throws Exception {
                return "new method1";
            }
        });

        MService mService = (MService) enhancer.create();
        System.out.println(mService.method1());
    }
}

class MService {

    public String method1() {
        return "method1";
    }

}

结果:
在这里插入图片描述

4.3、NoOp

啥都不干,只是调用原来的方法

public class CglibTest2 {

    public static void main(String[] args) {
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(MService.class);

        enhancer.setCallback(NoOp.INSTANCE);

        MService mService = (MService) enhancer.create();
        System.out.println(mService.method1());
    }
}

class MService {

    public String method1() {
        return "method1";
    }

}

在这里插入图片描述

4.4、LazyLoader

它提供了一个方法:Object loadObject() throws Exception;,loadObject()方法会在第一次被代理类的方法调用时触发,它返回一个代理类的对象,这个对象会被存储起来然后负责所有被代理类方法的调用,就像它的名字说的那样,一种lazy模式。如果被代理类或者代理类的对象的创建比较麻烦,而且不确定它是否会被使用,那么可以选择使用这种lazy模式来延迟生成代理。

public class CglibTest3 {

    public static void main(String[] args) {
        Enhancer enhancer = new Enhancer();

        enhancer.setSuperclass(Person.class);

        enhancer.setCallback((LazyLoader) () -> {
            try{
                System.out.println(" before lazyloader");
                return new Person("lg");
            }finally {
                System.out.println(" after lazyloader");

            }
        });

        Person person = (Person) enhancer.create();

        System.out.println(person.getName());
        System.out.println(person.getName());
        System.out.println(person.getName());


    }

}


class Person {

    private String name;

    public Person(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public Person(){

    }
}

结果:
在这里插入图片描述
如果把下面的代码注掉,则Person不会实例化:

       //System.out.println(person.getName());
        //System.out.println(person.getName());
        //System.out.println(person.getName());

结果:
在这里插入图片描述

4.5、Dispatcher

Dispatcher和LazyLoader接口相同,也是提供了loadObject()方法,这个方法同样地返回一个代理对象,这个对象同样可以代理原方法的调用。不过它们之间不同的地方在于,Dispatcher的loadObject()方法在每次发生对原方法的调用时都会被调用并返回一个代理对象来调用原方法。也就是说Dispatcher的loadObject()方法返回的对象并不会被存储起来,可以类比成Spring中的Prototype类型,而LazyLoader则是lazy模式的Singleton。

public class CglibTest3 {

    public static void main(String[] args) {
        Enhancer enhancer = new Enhancer();

        enhancer.setSuperclass(Person.class);

        enhancer.setCallback((Dispatcher) () -> {
            try{
                System.out.println(" before lazyloader");
                return new Person("lg");
            }finally {
                System.out.println(" after lazyloader");

            }
        });

        Person person = (Person) enhancer.create();

        System.out.println(person);
        System.out.println(person);


    }

}


class Person {

    private String name;

    public Person(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public Person(){

    }
}

结果:
在这里插入图片描述
即,通过Dispatcher生成的对象,每次调用的时候,代理都会重新再执行一次loadObject方法

参考

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章