AOP 概念
- 切面(Aspect)
将横切关注点设计为独立可重用的对象,这些对象称为切面。
实际上就是一些功能增强的类或者对象的代表,比如:日志管理、事物管理、异常控制等 - 连接点(Joinpoint)
切面在应用程序执行时加入对象的业务流程中的特定点,成为连接点(Joinpoint)。
连接点是AOP的核心概念之一。它用来定义在目标程序的哪里通过AOP加入新的逻辑。
一个要被拦截的方法,注意这里是一个被拦截或者需要功能增强的方法点 - 切点(Pointcut)
切入点是通知要被织入到应用程序中的所有连接点的集合。
可以在一个文件中,例如XML文件中,定义一个通知的切入点,即它的所有连接点。说白了就是一个joinpoint的集合,一个连接点的集合 - 增强\通知(Advice)
增强是织入到目标类连接点上的一段程序代码。说白了就是一段在被代理类方法上面或者下面、或者环绕增加代码 - Advisor
Advice和Pointcut组成的独立的单元,并且能够传给proxy factory 对象。 - 引入(Introduction)
通过引入,我们可以在一个对象中(动态)加入新的方法和属性,而不用修改它的程序。
对应切面中的<aop:declare-parents />
<aop:pointcut>
:用来定义切入点,该切入点可以重用;
<aop:advisor>
:用来定义只有一个通知和一个切入点的切面;
<aop:aspect>
:用来定义切面,该切面可以包含多个切入点和通知,而且标签内部的通知和切入点定义是无序的;和advisor的区别就在此,advisor只包含一个通知和一个切入点。
<!--
<aop:pointcut>:用来定义切入点,该切入点可以重用;
<aop:advisor>:用来定义只有一个通知和一个切入点的切面;
<aop:aspect>:用来定义切面,该切面可以包含多个切入点和通知,
而且标签内部的通知和切入点定义是无序的;和advisor的区别就在此,advisor只包含一个通知和一个切入点。
-->
<aop:config>
<!--
<aop:pointcut >:在此处定义的pointcut是全局的pointcut可以供所有的aspect使用
id:表示这个pointcut的名称,以方便使用
-->
<aop:pointcut id="myMethods"
expression="execution(public * com.dongnao.jack.service..*.*(..))" />
<!--
<aop:aspect>表示定义一个切面类(这需要Spring初始化加入其管理)
id:切面类的名称,
ref:引用哪个bean(需要使用<bean>标签初始化)
-->
<aop:aspect id="txAspect" ref="myaspectj">
<aop:declare-parents types-matching="com.dongnao.jack.service.MyServiceImpl"
implement-interface="com.dongnao.jack.aop.IntroductionIntf"
delegate-ref="myintroduction"/>
<!--
在此处定义的pointcut是全局的pointcut只供当前的aspect使用
id:表示这个pointcut的名称,以方便使用 -->
<aop:pointcut id="myMethod2"
expression="execution(public * com.dongnao.jack.service..*.*(..))" />
<!--
定义advice时的参数
method:切面逻辑的方法名称(切面类中的方法名)
pointcut-ref:表示引用哪个pointcut(要求已经在上面定义好了)
pointcut:定义一个pointcut
-->
<!--
<aop:before method="before" pointcut-ref="myMethods"/>
<aop:after-returning method="afterReturning" pointcut="execution(public * com.dongnao.jack.service..*.*(..))"/>
<aop:after method="after" pointcut-ref="myMethod2"/>
<aop:after-throwing method="afterthrowing" pointcut-ref="myMethods"/>
<aop:around method="around" pointcut-ref="myMethod2"/>-->
<aop:before method="before" pointcut="execution(public * com.dongnao.jack.aop..*.*(..))"/>
</aop:aspect>
<!--
<aop:advisor advice-ref="" pointcut-ref=""/>
-->
</aop:config>
AOP 标签解析
查看标签解析类注册类
org.springframework.aop.config.AopNamespaceHandler
// xml 方式 AOP
registerBeanDefinitionParser("config", new
// 注解方式 AOP
ConfigBeanDefinitionParser());
registerBeanDefinitionParser("aspectj-autoproxy", new AspectJAutoProxyBeanDefinitionParser());
xml 方式配置的 AOP 解析
org.springframework.aop.config.ConfigBeanDefinitionParser#parse
configureAutoProxyCreator(parserContext, element);
org.springframework.aop.config.ConfigBeanDefinitionParser#configureAutoProxyCreator
AopNamespaceUtils.registerAspectJAutoProxyCreatorIfNecessary(parserContext, element);
org.springframework.aop.config.AopNamespaceUtils#registerAspectJAutoProxyCreatorIfNecessary
BeanDefinition beanDefinition =
AopConfigUtils.registerAspectJAutoProxyCreatorIfNecessary(
parserContext.getRegistry(),
parserContext.extractSource(sourceElement));
org.springframework.aop.config.AopConfigUtils#registerAspectJAutoProxyCreatorIfNecessary(org.springframework.beans.factory.support.BeanDefinitionRegistry, java.lang.Object)
// AspectJAwareAdvisorAutoProxyCreator AOP 入口类
return
registerOrEscalateApcAsRequired(AspectJAwareAdvisorAutoProxyCreator.class, registry, source);
AspectJAwareAdvisorAutoProxyCreator 的顶层接口是 InstantiationAwareBeanPostProcessor
org.springframework.aop.config.AopConfigUtils#registerOrEscalateApcAsRequired
该方法传入参数为 AspectJAwareAdvisorAutoProxyCreator
类,并在方法内部实例化一个 beanDefinition
,查看 RootBeanDefinition
构造器,存储了传入的 class 类,则在循环 beanDefinition
时,就可以根据反射实例化传入类。
RootBeanDefinition beanDefinition = new RootBeanDefinition(cls);
beanDefinition.setSource(source);
beanDefinition.getPropertyValues().add("order", Ordered.HIGHEST_PRECEDENCE);
beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
// 注册,主要是将 beanName 存入容器中 this.beanDefinitionNames.add(beanName); 的过程
registry.registerBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME, beanDefinition);
return beanDefinition;
返回到
org.springframework.aop.config.AopNamespaceUtils#registerAspectJAutoProxyCreatorIfNecessary
// AOP 入口类的注册
BeanDefinition beanDefinition = AopConfigUtils.registerAspectJAutoProxyCreatorIfNecessary(
parserContext.getRegistry(), parserContext.extractSource(sourceElement));
// 根据标签配置,选择哪种方式实现动态代理
useClassProxyingIfNecessary(parserContext.getRegistry(), sourceElement);
返回到
org.springframework.aop.config.ConfigBeanDefinitionParser#parse
List<Element> childElts = DomUtils.getChildElements(element);
for (Element elt: childElts) {
String localName = parserContext.getDelegate().getLocalName(elt);
if (POINTCUT.equals(localName)) {
// <aop:pointcut> 标签解析
parsePointcut(elt, parserContext);
}
else if (ADVISOR.equals(localName)) {
// <aop:advisor> 标签解析
parseAdvisor(elt, parserContext);
}
else if (ASPECT.equals(localName)) {
// <aop:aspect> 标签解析
parseAspect(elt, parserContext);
}
}
查看
org.springframework.aop.config.ConfigBeanDefinitionParser#parsePointcut
String id = pointcutElement.getAttribute(ID);
// 表达式
String expression = pointcutElement.getAttribute(EXPRESSION);
pointcutDefinition = createPointcutDefinition(expression);
org.springframework.aop.config.ConfigBeanDefinitionParser#createPointcutDefinition
// 注册 AspectJExpressionPointcut 类,循环 beanDefinition 时,会实例化该类
RootBeanDefinition beanDefinition =
new RootBeanDefinition(AspectJExpressionPointcut.class);
beanDefinition.setScope(BeanDefinition.SCOPE_PROTOTYPE);
beanDefinition.setSynthetic(true);
beanDefinition.getPropertyValues().add(EXPRESSION, expression);
return beanDefinition;
AspectJExpressionPointcut Aop表达式解析类
返回到
org.springframework.aop.config.ConfigBeanDefinitionParser#parse
查看
org.springframework.aop.config.ConfigBeanDefinitionParser#parseAspect
// 引用标签:declare-parents 标签元素解析
List<Element> declareParents = DomUtils.getChildElementsByTagName(aspectElement, DECLARE_PARENTS);
for (int i = METHOD_INDEX; i < declareParents.size(); i++) {
Element declareParentsElement = declareParents.get(i);
// 查看 parseDeclareParents 方法,见下
beanDefinitions.add(parseDeclareParents(declareParentsElement, parserContext));
}
// 是否是 <aop:aspect> 标签节点
if (isAdviceNode(node, parserContext)) {
// 解析通知标签,查看 parseAdvice 方法,见下
AbstractBeanDefinition advisorDefinition =
parseAdvice(aspectName, i, aspectElement, (Element) node, parserContext, beanDefinitions, beanReferences);
}
org.springframework.aop.config.ConfigBeanDefinitionParser#parseDeclareParents
// 通过 BeanDefinitionBuilder 创建 BeanDefinition
// 在这里注册 DeclareParentsAdvisor 类
BeanDefinitionBuilder builder =
BeanDefinitionBuilder.rootBeanDefinition(DeclareParentsAdvisor.class);
org.springframework.aop.config.ConfigBeanDefinitionParser#parseAdvice
// 注册 MethodLocatingFactoryBean 类
RootBeanDefinition methodDefinition =
new RootBeanDefinition(MethodLocatingFactoryBean.class);
// 注册 SimpleBeanFactoryAwareAspectInstanceFactory 类
RootBeanDefinition aspectFactoryDef =
new RootBeanDefinition(SimpleBeanFactoryAwareAspectInstanceFactory.class);
// 查看 createAdviceDefinition 方法
AbstractBeanDefinition adviceDef = createAdviceDefinition(
adviceElement, parserContext, aspectName, order, methodDefinition, aspectFactoryDef,
beanDefinitions, beanReferences);
org.springframework.aop.config.ConfigBeanDefinitionParser#createAdviceDefinition
// 查看 getAdviceClass 方法
RootBeanDefinition adviceDefinition = new RootBeanDefinition(getAdviceClass(adviceElement, parserContext));
// 切面的执行顺序配置,例如定义多个 before 标签,哪个先执行呢?
adviceDefinition.getPropertyValues().add(DECLARATION_ORDER_PROPERTY, order);
在解析标签时,会将标签对应的 advice 增强类进行注册
org.springframework.aop.config.ConfigBeanDefinitionParser#getAdviceClass
private Class<?> getAdviceClass(Element adviceElement, ParserContext parserContext) {
String elementName = parserContext.getDelegate().getLocalName(adviceElement);
if (BEFORE.equals(elementName)) {
return AspectJMethodBeforeAdvice.class;
}
else if (AFTER.equals(elementName)) {
return AspectJAfterAdvice.class;
}
else if (AFTER_RETURNING_ELEMENT.equals(elementName)) {
return AspectJAfterReturningAdvice.class;
}
else if (AFTER_THROWING_ELEMENT.equals(elementName)) {
return AspectJAfterThrowingAdvice.class;
}
else if (AROUND.equals(elementName)) {
return AspectJAroundAdvice.class;
}
else {
throw new IllegalArgumentException("Unknown advice kind [" + elementName + "].");
}
}
返回到
org.springframework.aop.config.ConfigBeanDefinitionParser#parseAdvice
// 注册 AspectJPointcutAdvisor
RootBeanDefinition advisorDefinition =
new RootBeanDefinition(AspectJPointcutAdvisor.class);
// aop:aspect 标签的执行顺序
if (aspectElement.hasAttribute(ORDER_PROPERTY)) {
advisorDefinition.getPropertyValues().add(
ORDER_PROPERTY, aspectElement.getAttribute(ORDER_PROPERTY));
}
返回到
org.springframework.aop.config.ConfigBeanDefinitionParser#parseAspect
// 解析标签 aop:aspect 下的 aop:pointcut
List<Element> pointcuts = DomUtils.getChildElementsByTagName(aspectElement, POINTCUT);
for (Element pointcutElement : pointcuts) {
parsePointcut(pointcutElement, parserContext);
}
返回到
org.springframework.aop.config.ConfigBeanDefinitionParser#parse
查看 parseAdvisor(elt, parserContext);
解析 aop:advisor
org.springframework.aop.config.ConfigBeanDefinitionParser#parseAdvisor
AbstractBeanDefinition advisorDef =
createAdvisorBeanDefinition(advisorElement, parserContext);
org.springframework.aop.config.ConfigBeanDefinitionParser#createAdvisorBeanDefinition
// 创建引用方式的 BeanDefinition ,即 advice-ref
RootBeanDefinition advisorDefinition =
new RootBeanDefinition(DefaultBeanFactoryPointcutAdvisor.class);
返回到
org.springframework.aop.config.ConfigBeanDefinitionParser#parseAdvisor
// 解析 aop:advisor 下的 pointcut
Object pointcut = parsePointcutProperty(advisorElement, parserContext);
上面的对 aop 相关的xml 标签解析完毕
总结
aop的入口类
AspectJAwareAdvisorAutoProxyCreator
解析pointcut的时候往BeanDefinition里面注册了AspectJExpressionPointcut
解析Aspectj的时候往BeanDefinition里面注册了DeclareParentsAdvisor
解析advice的时候往BeanDefinition里面注册了MethodLocatingFactoryBean
在advice解析的时候创建了一个advisor的时候往BeanDefinition里面注册了AspectJPointcutAdvisor
解析advisor的时候往BeanDefinition里面注册了DefaultBeanFactoryPointcutAdvisor