spring源码的xml解析过程-6(AOP 标签解析)

AOP 概念

  1. 切面(Aspect)
    将横切关注点设计为独立可重用的对象,这些对象称为切面。
    实际上就是一些功能增强的类或者对象的代表,比如:日志管理、事物管理、异常控制等
  2. 连接点(Joinpoint)
    切面在应用程序执行时加入对象的业务流程中的特定点,成为连接点(Joinpoint)。
    连接点是AOP的核心概念之一。它用来定义在目标程序的哪里通过AOP加入新的逻辑。
    一个要被拦截的方法,注意这里是一个被拦截或者需要功能增强的方法点
  3. 切点(Pointcut)
    切入点是通知要被织入到应用程序中的所有连接点的集合。
    可以在一个文件中,例如XML文件中,定义一个通知的切入点,即它的所有连接点。说白了就是一个joinpoint的集合,一个连接点的集合
  4. 增强\通知(Advice)
    增强是织入到目标类连接点上的一段程序代码。说白了就是一段在被代理类方法上面或者下面、或者环绕增加代码
  5. Advisor
    Advice和Pointcut组成的独立的单元,并且能够传给proxy factory 对象。
  6. 引入(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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值