【spring源码分析(三)】AOP源码分析---解析xml中的aop:config标签内容并存储在BeanDefinition

xiaoxiao2025-05-17  29

前期准备

分析AOP源码,首先看下AOP的一个应用例子: UserService和UserServiceImpl实现类

public interface UserService { void saveUser(); void updateUser(); } @Service public class UserServiceImpl implements UserService { @Override public void saveUser() { System.out.println("添加用户"); } @Override public void updateUser() { System.out.println("修改用户"); } } }

aop.xml文件

<?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:context="http://www.springframework.org/schema/context" 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/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd"> <!-- 配置目标对象 --> <bean class="sourcecode.aop.target.UserServiceImpl"></bean> <!-- 配置通知类 --> <bean id="myAdvice" class="sourcecode.aop.advice.MyAdvice"></bean> <!-- AOP配置 --> <aop:config> <!-- 配置AOP切面,切面是由通知和切入点组成的 --> <aop:aspect ref="myAdvice"> <aop:before method="before" pointcut="execution(* *..*.*ServiceImpl.*(..))" /> </aop:aspect> </aop:config> </beans>

单元测试类:

@RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(locations="classpath:spring/spring-aop.xml") public class TestAOP { @Autowired private UserService userService; @Test public void test() { userService.saveUser(); } }

可以通过上述例子,设置断点调试,一步步看下aop的原理。接下来开始具体分析源码。

一、AOP源码入口

前面有篇文章已经分析过spring的ioc的源码,再次找到DefaultBeanDefinitionDocumentReader类的parseBeanDefinitions方法

protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) { // 加载的Document对象是否使用了Spring默认的XML命名空间(beans命名空间) if (delegate.isDefaultNamespace(root)) { // 获取Document对象根元素的所有子节点(bean标签、import标签、alias标签和其他自定义标签context、aop等) 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; // bean标签、import标签、alias标签,则使用默认解析规则 if (delegate.isDefaultNamespace(ele)) { parseDefaultElement(ele, delegate); } else {//像context标签、aop标签、tx标签,则使用用户自定义的解析规则解析元素节点 delegate.parseCustomElement(ele); } } } } else { delegate.parseCustomElement(root); } }

通过代码中注释可知,aop.xml文件中的<aop:config>标签,是通过调用delegate.parseCustomElement(ele)方法解析的,它的源码如下:

@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)); }

之前aop.xml文件已经被解析成org.w3c.dom.Document,并且org.w3c.dom.Document以树的形式展示,一个节点就是一个Node(Element是Node的子接口)。

对于解析aop.xml文件中的<aop:config>标签,上述代码第3行,返回的字符串为"http://www.springframework.org/schema/aop"的String对象。 分析第7行,this.readerContext.getNamespaceHandlerResolver()其实返回的是DefaultNamespaceHandlerResolver类,然后调用该类的resolve方法,该行最终返回的是AopNamespaceHandler类。resolve方法参数为第3行获取到的String对象,方法源码如下:

@Override @Nullable public NamespaceHandler resolve(String namespaceUri) { // 读取spring所有工程的META-INF/spring.handlers文件,获取namespaceUri和NamespaceHandler的映射关系 Map<String, Object> handlerMappings = getHandlerMappings(); // 获取 指定namespaceUri对应的namespaceHandler Object handlerOrClassName = handlerMappings.get(namespaceUri); if (handlerOrClassName == null) { return null; } else if (handlerOrClassName instanceof NamespaceHandler) { return (NamespaceHandler) handlerOrClassName; } else { // META-INF/spring.handlers文件中存储的value都是String类型的类名 String className = (String) handlerOrClassName; try { // 根据类名通过反射获取到NamespaceHandler的Class类对象 Class<?> handlerClass = ClassUtils.forName(className, this.classLoader); if (!NamespaceHandler.class.isAssignableFrom(handlerClass)) { throw new FatalBeanException("Class [" + className + "] for namespace [" + namespaceUri + "] does not implement the [" + NamespaceHandler.class.getName() + "] interface"); } // 实例化NamespaceHandler NamespaceHandler namespaceHandler = (NamespaceHandler) BeanUtils.instantiateClass(handlerClass); // 调用NamespaceHandler类的init方法,初始化一些专门处理指定标签的BeanDefinitionParsers类 namespaceHandler.init(); // 将namespaceUri对应的String类型的类名,替换为NamespaceHandler对象,下一次再获取的话,就不会重复创建实例 handlerMappings.put(namespaceUri, namespaceHandler); return namespaceHandler; } catch (ClassNotFoundException ex) { throw new FatalBeanException("Could not find NamespaceHandler class [" + className + "] for namespace [" + namespaceUri + "]", ex); } catch (LinkageError err) { throw new FatalBeanException("Unresolvable class definition for NamespaceHandler class [" + className + "] for namespace [" + namespaceUri + "]", err); } } }

分析上述代码:第7行返回的是AopNamespaceHandler类。27行代码调用AopNamespaceHandler类的init方法,初始化一些专门处理指定标签的BeanDefinitionParsers类,init方法源码:

@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()); }

分析上述代码:总共4个用于具体标签转换的Parser,分别为: config–>ConfigBeanDefinitionParser aspectj-autoproxy–>AspectJAutoProxyBeanDefinitionParser scoped-proxy–>ScopedProxyBeanDefinitionDecorator spring-configured–>SpringConfiguredBeanDefinitionParser

通过查看init方法中的其中一个方法registerBeanDefinitionParser可知,这些标签解析类是存储在AopNamespaceHandler的父类NamespaceHandlerSupport的map集合中,供后面使用,如下:

public abstract class NamespaceHandlerSupport implements NamespaceHandler { /** * Stores the {@link BeanDefinitionParser} implementations keyed by the * local name of the {@link Element Elements} they handle. */ private final Map<String, BeanDefinitionParser> parsers = new HashMap<>();

回头再接着看BeanDefinitionParserDelegate类的parseCustomElement方法,第12行最终调用的是AopNamespaceHandler类的parse方法。因为通过查看AopNamespaceHandler类,类中无parse方法定义,所以,调用的其实是父类NamespaceHandlerSupport的parse方法。该方法源码如下:

@Override @Nullable public BeanDefinition parse(Element element, ParserContext parserContext) { BeanDefinitionParser parser = findParserForElement(element, parserContext); return (parser != null ? parser.parse(element, parserContext) : null); }

分析上述代码:第4行根据aop标签,获取对应的解析类。对于标签aop:config,第4行获取到它的解析类ConfigBeanDefinitionParser,第5行接着调用该类的parse方法。

二、AOP Bean定义加载(根据织入方式将<aop:before>转换成名为adviceDef的RootBeanDefinition)

接着分析,查看ConfigBeanDefinitionParser类的parse方法,如下:

/** * element : 就是<aop:config>标签元素对象 */ @Override @Nullable public BeanDefinition parse(Element element, ParserContext parserContext) { CompositeComponentDefinition compositeDef = new CompositeComponentDefinition(element.getTagName(), parserContext.extractSource(element)); parserContext.pushContainingComponent(compositeDef); // 向IoC容器中注册AspectJAwareAdvisorAutoProxyCreator类的BeanDefinition:(用于创建AOP代理对象的) // BeanPostProcessor可以对实例化之后的bean进行一些操作 // AspectJAwareAdvisorAutoProxyCreator 实现了BeanPostProcessor接口,可以对目标对象实例化之后,创建对应的代理对象 configureAutoProxyCreator(parserContext, element); // 获取<aop:config>标签的子标签<aop:aspect>、<aop:advisor> 、<aop:pointcut> 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); } } parserContext.popAndRegisterContainingComponent(); return null; }

分析上述代码,查看第28行,该方法是处理<aop:config>下的节点为<aop:aspect>,查看源码:

private void parseAspect(Element aspectElement, ParserContext parserContext) { // 获取<aop:aspect>标签的id属性值 String aspectId = aspectElement.getAttribute(ID); // 获取<aop:aspect>标签的ref属性值 String aspectName = aspectElement.getAttribute(REF); try { this.parseState.push(new AspectEntry(aspectId, aspectName)); List<BeanDefinition> beanDefinitions = new ArrayList<>(); List<BeanReference> beanReferences = new ArrayList<>(); // 处理<aop:declare-parents>标签 List<Element> declareParents = DomUtils.getChildElementsByTagName(aspectElement, DECLARE_PARENTS); 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. // 获取<aop:aspect>标签的所有子标签 NodeList nodeList = aspectElement.getChildNodes(); boolean adviceFoundAlready = false; for (int i = 0; i < nodeList.getLength(); i++) { Node node = nodeList.item(i); // 判断是否是<aop:before>、<aop:after>、<aop:after-returning>、<aop:after-throwing method="">、<aop:around method="">这五个标签 if (isAdviceNode(node, parserContext)) { if (!adviceFoundAlready) { adviceFoundAlready = true; if (!StringUtils.hasText(aspectName)) { parserContext.getReaderContext().error( "<aspect> tag needs aspect bean reference via 'ref' attribute when declaring advices.", aspectElement, this.parseState.snapshot()); return; } beanReferences.add(new RuntimeBeanReference(aspectName)); } //方法主要做了三件事: // 1、根据织入方式(before、after这些)创建RootBeanDefinition,名为adviceDef即advice定义 // 2、将上一步创建的RootBeanDefinition写入一个新的RootBeanDefinition,构造一个新的对象,名为advisorDefinition,即advisor定义 // 3、将advisorDefinition注册到DefaultListableBeanFactory中 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); // 得到所有<aop:aspect>下的<aop:pointcut>子标签 List<Element> pointcuts = DomUtils.getChildElementsByTagName(aspectElement, POINTCUT); for (Element pointcutElement : pointcuts) { // 解析<aop:pointcut>子标签 parsePointcut(pointcutElement, parserContext); } parserContext.popAndRegisterContainingComponent(); } finally { this.parseState.pop(); } }

接着进入第43行的parseAdvice方法

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 // 创建方法工厂Bean的BeanDefinition对象:用于获取Method对象 RootBeanDefinition methodDefinition = new RootBeanDefinition(MethodLocatingFactoryBean.class); methodDefinition.getPropertyValues().add("targetBeanName", aspectName); methodDefinition.getPropertyValues().add("methodName", adviceElement.getAttribute("method")); methodDefinition.setSynthetic(true); // create instance factory definition // 创建实例工厂BeanDefinition:用于创建增强类的实例 RootBeanDefinition aspectFactoryDef = new RootBeanDefinition(SimpleBeanFactoryAwareAspectInstanceFactory.class); aspectFactoryDef.getPropertyValues().add("aspectBeanName", aspectName); aspectFactoryDef.setSynthetic(true); //以上的两个BeanDefinition的作用主要是应用在以下这行代码 // method.invoke(obj,args) // register the pointcut // 通知增强类的BeanDefinition对象(核心) AbstractBeanDefinition adviceDef = createAdviceDefinition( adviceElement, parserContext, aspectName, order, methodDefinition, aspectFactoryDef, beanDefinitions, beanReferences); // configure the advisor // 通知器类的BeanDefinition对象 RootBeanDefinition advisorDefinition = new RootBeanDefinition(AspectJPointcutAdvisor.class); advisorDefinition.setSource(parserContext.extractSource(adviceElement)); advisorDefinition.getConstructorArgumentValues().addGenericArgumentValue(adviceDef); if (aspectElement.hasAttribute(ORDER_PROPERTY)) { advisorDefinition.getPropertyValues().add( ORDER_PROPERTY, aspectElement.getAttribute(ORDER_PROPERTY)); } // register the final advisor // 将advisorDefinition注册到IoC容器中 parserContext.getReaderContext().registerWithGeneratedName(advisorDefinition); return advisorDefinition; } finally { this.parseState.pop(); } }

接着进入第27行的createAdviceDefinition方法:

private AbstractBeanDefinition createAdviceDefinition( Element adviceElement, ParserContext parserContext, String aspectName, int order, RootBeanDefinition methodDef, RootBeanDefinition aspectFactoryDef, List<BeanDefinition> beanDefinitions, List<BeanReference> beanReferences) { // 根据通知类型的不同,分别创建对应的BeanDefinition对象(可以去看看getAdviceClass方法) RootBeanDefinition adviceDefinition = new RootBeanDefinition(getAdviceClass(adviceElement, parserContext)); adviceDefinition.setSource(parserContext.extractSource(adviceElement)); // 为不同的增强通知类,添加统一的属性值 adviceDefinition.getPropertyValues().add(ASPECT_NAME_PROPERTY, aspectName); adviceDefinition.getPropertyValues().add(DECLARATION_ORDER_PROPERTY, order); // 为不同的增强通知类,添加对应的属性值 if (adviceElement.hasAttribute(RETURNING)) { adviceDefinition.getPropertyValues().add( RETURNING_PROPERTY, adviceElement.getAttribute(RETURNING)); } if (adviceElement.hasAttribute(THROWING)) { adviceDefinition.getPropertyValues().add( THROWING_PROPERTY, adviceElement.getAttribute(THROWING)); } if (adviceElement.hasAttribute(ARG_NAMES)) { adviceDefinition.getPropertyValues().add( ARG_NAMES_PROPERTY, adviceElement.getAttribute(ARG_NAMES)); } // 获取构造器参数值 ConstructorArgumentValues cav = adviceDefinition.getConstructorArgumentValues(); // 设置第一个构造参数:方法工厂对象的BeanDefinition cav.addIndexedArgumentValue(METHOD_INDEX, methodDef); // 解析<aop:before>、<aop:after>、<aop:after-returning>标签中的pointcut或者pointcut-ref属性 Object pointcut = parsePointcutProperty(adviceElement, parserContext); // 设置第二个构造参数:切入点BeanDefinition 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); } // 设置第三个构造参数:实例工厂BeanDefinition cav.addIndexedArgumentValue(ASPECT_INSTANCE_FACTORY_INDEX, aspectFactoryDef); return adviceDefinition; }

分析上述代码:第7行,根据切入方式的不同,分别创建对应的BeanDefinition对象。 before对应AspectJMethodBeforeAdvice After对应AspectJAfterAdvice after-returning对应AspectJAfterReturningAdvice after-throwing对应AspectJAfterThrowingAdvice around对应AspectJAroundAdvice

到这里为止,aop:before标签对应的AbstractBeanDefinition创建成功。

三、AOP Bean定义加载(包装名为adviceDef的RootBeanDefinition 成 名字为advisorDefinition的RootBeanDefinition)

回来看ConfigBeanDefinitionParser类parseAdvice方法:

// 通知器类的BeanDefinition对象 RootBeanDefinition advisorDefinition = new RootBeanDefinition(AspectJPointcutAdvisor.class); advisorDefinition.setSource(parserContext.extractSource(adviceElement)); advisorDefinition.getConstructorArgumentValues().addGenericArgumentValue(adviceDef); if (aspectElement.hasAttribute(ORDER_PROPERTY)) { advisorDefinition.getPropertyValues().add( ORDER_PROPERTY, aspectElement.getAttribute(ORDER_PROPERTY)); }

分析上述代码:第4行创建新的名字为advisorDefinition的RootBeanDefinition类。第5行是用于判断aop:aspect标签中是否存在"order"属性的(用来控制切入方法优先级的)。

四、AOP Bean定义加载(AopNamespaceHandler处理<aop:pointcut>标签)

接着看ConfigBeanDefinitionParser类parseAdvice方法中的处理<aop:pointcut>标签的代码:

// 得到所有<aop:aspect>下的<aop:pointcut>子标签 List<Element> pointcuts = DomUtils.getChildElementsByTagName(aspectElement, POINTCUT); for (Element pointcutElement : pointcuts) { // 解析<aop:pointcut>子标签 parsePointcut(pointcutElement, parserContext); }

进入第5行的parsePointcut方法:

private AbstractBeanDefinition parsePointcut(Element pointcutElement, ParserContext parserContext) { String id = pointcutElement.getAttribute(ID); String expression = pointcutElement.getAttribute(EXPRESSION); AbstractBeanDefinition pointcutDefinition = null; try { this.parseState.push(new PointcutEntry(id)); // 此处创建一个AspectJExpressionPointcut类对应的BeanDefinition对象,处理pointcut pointcutDefinition = createPointcutDefinition(expression); pointcutDefinition.setSource(parserContext.extractSource(pointcutElement)); String pointcutBeanName = id; // 如果配置id属性,则走下面代码 if (StringUtils.hasText(pointcutBeanName)) { parserContext.getRegistry().registerBeanDefinition(pointcutBeanName, pointcutDefinition); } // 如果没有配置id属性,则走下面代码 else { pointcutBeanName = parserContext.getReaderContext().registerWithGeneratedName(pointcutDefinition); } parserContext.registerComponent( new PointcutComponentDefinition(pointcutBeanName, pointcutDefinition, expression)); } finally { this.parseState.pop(); } return pointcutDefinition; }

进入第10行代码的createPointcutDefinition方法:

protected AbstractBeanDefinition createPointcutDefinition(String expression) { RootBeanDefinition beanDefinition = new RootBeanDefinition(AspectJExpressionPointcut.class); beanDefinition.setScope(BeanDefinition.SCOPE_PROTOTYPE); beanDefinition.setSynthetic(true); beanDefinition.getPropertyValues().add(EXPRESSION, expression); return beanDefinition; }

分析上述代码:<aop:pointcut>标签对应解析出来的BeanDefinition是RootBeanDefinition,且RootBenaDefinitoin中的Class是org.springframework.aop.aspectj.AspectJExpressionPointcut,且RootBeanDefinition对应的Bean被定义成原型。

转载请注明原文地址: https://www.6miu.com/read-5030270.html

最新回复(0)