May 14 2009

Spring如何选择使用CGLIB还是JDK作为Proxy

Category: 技术ssmax @ 10:11:37

如果要使用Spring的aop特性,类就必须转换为Proxy,让Spring去管理切入点,jdk和cglib的性能差别不大,但是各有自己的限制:

JDK dynamic proxies:

  • The class has to implement interfaces. Otherwise you will get ClassCastExceptions saying that $Proxy0 can not be casted to the particular class.
  • Eventually dynamic proxies force you to program to interfaces since you can not cast the proxy to the class – a feature I really like about them.

 

CGLib proxies:

  • The proxies are created by sub-classing the actual class. This means wherever an instance of the class is used it is also possible to use the CGLib proxy.
  • The class needs to provide a default constructor, i.e. without any arguments. Otherwise you’ll get an IllegalArgumentException: “Superclass has no null constructors but no arguments were given.” This makes constructor injection impossible.
  • The proxying does not work with final methods since the proxy sub class can not override the class’ implementation.
  • The CGLib proxy is final, so proxying a proxy does not work. You will get an IllegalArgumentException saying “Cannot subclass final class $Proxy0”. But this feature is usually not needed anyway. (This issue might be solved in the future.)
  • Since two objects are created (the instance of the class and the proxy as instance of a sub class) the constructor is called twice. In general this should not matter. I consider changing the class’ state based on constructor calls a code smell anyway.
  • You have CGLib as additional dependency.

如果你的类继承了某个父类,或者实现了某个接口,因为Spring没有办法判断这个是jdk自带的接口,还是你自己实现的接口,所以Spring就默认使用jdk proxy了,这样子类必须要实现了一个接口,然后用这个接口来调用该类,某则就会报:

$Proxy0 cannot be cast to xxx

之类的错误,但是也可以通过强制指定使用cglib,用下面的语句:

<bean id=”userPreferences” class=”com.foo.DefaultUserPreferences” scope=”session”>
    <aop:scoped-proxy proxy-target-class=”true” />
</bean>

这样子就可以强制使用cglib,也可以直接cast该类了,当然这不是一种好习惯,实现自己的接口在测试和替换的时候毕竟比较灵活。

Leave a Reply