Spring在xml中开启AOP:
<aop:aspectj-autoproxy />
在自定义标签注解解析时:
public void init(){
registerBeanDefinitionParser("config",new ConfigBeanDefinitionParser());
//注册AspectJ的解析器,一旦使用aspectj-autoproxy注解,就使用该解析器来解析
registerBeanDefinitionParser("aspectj-autoproxy",new AspectJAutoProxyBeanDefinitionParser());
......
}
所有的解析器都是对BeanDefinitionParser接口的统一实现,所以入口函数都是从parse方法开始的:
public BeanDefinition parse(Element element,ParserContext parserContext){
//注册AspectJAnnotationAutoProxyCreator
AopNamespaceUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(parserContext,element);
//对于注解中子类的处理
extendBeanDefiniton(element,parserContext);
return null
}
其中这个方法registerAspectJAnnotationAutoProxyCreatorIfNecessary是非常重要的,也是关键的逻辑实现
1.注册或者升级AnnotationAwareAspectJAutoProxyCreator:
AOP功能基本上都是由AnnotationAwareAspectJAutoProxyCreator来实现的,它可以根据@Point注解定义的切点来自动代理与其匹配的bean
2.处理proxy-tatget-class属性和expose-proxy属性
proxy-tatget-class:与使用哪种动态代理技术有关。如果需要代理的对象实现了至少一种接口,则使用jdk动态代理,反之使用cglib。
补:CGLIB和JDK动态代理:
JDK:在运行期间创建接口的实现类实现动态代理
CGLIB:在运行期间操作字节码从而针对目标类创建其子类
如果强制使用CGLIB的动态代理:
1.无法增强final方法,因为final方法不能够被子类实现覆盖
2.需要把CGLIB的包放到classPath下面
3.需要将<aop:config>标签的proxy-tatget-class属性设为true:
<aop:config proxy-tatget-class="true" />
如果在目标对象中实现自我调用:
public interface TService{
public void a();
public void b();
}
@Service
public class TServiceImpl implements TService{
@Transactional(...)
public void a(){
//在这里由于this指向了目标对象而不是代理对象
//因此在执行这个自我调用时会调用自身的b方法而不是代理对象的b方法
//所以在b方法上的事务切面不会被调用,即不会进行事务增强
this.b();
}
@Transactional(...)
public void b(){
...
}
}
上述问题解决办法:
<aop:aspectj-autoproxy expose-proxy = "true">
并将this.b()改成((AService)AopContext.currentProxy()).b(),这样就可以在自我调用中实现b方法的增强