JDK和CGLIB生成动态代理类的区别

 关于动态代理和静态代理

当一个对象(客户端)不能或者不想直接引用另外一个对象(目标对象),这时能够应用代理模式在这二者之间构建一个桥梁--代理对象。java

按照代理对象的建立时期不一样,能够分为两种:spring

静态代理:事先写好代理对象类,在程序发布前就已经存在了;编程

动态代理:应用程序发布后,经过动态建立代理对象。this

静态代理其实就是一个典型的代理模式实现,在代理类中包装一个被代理对象,而后影响被代理对象的行为,比较简单,代码就不放了。spa

其中动态代理又可分为:JDK动态代理和CGLIB代理。代理

1.JDK动态代理

此时代理对象和目标对象实现了相同的接口,目标对象做为代理对象的一个属性,具体接口实现中,能够在调用目标对象相应方法先后加上其余业务处理逻辑。code

代理模式在实际使用时须要指定具体的目标对象,若是为每一个类都添加一个代理类的话,会致使类不少,同时若是不知道具体类的话,怎样实现代理模式呢?这就引出动态代理。对象

JDK动态代理只能针对实现了接口的类生成代理。继承

2.CGLIB代理

CGLIB(CODE GENERLIZE LIBRARY)代理是针对类实现代理,接口

主要是对指定的类生成一个子类,覆盖其中的全部方法,因此该类或方法不能声明称final的。

JDK动态代理和CGLIB代理生成的区别

JDK动态代理只能对实现了接口的类生成代理,而不能针对类 。
CGLIB是针对类实现代理,主要是对指定的类生成一个子类,覆盖其中的方法 。
由于是继承,因此该类或方法最好不要声明成final ,final能够阻止继承和多态。

PS:final 所修饰的数据具备“终态”的特征,表示“最终的”意思:

  • final 修饰的类不能被继承。
  • final 修饰的方法不能被子类重写。
  • final 修饰的变量(成员变量或局部变量)即成为常量,只能赋值一次。
  • final 修饰的成员变量必须在声明的同时赋值,若是在声明的时候没有赋值,那么只有 一次赋值的机会,并且只能在构造方法中显式赋值,而后才能使用。
  • final 修饰的局部变量能够只声明不赋值,而后再进行一次性的赋值。

参考代码

CGLIB: 

public Object createProxyObject(Object obj) { 

    this.targetObject = obj; 

    Enhancer enhancer = new Enhancer(); 

    enhancer.setSuperclass(obj.getClass()); 

    enhancer.setCallback(this); 

    Object proxyObj = enhancer.create(); 

    return proxyObj;// 返回代理对象,返回的对象其实就是一个封装了“实现类”的代理类,是实现类的实例。 

JDK: 

1

2

3

4

5

public Object newProxy(Object targetObject) {// 将目标对象传入进行代理 

    this.targetObject = targetObject;  <br>    //注意这个方法的参数,后面是类实现的接口

    return Proxy.newProxyInstance(targetObject.getClass().getClassLoader(), 

            targetObject.getClass().getInterfaces(), this);// 返回代理对象 

}

在代码中能够看到,在生成代理类时,传递的是实现类所实现的接口 targetObject.getClass().getInterfaces(),因此JDK只能对于接口进行作代理。若是换成类的话,则会抛java.lang.ClassCastException异常。 

在Spring的源码中,能够看到不少生成代理类的代码。

 

动态代理的应用

AOP(Aspect-OrientedProgramming,面向切面编程),AOP包括切面(aspect)、通知(advice)、链接点(joinpoint),实现方式就是经过对目标对象的代理在链接点先后加入通知,完成统一的切面操做。

实现AOP的技术,主要分为两大类:

一是采用动态代理技术,利用截取消息的方式,对该消息进行装饰,以取代原有对象行为的执行;

二是采用静态织入的方式,引入特定的语法建立“方面”,从而使得编译器能够在编译期间织入有关“方面”的代码。

Spring提供了两种方式来生成代理对象: JDKProxy和Cglib,具体使用哪一种方式生成由AopProxyFactory根据AdvisedSupport对象的配置来决定。

默认的策略是若是目标类是接口,则使用JDK动态代理技术,若是目标对象没有实现接口,则默认会采用CGLIB代理。

若是目标对象实现了接口,能够强制使用CGLIB实现代理(添加CGLIB库,并在spring配置中加入<aop:aspectj-autoproxy proxy-target-class="true"/>

相关文章
相关标签/搜索