本篇文章主要讲解AOP配置中的几个通知类的解析过程,为后续对目标类进行代理做准备;在前面的Spring IOC篇我们讲解了自定义配置的解析,AOP配置的解析过程也是其自定义注解的过程,如果不熟悉自定义解析过程可以看之前的文章Spring IOC源码:<context:component-scan>源码详解
先看下AOP配置文件内容:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<bean id="accountAdvice" class="service.impl.AccountAdvice" ></bean>
<bean id="myAccount" class="service.impl.MyAccount" ></bean>
<aop:config>
<aop:pointcut id="pointCut" expression="execution(* service.impl.*.*())"/>
<aop:aspect ref="accountAdvice">
<aop:after method="after" pointcut-ref="pointCut"></aop:after>
<aop:before method="before" pointcut-ref="pointCut"></aop:before>
<aop:around method="around" pointcut-ref="pointCut"></aop:around>
<aop:after-returning method="afterReturn" pointcut-ref="pointCut"></aop:after-returning>
<aop:after-throwing method="afterThrow" pointcut-ref="pointCut"></aop:after-throwing>
</aop:aspect>
</aop:config>
</beans>
回到BeanDefinition的解析步骤中,由于AOP是属于自定义解析,所以会使用自定义命名空间处理器进行处理,也就是会走delegate.parseCustomElement(ele)方法。
protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
if (delegate.isDefaultNamespace(root)) {
NodeList nl = root.getChildNodes();
for (int i = 0; i < nl.getLength(); i++) {
Node node = nl.item(i);
if (node instanceof Element) {
Element ele = (Element) node;
if (delegate.isDefaultNamespace(ele)) {
parseDefaultElement(ele, delegate);
}
else {
delegate.parseCustomElement(ele);
}
}
}
}
else {
delegate.parseCustomElement(root);
}
}
public BeanDefinition parseCustomElement(Element ele) {
return parseCustomElement(ele, null);
}
/**
* Parse a custom element (outside of the default namespace).
* @param ele the element to parse
* @param containingBd the containing bean definition (if any)
* @return the resulting bean definition
*/
@Nullable
public BeanDefinition parseCustomElement(Element ele, @Nullable BeanDefinition containingBd) {
String namespaceUri = getNamespaceURI(ele);
if (namespaceUri == null) {
return null;
}
//获取自定义命名空间处理器
NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);
if (handler == null) {
error("Unable to locate Spring NamespaceHandler for XML schema namespace [" + namespaceUri + "]", ele);
return null;
}
return handler.parse(ele, new ParserContext(this.readerContext, this, containingBd));
}
handler.parse(ele, new ParserContext(this.readerContext, this, containingBd)),见方法1详解
public BeanDefinition parse(Element element, ParserContext parserContext) {
BeanDefinitionParser parser = findParserForElement(element, parserContext);
return (parser != null ? parser.parse(element, parserContext) : null);
}
public BeanDefinition parse(Element element, ParserContext parserContext) {
CompositeComponentDefinition compositeDef =
new CompositeComponentDefinition(element.getTagName(), parserContext.extractSource(element));
parserContext.pushContainingComponent(compositeDef);
//注册AspectJAwareAdvisorAutoProxyCreator到beanFactory工厂中
configureAutoProxyCreator(parserContext, element);
List<Element> childElts = DomUtils.getChildElements(element);
for (Element elt: childElts) {
String localName = parserContext.getDelegate().getLocalName(elt);
//解析POINTCUT配置标签,
if (POINTCUT.equals(localName)) {
parsePointcut(elt, parserContext);
}
//解析标签
else if (ADVISOR.equals(localName)) {
parseAdvisor(elt, parserContext);
}
//解析标签
else if (ASPECT.equals(localName)) {
parseAspect(elt, parserContext);
}
}
parserContext.popAndRegisterContainingComponent();
return null;
}
parsePointcut(elt, parserContext),见方法2详解
parseAspect(elt, parserContext),见方法4详解
private AbstractBeanDefinition parsePointcut(Element pointcutElement, ParserContext parserContext) {
//获取id属性值
String id = pointcutElement.getAttribute(ID);
//获取expression表达式值
String expression = pointcutElement.getAttribute(EXPRESSION);
AbstractBeanDefinition pointcutDefinition = null;
try {
this.parseState.push(new PointcutEntry(id));
//将表达式内容封装成RootBeanDefinition对象
pointcutDefinition = createPointcutDefinition(expression);
pointcutDefinition.setSource(parserContext.extractSource(pointcutElement));
String pointcutBeanName = id;
if (StringUtils.hasText(pointcutBeanName)) {
//如果有设置id名称,则将其作为beanName并将definition注册到beanFactory工厂中
parserContext.getRegistry().registerBeanDefinition(pointcutBeanName, pointcutDefinition);
}
else {
//没有名称则生成并注册到beanFactory工厂中
pointcutBeanName = parserContext.getReaderContext().registerWithGeneratedName(pointcutDefinition);
}
//注册组件到上下文中
parserContext.registerComponent(
new PointcutComponentDefinition(pointcutBeanName, pointcutDefinition, expression));
}
finally {
this.parseState.pop();
}
return pointcutDefinition;
}
createPointcutDefinition(expression),见方法3详解
protected AbstractBeanDefinition createPointcutDefinition(String expression) {
//设置封装类型为AspectJExpressionPointcut的RootBeanDefinition
RootBeanDefinition beanDefinition = new RootBeanDefinition(AspectJExpressionPointcut.class);
//设置为原型模式
beanDefinition.setScope(BeanDefinition.SCOPE_PROTOTYPE);
beanDefinition.setSynthetic(true);
//添加属性值
beanDefinition.getPropertyValues().add(EXPRESSION, expression);
return beanDefinition;
}
private void parseAspect(Element aspectElement, ParserContext parserContext) {
//获取id值
String aspectId = aspectElement.getAttribute(ID);
//获取引用的切面类名称
String aspectName = aspectElement.getAttribute(REF);
try {
this.parseState.push(new AspectEntry(aspectId, aspectName));
//存放解析的BeanDefinition
List<BeanDefinition> beanDefinitions = new ArrayList<>();
List<BeanReference> beanReferences = new ArrayList<>();
//获取declare-parents标签
List<Element> declareParents = DomUtils.getChildElementsByTagName(aspectElement, DECLARE_PARENTS);
//遍历解析封装成BeanDefinition
for (int i = METHOD_INDEX; i < declareParents.size(); i++) {
Element declareParentsElement = declareParents.get(i);
beanDefinitions.add(parseDeclareParents(declareParentsElement, parserContext));
}
// We have to parse "advice" and all the advice kinds in one loop, to get the
// ordering semantics right.
NodeList nodeList = aspectElement.getChildNodes();
boolean adviceFoundAlready = false;
for (int i = 0; i < nodeList.getLength(); i++) {
Node node = nodeList.item(i);
//判断是否是通知配置标签,如、 等
if (isAdviceNode(node, parserContext)) {
if (!adviceFoundAlready) {
adviceFoundAlready = true;
if (!StringUtils.hasText(aspectName)) {
parserContext.getReaderContext().error(
" tag needs aspect bean reference via 'ref' attribute when declaring advices." ,
aspectElement, this.parseState.snapshot());
return;
}
//封装切面类为RuntimeBeanReference,并添加到集合中
beanReferences.add(new RuntimeBeanReference(aspectName));
}
//解析当前通知标签
AbstractBeanDefinition advisorDefinition = parseAdvice(
aspectName, i, aspectElement, (Element) node, parserContext, beanDefinitions, beanReferences);
beanDefinitions.add(advisorDefinition);
}
}
AspectComponentDefinition aspectComponentDefinition = createAspectComponentDefinition(
aspectElement, aspectId, beanDefinitions, beanReferences, parserContext);
parserContext.pushContainingComponent(aspectComponentDefinition);
//获取aspect标签下的pointcut子标签
List<Element> pointcuts = DomUtils.getChildElementsByTagName(aspectElement, POINTCUT);
//解析并注册到beanFactory中
for (Element pointcutElement : pointcuts) {
parsePointcut(pointcutElement, parserContext);
}
parserContext.popAndRegisterContainingComponent();
}
finally {
this.parseState.pop();
}
}
isAdviceNode(node, parserContext),见方法5详解
parseAdvice(aspectName, i, aspectElement, (Element) node, parserContext, beanDefinitions, beanReferences),见方法6详解
private boolean isAdviceNode(Node aNode, ParserContext parserContext) {
if (!(aNode instanceof Element)) {
return false;
}
else {
//获取节点名称
String name = parserContext.getDelegate().getLocalName(aNode);
//判断是否是befor、after、after-returning、after-throwing、around
return (BEFORE.equals(name) || AFTER.equals(name) || AFTER_RETURNING_ELEMENT.equals(name) ||
AFTER_THROWING_ELEMENT.equals(name) || AROUND.equals(name));
}
}
private AbstractBeanDefinition parseAdvice(
String aspectName, int order, Element aspectElement, Element adviceElement, ParserContext parserContext,
List<BeanDefinition> beanDefinitions, List<BeanReference> beanReferences) {
try {
this.parseState.push(new AdviceEntry(parserContext.getDelegate().getLocalName(adviceElement)));
// create the method factory bean
//创建MethodLocatingFactoryBean的RootBeanDefinition
RootBeanDefinition methodDefinition = new RootBeanDefinition(MethodLocatingFactoryBean.class);
//设置切面名称
methodDefinition.getPropertyValues().add("targetBeanName", aspectName);
//设置method方法名称
methodDefinition.getPropertyValues().add("methodName", adviceElement.getAttribute("method"));
//标志为合成的
methodDefinition.setSynthetic(true);
// create instance factory definition
//创建SimpleBeanFactoryAwareAspectInstanceFactory类型的RootBeanDefinition
RootBeanDefinition aspectFactoryDef =
new RootBeanDefinition(SimpleBeanFactoryAwareAspectInstanceFactory.class);
aspectFactoryDef.getPropertyValues().add("aspectBeanName", aspectName);
aspectFactoryDef.setSynthetic(true);
// register the pointcut
//封装成完整的通知类BeanDefinition
AbstractBeanDefinition adviceDef = createAdviceDefinition(
adviceElement, parserContext, aspectName, order, methodDefinition, aspectFactoryDef,
beanDefinitions, beanReferences);
// configure the advisor
//将advice再加层封装成advisor
RootBeanDefinition advisorDefinition = new RootBeanDefinition(AspectJPointcutAdvisor.class);
advisorDefinition.setSource(parserContext.extractSource(adviceElement));
advisorDefinition.getConstructorArgumentValues().addGenericArgumentValue(adviceDef);
//判断是否有order属性,有则添加到定义信息中
if (aspectElement.hasAttribute(ORDER_PROPERTY)) {
advisorDefinition.getPropertyValues().add(
ORDER_PROPERTY, aspectElement.getAttribute(ORDER_PROPERTY));
}
// register the final advisor
//生成beanName并注册到beanFactory中
parserContext.getReaderContext().registerWithGeneratedName(advisorDefinition);
return advisorDefinition;
}
finally {
this.parseState.pop();
}
}
createAdviceDefinition(adviceElement, parserContext, aspectName, order, methodDefinition, aspectFactoryDef,beanDefinitions, beanReferences),见方法7详解
private AbstractBeanDefinition createAdviceDefinition(
Element adviceElement, ParserContext parserContext, String aspectName, int order,
RootBeanDefinition methodDef, RootBeanDefinition aspectFactoryDef,
List<BeanDefinition> beanDefinitions, List<BeanReference> beanReferences) {
//获取对应类型的消息通知类并封装成RootBeanDefinition
RootBeanDefinition adviceDefinition = new RootBeanDefinition(getAdviceClass(adviceElement, parserContext));
adviceDefinition.setSource(parserContext.extractSource(adviceElement));
//添加切面名称
adviceDefinition.getPropertyValues().add(ASPECT_NAME_PROPERTY, aspectName);
//添加declarationOrder值
adviceDefinition.getPropertyValues().add(DECLARATION_ORDER_PROPERTY, order);
//添加returning属性值
if (adviceElement.hasAttribute(RETURNING)) {
adviceDefinition.getPropertyValues().add(
RETURNING_PROPERTY, adviceElement.getAttribute(RETURNING));
}
//添加throwing属性值
if (adviceElement.hasAttribute(THROWING)) {
adviceDefinition.getPropertyValues().add(
THROWING_PROPERTY, adviceElement.getAttribute(THROWING));
}
//添加arg-names属性值
if (adviceElement.hasAttribute(ARG_NAMES)) {
adviceDefinition.getPropertyValues().add(
ARG_NAMES_PROPERTY, adviceElement.getAttribute(ARG_NAMES));
}
//获取构造函数
ConstructorArgumentValues cav = adviceDefinition.getConstructorArgumentValues();
//添加第一个参数为方法对象
cav.addIndexedArgumentValue(METHOD_INDEX, methodDef);
//解析其表达式
Object pointcut = parsePointcutProperty(adviceElement, parserContext);
//将表达式添加到构造函数中的第二位
if (pointcut instanceof BeanDefinition) {
cav.addIndexedArgumentValue(POINTCUT_INDEX, pointcut);
beanDefinitions.add((BeanDefinition) pointcut);
}
else if (pointcut instanceof String) {
RuntimeBeanReference pointcutRef = new RuntimeBeanReference((String) pointcut);
cav.addIndexedArgumentValue(POINTCUT_INDEX, pointcutRef);
beanReferences.add(pointcutRef);
}
//将切面工厂实例作为构造函数的第三个参数
cav.addIndexedArgumentValue(ASPECT_INSTANCE_FACTORY_INDEX, aspectFactoryDef);
return adviceDefinition;
}
getAdviceClass(adviceElement, parserContext),见方法8详解
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 + "].");
}
}
到这里对AOP配置的解析就完成了,我们可以看到解析后的5个通知对象如下:
AOP自定命名空间解析会往beanFactory工厂中注册AspectJAwareAdvisorAutoProxyCreator类型的beanDefinition,对于aspect标签的解析中,会将< aop:after >等元素解析成advisor对象的beanDefition,为后续AOP代理增强做准备。