JDK与CGLIB选择性
Spring Aop部分使用JDK动态代理或者CGLIB来为目标实现创建代理那么什么时候使用JDK,什么时候使用CGLIB?
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {
Class targetClass = config.getTargetClass();
if (targetClass == null) {
throw new AopConfigException("TargetSource cannot determine target class: " +
"Either an interface or a target is required for proxy creation.");
}
if (targetClass.isInterface()) {
return new JdkDynamicAopProxy(config);
}
if (!cglibAvailable) {
throw new AopConfigException(
"Cannot proxy target class because CGLIB2 is not available. " +
"Add CGLIB to the class path or specify proxy interfaces.");
}
return CglibProxyFactory.createCglibProxy(config);
}
else {
return new JdkDynamicAopProxy(config);
}
}
- 如果代理目标对象实现了至少一个接口,则会默认使用JDK动态代理,可以强制使用cglib进行代理
- 如果目标对象没有实现任何接口,则一定会使用CGLIB代理
如何强制使用CGLIB实现AOP功能?
- 添加CGLIB库,Spring_HOME/cglib/*.jar
- 在配置文件中加入<aop:aspectj-autoproxy proxy-target-class="true"/>
JDK与CGLIB区别
- JDK动态代理:其代理对象必须是某个接口的实现,通过运行期间生成一个接口的实现类来完成对象的代理,通过反射调用相应的方法
- CGLIB代理:运行期间生成代理对象是针对目标类扩展的子类,底层依靠ASM字节码来操作实现,直接调用其方法
效率:CGLIB>JDK
expose-proxy
有时候目标对象的自我调用将无法实施切面的增强,楼主在阿里的面试中被问到这样一个问题,列如在HelloServiceImpl的a()方法里面调用this.b()方法会执行相应的事务么?
public interface HelloService {
void a();
void b();
}
public class HelloServiceImpl implements HelloService {
@Transactional(propagation = Propagation.REQUIRES_NEW)
@Override
public void a() {
this.b();
}
@Transactional(propagation = Propagation.REQUIRES_NEW)
@Override
public void b() {
}
}
答案是不会执行的!!!!
我们可以配置文件里面这样做<aop:aspectj-autoproxy expose-proxy=“true”>并且在代码里面修改为
((HelloService)AopContext.currentProxy()).b();
通过以上方法可以同时对a(),b()方法同时增强