如果要使用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