cglib 底层源码分析

1. cglib 介绍

cglib是一个功能强大,高性能的代码生成包,它为没有实现接口的类提供代理,为JDK的动态代理提供了很好的补充。

1.1 cglib原理

  • 原理:动态生成一个要代理类的子类,子类重写要代理的类的所有不是final的方法。在子类中采用方法拦截的技术拦截所有父类方法的调用,顺势织入横切逻辑。它比使用java反射的JDK动态代理要快。
  • 底层:使用字节码处理框架ASM,来转换字节码并生成新的类。不鼓励直接使用ASM,因为它要求你必须对JVM内部结构包括class文件的格式和指令集都很熟悉。
  • 缺点:对于final方法,无法进行代理。

1.2 cglib的应用

广泛的被许多AOP的框架使用,例如Spring AOPdynaopHibernate使用CGLIB来代理单端single-ended(多对一和一对一)关联。

1.3 为什么使用cglib

CGLIB代理主要通过对字节码的操作,为对象引入间接级别,以控制对象的访问。我们知道Java中有一个动态代理也是做这个事情的,那我们为什么不直接使用Java动态代理,而要使用CGLIB呢?答案是CGLIB相比于JDK动态代理更加强大,JDK动态代理虽然简单易用,但是其有一个致命缺陷是,只能对接口进行代理。如果要代理的类为一个普通类、没有接口,那么Java动态代理就没法使用了

1.4 cglib 组成结构


CGLIB底层使用了ASM(一个短小精悍的字节码操作框架)来操作字节码生成新的类。除了CGLIB库外,脚本语言(如Groovy何BeanShell)也使用ASM生成字节码。ASM使用类似SAX的解析器来实现高性能。我们不鼓励直接使用ASM,因为它需要对Java字节码的格式足够的了解。

1.5 cglib的API

1、Jar包:

  • cglib-nodep-2.2.jar:使用nodep包不需要关联asm的jar包,jar包内部包含asm的类.
  • cglib-2.2.jar:使用此jar包需要关联asm的jar包,否则运行时报错.

2、CGLIB类库:

由于基本代码很少,学起来有一定的困难,主要是缺少文档和示例,这也是CGLIB的一个不足之处。

本系列使用的CGLIB版本是2.2。

  • net.sf.cglib.core: 底层字节码处理类,他们大部分与ASM有关系。
  • net.sf.cglib.transform: 编译期或运行期类和类文件的转换
  • net.sf.cglib.proxy: 实现创建代理和方法拦截器的类
  • net.sf.cglib.reflect: 实现快速反射和C#风格代理的类
  • net.sf.cglib.util: 集合排序等工具类
  • net.sf.cglib.beans: JavaBean相关的工具类

2. cglib使用

上面讲了一大段cglib的基本概念以及Api等,那么下面开始介绍通过MethodInterceptorEnhancer实现一个动态代理,看下cglib底层是如何实现动态代理的。

  1. 被代理类:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    public class TargetObject{
    public String method(){
    return "method";
    }
    public void voidMethod(){
    System.out.println("-----void-----");
    }

    public String method1(String name){
    return name;
    }
    }
  2. 定义一个拦截器,在调用目标方法时,cglib会回调MethodInterceptor接口方法拦截,来实现自己的代理逻辑,类似于JDK中的InvocationHandler接口

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    /**
    * 目标对象拦截器实现, 实现MethodInterceptor
    *
    * @author xiaoyuge
    */
    public class TargetInterceptor implements MethodInterceptor {
    /**
    * 重写方法拦截在方法前和方法后加入业务
    *
    * @param o 目标对象, 由cglib动态生成的代理类示例
    * @param method 目标方法,实体类所调用的被代理的方法引用
    * @param objects 参数值列表
    * @param methodProxy cglib方法代理对象
    * @return 结果
    * @throws Throwable 异常信息
    */
    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
    System.out.println("--------调用前-------");
    //调用代理类示例上的proxy 方法的弗雷方法(即实体类TargetObject中对应的方法)
    Object result = methodProxy.invokeSuper(o, objects);
    System.out.println("------调用后:" + result);
    return result;
    }
    }
  3. 生成动态代理类

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    import net.sf.cglib.proxy.Enhancer;

    public class TestCglib {
    public static void main(String[] args) {
    Enhancer enhancer = new Enhancer();
    enhancer.setSuperclass(TargetObject.class);
    enhancer.setCallback(new TargetInterceptor());

    TargetObject target = (TargetObject) enhancer.create();
    System.out.println(target);
    System.out.println(target.method1("xiaoyuge"));
    System.out.println(target.method());
    target.voidMethod();
    }
    }

    输出:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    org.example.TargetObject$$EnhancerByCGLIB$$8db9696e@5e91993f
    --------调用前-------
    ------调用后:xiaoyuge
    xiaoyuge
    --------调用前-------
    ------调用后:method
    --------调用前-------
    -----void-----
    ------调用后:null
    • Enhancer类:cglib中的一个字节码增强器,他可以方便的对你想要处理的类进行扩展。
    • 首先将被代理类设置为父类,然后设置拦截器TargetInterceptor,最后执行enhancer.create()动态生成一个代理类,并从Object强转为弗类型TargetObject,最后在代理类上调用方法
  1. 回调过滤器CallbackFilter
    在cglib回调时可以设置不同方法执行不同的回调逻辑,或者根本不执行回调,在JDK动态代理中并没有类似的功能,对InvocationHandler接口方法的调用对代理类内的所以方法都有效。
    定义实现过滤器CallbackFilter接口的类:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    import net.sf.cglib.proxy.CallbackFilter;

    import java.lang.reflect.Method;

    /**
    * 回调方法过滤器
    *
    * @author xiaoyuge
    */
    public class TargetMethodCallbackFilter implements CallbackFilter {

    /**
    * 过滤方法,
    * 返回的值为数字,代表类Callback数组中的索引位置
    *
    * @param method 方法
    * @return 结果
    */
    @Override
    public int accept(Method method) {
    if ("method1".equals(method.getName())) {
    System.out.println("filter method1 ==0");
    return 0;
    }
    if ("method".equals(method.getName())) {
    System.out.println("filter method1 ==1");
    return 1;
    }
    if ("voidMethod".equals(method.getName())) {
    System.out.println("filter method1 ==2");
    return 2;
    }
    return 0;
    }
    }
    其中return值为被代理类的各个方法在回调数组Callback[]中的位置
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    import net.sf.cglib.proxy.FixedValue;
    /**
    * 表示锁定方法返回值,无论被代理类的方法返回什么值,回调方法都返回固定值。
    * @author xiaoyuge
    *
    */
    public class TargetResultFixed implements FixedValue{

    /**
    * 该类实现FixedValue接口,同时锁定回调值为123
    * (整型,CallbackFilter中定义的使用FixedValue型回调的方法为getConcreteMethodFixedValue,该方法返回值为整型)。
    */
    @Override
    public Object loadObject() throws Exception {
    System.out.println("锁定结果");
    return 123;
    }

    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    import net.sf.cglib.proxy.Callback;
    import net.sf.cglib.proxy.CallbackFilter;
    import net.sf.cglib.proxy.Enhancer;
    import net.sf.cglib.proxy.NoOp;

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

    CallbackFilter callbackFilter = new TargetMethodCallbackFilter();
    //NoOp.INSTANC:表示no operator, 即什么操作也不做,代理类直接调用被代理的方法不进行拦截
    Callback noopCb = NoOp.INSTANCE;

    Callback callback = new TargetInterceptor();
    //FixedValue:表示锁定方法返回值,无论被代理类的方法返回什么值,回调方法都返回固定值。
    Callback fixedValue = new TargetResultFixed();

    Callback[] array = new Callback[]{callback, noopCb, fixedValue};
    enhancer.setCallbacks(array);
    enhancer.setCallbackFilter(callbackFilter);
    TargetObject targetObject = (TargetObject) enhancer.create();
    System.out.println(targetObject);
    System.out.println(targetObject.method());
    System.out.println(targetObject.method1("xiaoyuge"));
    targetObject.voidMethod();
    }
    }
    输出:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    filter method1 ==2
    filter method1 ==0
    filter method1 ==1
    --------调用前-------
    --------调用前-------
    ------调用后:359023572
    ------调用后:org.example.TargetObject$$EnhancerByCGLIB$$92522e49@156643d4
    org.example.TargetObject$$EnhancerByCGLIB$$92522e49@156643d4
    method
    --------调用前-------
    ------调用后:xiaoyuge
    xiaoyuge
    锁定结果
  2. 延迟加载对象

    LazyLoader接口实现了Callback,因此也算是cglib中的一种Callback类型

    另一种延迟加载接口Dispatcher,同样也继承于Callback,也是一种回调类型。

    两者的区别在于:LazyLoader只在第一次访问延迟加载属性时除法代理类的回调方法,而Dispatcher在每次访问延迟加载属性时都会触发代理类回调方法

    定义一个实体类LoaderBean,该bean内又一个需要延迟加载的属性PropertyBean
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    import net.sf.cglib.proxy.Enhancer;

    public class LazyBean {
    private String name;
    private int age;
    /**
    * 延迟加载属性
    */
    private PropertyBean propertyBean;
    private PropertyBean propertyBeanDispatcher;

    public LazyBean(String name, int age, PropertyBean propertyBean, PropertyBean propertyBeanDispatcher) {
    this.name = name;
    this.age = age;
    this.propertyBean = propertyBean;
    this.propertyBeanDispatcher = propertyBeanDispatcher;
    }

    /**
    * 只有第一次懒加载
    * 使用cglib进行懒加载,对需要延迟加载的对象添加代理,在获取该对象属性时先通过代理类回调方法进行对象初始化
    * 在不需要加载该对象时,只要不去获取该对象内属性,该对象就不会补初始化类(在cglib的实现中只要去访问该对象内属性的getter方法就会触发代理类回调)
    * @return 对象
    */
    private PropertyBean createPropertyBean() {
    Enhancer enhancer = new Enhancer();
    enhancer.setSuperclass(PropertyBean.class);
    return (PropertyBean) Enhancer.create(PropertyBean.class, new ConcreteClassLazyLoader());
    }

    /**
    * 每次都懒加载
    *
    * @return 对象
    */
    private PropertyBean createPropertyBeanDispatcher() {
    Enhancer enhancer = new Enhancer();
    enhancer.setSuperclass(PropertyBean.class);
    return (PropertyBean) Enhancer.create(PropertyBean.class,
    new ConcreteClassDispatcher());
    }

    public String getName() {
    return name;
    }

    public void setName(String name) {
    this.name = name;
    }

    public int getAge() {
    return age;
    }

    public void setAge(int age) {
    this.age = age;
    }

    public PropertyBean getPropertyBean() {
    return propertyBean;
    }

    public void setPropertyBean(PropertyBean propertyBean) {
    this.propertyBean = propertyBean;
    }

    public PropertyBean getPropertyBeanDispatcher() {
    return propertyBeanDispatcher;
    }

    public void setPropertyBeanDispatcher(PropertyBean propertyBeanDispatcher) {
    this.propertyBeanDispatcher = propertyBeanDispatcher;
    }

    @Override
    public String toString() {
    return "LazyBean{" +
    "name='" + name + '\'' +
    ", age=" + age +
    ", propertyBean=" + propertyBean +
    ", propertyBeanDispatcher=" + propertyBeanDispatcher +
    '}';
    }
    }
    延迟加载类 PropertyBean :
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    public class PropertyBean {
    private String key;
    private Object value;
    public String getKey() {
    return key;
    }
    public void setKey(String key) {
    this.key = key;
    }
    public Object getValue() {
    return value;
    }
    @Override
    public String toString() {
    return "PropertyBean{" +
    "key='" + key + '\'' +
    ", value=" + value +
    '}';
    }
    public void setValue(Object value) {
    this.value = value;
    }
    }
    延迟加载器:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    import net.sf.cglib.proxy.LazyLoader;

    /**
    * @author xiaoyuge
    */
    public class ConcreteClassLazyLoader implements LazyLoader {
    /**
    * 对于需要延迟加载的对象添加代理,在获取对象属性时先通过代理类回调方法进行对象初始化
    * 在不需要加载该对象时,只要不去获取该对象内属性,该对象就不会补初始化类(在cglib的实现中只要去访问该对象内属性的getter方法就会触发代理类回调)
    * @return 延迟加载对象
    * @throws Exception 异常信息
    */
    @Override
    public Object loadObject() throws Exception {
    System.out.println("before lazyLoader...");
    PropertyBean propertyBean = new PropertyBean();
    propertyBean.setKey("xiaoyuge");
    propertyBean.setValue(new TargetObject());
    System.out.println("after lazyLoader...");
    return propertyBean;
    }
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    /**
    * @author xiaoyuge
    */
    public class ConcreteClassDispatcher implements Dispatcher {
    @Override
    public Object loadObject() throws Exception {
    System.out.println("before Dispatcher...");
    PropertyBean propertyBean = new PropertyBean();
    propertyBean.setKey("nb");
    propertyBean.setValue(new TargetObject());
    System.out.println("after Dispatcher...");
    return propertyBean;
    }
    }
    测试方法:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    public class TestCglib2 {
    public static void main(String[] args) {
    LazyBean bean = new LazyBean("xiaoyuge", 18);
    //LazyLoader只在第一次访问延迟加载属性时触发代理类回调方法
    System.out.println("延迟加载" + bean.getPropertyBean().toString());
    System.out.println("延迟加载" + bean.getPropertyBean().toString());

    //Dispatcher在每次访问延迟加载属性时都会触发代理类回调方法。
    Object obj = bean.getPropertyBeanDispatcher().getValue();
    Object obj1 = bean.getPropertyBeanDispatcher().getValue();
    }
    }
    输出:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    before lazyLoader...
    after lazyLoader...
    before Dispatcher...
    after Dispatcher...
    延迟加载PropertyBean{key='xiaoyuge', value=org.example.TargetObject@45fe3ee3}
    延迟加载PropertyBean{key='xiaoyuge', value=org.example.TargetObject@45fe3ee3}
    before Dispatcher...
    after Dispatcher...
    before Dispatcher...
    after Dispatcher...
    从上面可以看出:Dispatcher在每次访问延迟加载属性时都会触发代理类回调方法,LazyLoader只在第一次访问延迟加载属性时触发代理类回调方法
  1. 接口生成器

    InterfaceMaker 会动态生成一个接口,该接口包含指定类的所有方法

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    import net.sf.cglib.proxy.Enhancer;
    import net.sf.cglib.proxy.InterfaceMaker;
    import net.sf.cglib.proxy.MethodInterceptor;
    import net.sf.cglib.proxy.MethodProxy;
    import org.junit.jupiter.api.Test;

    import java.lang.reflect.InvocationTargetException;
    import java.lang.reflect.Method;

    public class InterfaceMakerDemo {

    @Test
    public void test() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
    InterfaceMaker interfaceMaker = new InterfaceMaker();
    //抽取某个类的方法生成接口方法
    interfaceMaker.add(TargetObject.class);
    Class<?> targetInterface = interfaceMaker.create();

    for (Method method : targetInterface.getMethods()) {
    System.out.println(method.getName());
    }
    //接口代理并设置代理接口方法拦截
    Object object = Enhancer.create(Object.class, new Class[]{targetInterface}, new MethodInterceptor() {
    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
    if ("method".equals(method.getName())) {
    System.out.println("filter method");
    return "method";
    }
    if ("method1".equals(method.getName())) {
    System.out.println("filter method1");
    return "method1";
    }
    if ("voidMethod".equals(method.getName())) {
    System.out.println("filter voidMethod");
    return "filter voidMethod";
    }
    return "default";
    }
    });
    Method targetMethod = object.getClass().getMethod("method1", String.class);
    String value = (String) targetMethod.invoke(object, new Object[]{"xiaoyuge"});
    System.out.println("----"+value);
    Method targetMethod1 = object.getClass().getMethod("method");
    String value1 = (String) targetMethod1.invoke(object, new Object[] {});
    System.out.println("----"+value1);
    }
    }
    输出:
    1
    2
    3
    4
    5
    6
    7
    method1
    voidMethod
    method
    filter method1
    ----method1
    filter method
    ----method

3. 底层源码分析

上面讲了通过MethodInterceptorEnhancer实现一个动态代理,那么它的底层是如何实现的呢?

我们都知道,既然要生成一个代理对象,那么肯定需要一个代理类,只不过当我们使用cglib时,这个代理类是由cglib生成的,那么我们要看到这个代理类是怎么生成的,只需要在运行时加上:

1
-Dcglib.debugLocation=/Users/xiaoyuge/Desktop/classes

cglib就会将生成的代理类放到上面所指定的路径上。

先看原来的类:

1
2
3
4
5
public class TargetObject {
public String method() {
return "method";
}
}

测试方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
@Test
public static void testTargetObject(){
final TargetObject target = new TargetObject();
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(TargetObject.class);
enhancer.setCallbacks(new Callback[]{new MethodInterceptor() {
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
//test 方法增加了其他的逻辑
if ("method1".equals(method.getName())) {
System.out.println("------before------");
Object result = method.invoke(target, objects);
System.out.println("------after-------");
return result;
}
//其他方法正常执行
return method.invoke(target, objects);
}
}});
TargetObject t = (TargetObject) enhancer.create();
t.method();
}

cglib代理类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class TargetObject$$EnhancerByCGLIB$$8db9696e extends TargetObject implements Factory {
//............省略.........
final String CGLIB$method1$0(String var1) {
return super.method1(var1);
}
public final String method1(String var1) {
MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
if (var10000 == null) {
CGLIB$BIND_CALLBACKS(this);
var10000 = this.CGLIB$CALLBACK_0;
}
return var10000 != null ? (String)var10000.intercept(this, CGLIB$method1$0$Method, new Object[]{var1}, CGLIB$method1$0$Proxy) : super.method1(var1);
}
}

可以看到代理类继承了TargetObject,然后重写了TargetObject里面的方法,通过代理对象去调用,代理对象中包含了一个CGLIB$method1$0和一个method1方法。

method1方法内会调用所设置的Callbacks中的intercept(), 相当于执行增强逻辑,如果没有Callbacks,则会执行super.method1();
那么如果不设置Callbacks,是否能够正常执行,接着往下看

1
2
3
4
5
6
7
@Test
public void test(){
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(TargetObject.class);
TargetObject t = (TargetObject) enhancer.create();
t.method();
}

运行时,cglib在构造对象时就会报一个没有Callbacks的控制针异常。

1
2
3
4
5
6
7
8
java.lang.NullPointerException
trueat net.sf.cglib.proxy.CallbackInfo.determineTypes(CallbackInfo.java:39)
trueat net.sf.cglib.proxy.Enhancer.preValidate(Enhancer.java:350)
trueat net.sf.cglib.proxy.Enhancer.createHelper(Enhancer.java:471)
trueat net.sf.cglib.proxy.Enhancer.create(Enhancer.java:305)
trueat org.example.TestBitwise.test(TestBitwise.java:17)
trueat sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
true//.....

再来看代理类中的另一个方法:

1
2
3
final String CGLIB$method1$0(String var1) {
return super.method1(var1);
}

这个方法我们不能直接调用,要通过所设置的Callback,也就是MethodInterceptorMethodProxy对象来调用,MethodProxy对象表示方法代理。

假如TargetObject代理对象在执行method1方法,那么当执行流程进入到intercept()方法时,MethodProxy对象表示的就是method1()方法,但是我们现在知道了在TargetObject类和代理类都有method1方法,所以MethodProxy对象代理的就是这两个method1方法。

比如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// o 表示当前代理对象,  target表示被代理对象

//执行TargetObject代理对象的CGLIB$method1$0方法,也就是执行TargetObject代理对象的父类的method1方法
Object result1 = methodProxy.invokeSuper(o, objects);

//执行TargetObject代理对象的CGLIB$method1$0方法,会报错,调用invokeSuper只能传入代理对象
Object result2 = methodProxy.invokeSuper(target, objects);


//执行TargetObject对象method1方法
Object result3 = methodProxy.invoke(o, objects);

//执行TargetObject代理对象的method1方法,又会进入拦截器,栈溢出
Object result4 = methodProxy.invokeSuper(target, objects);

所以在执行methodProxy.invokeSuper()方法时,就会去执行CGLIB$method1$0()方法。

总结一下cglib的大概工作原理是:cglib会根据所设置的Superclass,生成代理类作为其子类,并且会重写Superclass中的方法,Superclass中的某一个方法,比如method1(),相应的在代理类中会对应两个方法,一个是重写的method1(),用来执行增强逻辑,一个是CGLIB$method1$0(),会直接调用super.test(),是让MethodProxy对象来用的。

4. 流程总结

  1. 首先生成代理对象。创建增强类Enhancer,设置代理类的父类,设置回调拦截方法,返回创建的代理对象;
  1. 调用代理类中的方法。这里调用的代理类中的方法实际上是重写的父类的拦截。重写的方法中会去调用intercept方法;
  1. 调用intercept,方法中会对调用代理方法中的invokeSuper方法。而在 invokeSuper 中维护了一个 FastClassInfo类,其包含四个属性字段:
    • FastClass f1(目标类)、
    • FastClass f2 (代理类)、
    • int i1(目标类要执行方法的下标)、
    • int i2(代理类要执行方法的下标);
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      private static class FastClassInfo {
      FastClass f1;
      FastClass f2;
      int i1;
      int i2;

      private FastClassInfo() {
      }
      }
      public Object invokeSuper(Object obj, Object[] args) throws Throwable {
      try {
      this.init();
      MethodProxy.FastClassInfo fci = this.fastClassInfo;
      return fci.f2.invoke(fci.i2, obj, args);
      } catch (InvocationTargetException var4) {
      throw var4.getTargetException();
      }
      }
    invokeSuper中会调用的为代理类中的对应方法(代理类继承于父类的时候,对于其父类的方法,自己会生成两个方法,一个是重写的方法,一个是代理生成的方法,这里调用的即是代理生成的方法);
  1. 调用代理类中的代理方法。代理方法中通过super.xxxx(string)来实际真正的调用要执行的方法;

5. JDK与cglib的区别

JDK动态代理

1
2
3
4
5
6
7
8
9
public static Object getProxy(Object proxyObj) {
return Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(),
proxyObj.getClass().getInterfaces(), new MyInvocationHandler(proxyObj));
}

public static void main(String[] args) {
UserDetailService service = (UserDetailService) getProxy(new UserDetailServiceImpl());
service.method1("xiaoyuge");
}

cglib动态代理

1
2
3
4
5
6
7
8
9
10
11
12
13
private static Enhancer enhancer = new Enhancer();
private static TargetInterceptor cglibProxy = new TargetInterceptor();

public static Object getProxy(Class cls) {
enhancer.setSuperclass(cls);
enhancer.setCallback(cglibProxy);
return enhancer.create();
}

public static void main(String[] args) throws InterruptedException {
TargetObject target = (TargetObject) getProxy(TargetObject.class);
target.method1("xiaoyuge");
}

个人理解两者的区别在于:JDK动态代理是基于委托思想,而CGLib动态代理是基于继承的思想!!!

  • 基于委托思想,JDK生成动态代理类的时候,需要传入被代理类(被委托类)的对象,可以看作是对象级别的重用机制
  • 基于继承思想,动态代理类继承了被代理类,理论上父类的所有开放方法对于子类都是可见的,可以看作是类级别的重用机制;

动态代理 = 拦截器机制 + 回溯到被代理类的能力

  • 对于JDK动态代理:

    JDK动态代理 = 拦截器机制(InvocationHandler) + 回溯到被代理类的能力(反射调用被代理类对象相关方法)

    在JDK动态代理中,生成的代理类的全限定类名是com.sun.proxy.$ProxyN(N是正整数,比如$Proxy0),它继承了com.sun.proxy类,该类中存在一个InvocationHandler类型的h成员变量,它就是拦截器。但这里会存在一个问题,由于我们希望代理类和被代理类在行为上是一致的(具有相同的类型),所以JDK动态代理需要引入接口的概念,代理对象和被代理对象需要具有相同的接口定义。

    所以,在我们使用JDK动态代理的过程中,我们需要自定义拦截器,实现InvocationHandler 接口,然后将被代理对象(被委托对象)注入到拦截器中。当调用接口方法时,会首先调用拦截器的invoke方法,拦截器invoke方法内部,会经过反射去调用被代理对象的相应方法。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    public class MyInvocationHandler implements InvocationHandler {
    private Object target;
    public MyInvocationHandler(Object target) {
    this.target = target;
    }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    //执行目标方法对象
    Object result = method.invoke(target, args);
    return result;
    }
    }
  • 对于CGLIB动态代理:

    CGLIB动态代理 = 拦截器机制(MethodInterceptor) + 回溯到被代理类的能力 (FastClass辅助类、MethodProxy类)

    在CGLIB动态代理中,生成的代理类的全限定类名是很自由的。因为它是基于继承机制,代理类继承了被代理类。 在生成的代理类中,会存在一个MethodInterceptor类型的CGLIB$CALLBACK_0成员变量,它就是拦截器。由于是继承,代理类天然就可以调用到父类(被代理类)的方法,因此这里不再需要注入被代理类的对象实例了。但这里仍然存在一个很核心的问题:代理类看起来,既要能够调用到拦截器,又要可以回溯到父类(被代理类)的原始方法,这看起来很矛盾。怎么解决呢?

    其实很简单,CGLIB生成的代理,对于被代理类的原有方法(比如上面的method1方法),会调用到拦截器。而与此同时,CGLIB还增加了隐藏的能够回溯到原始方法的传送门方法(比如CGLIB$method1$0)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    public class CglibProxy implements MethodInterceptor {   
    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
    //执行目标方法对象
    Object result = methodProxy.invokeSuper(o, objects);
    return result;
    }
    }

两者区别

  • JDK动态代理基于接口实现,必须先定义接口;

    CGLib动态代理基于被代理类实现,可以直接定义类或者实现接口的类;

  • JDK动态代理需要实现InvocationHanlder接口,加上反射机制实现代理类

    CGLib动态代理需要实现MethodInterceptor接口,对于代理类不可使用final修饰

  • JDK动态代理是委托机制,委托hanlder,生成新的委托类,调用实现类方法;

    CGLib动态代理则使用继承机制,被代理类和代理类是继承关系,直接调用其中方法;