Spring AOP原理
我们知道声明式事务是通过spring 的aop实现的,先看spring aop的实现
Spring aop
注解属性解析
spring能完成AOP的代理,因为Spring有这样的配置
<aop:aspectj-autoproxy />
这一配置使得整个Spring项目拥有了AOP的功能.那么spring如何解析aop配置的呢?
根据spring 代码习惯,命名空间的解析都在相应的jar下的config包里,取名xxNamespaceHandler.比如aop在Spring-aop.jar中org.springframework.aop.config包内有AopNamespaceHandler.
@Override
public void init() {
// In 2.0 XSD as well as in 2.1 XSD.
registerBeanDefinitionParser("config", new ConfigBeanDefinitionParser());
registerBeanDefinitionParser("aspectj-autoproxy", new AspectJAutoProxyBeanDefinitionParser());
registerBeanDefinitionDecorator("scoped-proxy", new ScopedProxyBeanDefinitionDecorator());
// Only in 2.0 XSD: moved to context namespace as of 2.1
registerBeanDefinitionParser("spring-configured", new SpringConfiguredBeanDefinitionParser());
}
可以看到当指定了aspectj-autoproxy,会使用org.springframework.aop.config.AspectJAutoProxyBeanDefinitionParser解析元素.AspectJAutoProxyBeanDefinitionParser的parse方法调用的是AopNamespaceUtils类中的registerAspectJAnnotationAutoProxyCreatorIfNecessary方法,作用是初始化一个AOP专用的Bean,并且注册到Spring容器中。
public static void registerAspectJAnnotationAutoProxyCreatorIfNecessary(
ParserContext parserContext, Element sourceElement) {
BeanDefinition beanDefinition = AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(
parserContext.getRegistry(), parserContext.extractSource(sourceElement));
useClassProxyingIfNecessary(parserContext.getRegistry(), sourceElement);
registerComponentIfNecessary(beanDefinition, parserContext);
}
3句对应三个操作
a.注册一个AnnotationAwareAspectJAutoProxyCreator(称它为自动代理器),Creator是AOP的操作核心,也是扫描Bean,代理Bean的操作所在。
b.解析配置元素,决定代理的模式。包含有JDK动态代理,CGLIB代理
c.作为系统组件,把Creator放到Spring容器中。让Spring实例化,启动这个Creator。
重点看下第2句,后面会用到
private static void useClassProxyingIfNecessary(BeanDefinitionRegistry registry, Element sourceElement) {
if (sourceElement != null) {
//public static final String PROXY_TARGET_CLASS_ATTRIBUTE = "proxy-target-class";
boolean proxyTargetClass = Boolean.parseBoolean(sourceElement.getAttribute(PROXY_TARGET_CLASS_ATTRIBUTE));
if (proxyTargetClass) {
AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
}
//private static final String EXPOSE_PROXY_ATTRIBUTE = "expose-proxy";
boolean exposeProxy = Boolean.parseBoolean(sourceElement.getAttribute(EXPOSE_PROXY_ATTRIBUTE));
if (exposeProxy) {
AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry);
}
}
}
不难发现其实就是解析配置,设置属性的过程
jdk or cglib选取
org.springframework.aop.framework.DefaultAopProxyFactory
public class DefaultAopProxyFactory implements AopProxyFactory, Serializable {
@Override
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
//optimize:通过cglib控制的代理使用优化策略,default=false
//proxyTargetClass:设置直接通过目标类来代理,而不是接口,default=false.
//hasNoUserSuppliedProxyInterfaces:是否实现了接口,是-else
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.");
}
//如果代理对象是Interface类型,仍然使用jdk代理
//或者,当代理目标是getProxyClass方法或者newProxyInstance方法生成时,仍然使用jdk代理
if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
return new JdkDynamicAopProxy(config);
}
return new ObjenesisCglibAopProxy(config);
}
else {
//默认情况Optimize与proxyTargetClass=false,实现了接口时hasNoUserSuppliedProxyInterfaces=false,使用jdk代理
return new JdkDynamicAopProxy(config);
}
}
/**
* Determine whether the supplied {@link AdvisedSupport} has only the
* {@link org.springframework.aop.SpringProxy} interface specified
* (or no proxy interfaces specified at all).
*/
private boolean hasNoUserSuppliedProxyInterfaces(AdvisedSupport config) {
Class<?>[] ifcs = config.getProxiedInterfaces();
//没有实现接口,或者类只是SpringProxy.class的子类。
//isAssignableFrom方法用于判断两个类或者接口是否是相同的类
return (ifcs.length == 0 || (ifcs.length == 1 && SpringProxy.class.isAssignableFrom(ifcs[0])));
}
}
从源码看出,使用cglib有3个条件判断,config.isOptimize()、config.isProxyTargetClass()和hasNoUserSuppliedProxyInterfaces(config)。其中config.isOptimize()与config.isProxyTargetClass()默认返回是false,因此默认情况下就由hasNoUserSuppliedProxyInterfaces(config)的结果决定,hasNoUserSuppliedProxyInterfaces(config)是在判断代理的对象是否有实现接口,有实现接口的话直接走new JdkDynamicAopProxy(config)分支,即使用JDK的动态代理。
ProxyTargetClass通过配置决定,Optimize可以通过bean属性指定.
JDK与CGlib方式实现aop总结
Spring会自动在JDK动态代理和CGLIB之间转换,选取合适的代理方式,规则如下:
1.如果目标对象实现了接口,默认情况采用jdk动态代理实现aop,所有由目标对象实现的接口将全部被代理。
2.如果目标对象实现了接口,可以强制指定使用cglib实现aop,方式为配置<aop:aspectj-autoproxy proxy-target-class=”true”/>,且需引入cglib的Jar,如果已经有spring-core的jar包,则无需引入,因为spring-core中包含了cglib。
3.如果对象没有实现接口,就使用cglib方式
JDK动态代理与CGlib字节码生成的区别
JDK动态代理,必须是实现了接口的类生成代理,实现方式是运行时创建一个接口的实现类.JDK代理通过这些接口获取构造方法,用这个构造方法和InvocationHandler,实例化一个对象出来。所以JDK的方式是基于接口的。
CGlib是针对类生成代理,用目标类生成一个子类,子类重写父类的方法,达到动态代理的效果,因此,不能用于声明为final的方法或类上.底层依赖ASM操作字节码,性能比JDK好
实现类中方法自我调用的代理
属性expose-proxy=true,可以对目标对象的自我调用进行增强,然后按如下方式改写代码
<aop:aspectj-autoproxy expose-proxy="true"/>
改写代码
this.hello()
改为
((HelloService) AopContext.currentProxy()).hello()