背景
主要目的为了解决如下问题:
spring是如何使用aop来实现声明式事务管理的?
为了解决上面这个问题,需解决如下两个问题:
1.spring如何解析xml文件中关于事务配置标签?
2.代码执行时aop是如何进行事务管理的?
本文主要解决第一个问题。
1.spring如何解析xml文件中关于事务配置标签?
准备spring xml文件解析
对于spring xml文件的解析,我们要分析的代码片断为:
ClassPathXmlApplicationContext context=new ClassPathXmlApplicationContext("/com/test/spring.xml");
而对应的spring.xml内容片断为:
<aop:config>
<aop:pointcut id="interceptorPointCuts"
expression="execution(* com.test..srv.impl.*.*(..))" />
<aop:advisor advice-ref="txAdvice" pointcut-ref="interceptorPointCuts" />
</aop:config>
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="add*" propagation="REQUIRED" rollback-for="Exception" />
<tx:method name="del*" propagation="REQUIRED" rollback-for="Exception" />
<tx:method name="save*" propagation="REQUIRED"
rollback-for="Exception" />
<tx:method name="update*" propagation="REQUIRED"
rollback-for="Exception" />
<tx:method name="do*" propagation="REQUIRED" rollback-for="Exception" />
</tx:attributes>
</tx:advice>
后文主要分析spring如何解析xml文件,并生成相应的bean数据结构BeanDefinition.阅读时,带着一个问题。
spring xml中配置的bean是如何加载进spring容器的?
我们先查看spring解析标签代码,再查看解析标签代码.spring代码版本v.4.2.4.RELEASE.
- ClassPathXmlApplicationContext 构造器
ClasspathXmlApplicationContext.refresh()
这个方法很重要,它是spring启动的整个过程,我们现在只分析它是如何完成bean加载这一步 // Tell the subclass to refresh the internal bean factory. ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
AbstractApplicationContext.obtainFreshBeanFactory
这个方法最后返回一个ConfigurableListableBeanFactory实现的实例,我们所有的bean最终都被装载进这个容器中,那么下面继续.
AbstractApplicationContext.refreshBeanFactory()
AbstractRefreshableApplicationContext.refreshBeanFactory
在这个方法中我们实例化一个DefaultListableBeanFactory实例,它的类定义
public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory
implements ConfigurableListableBeanFactory, BeanDefinitionRegistry, Serializable
在此需要注意一下BeanDefinitionRegistry这个接口,它的作用即可以动态的向容器注册相应的bean,正是由于这个接口,我们在后面才可以将相应的bean注册到DefaultListableBeanFactory容器实例中。
AbstractRefreshableApplicationContext.loadBeanDefinition
AbstractXmlApplicationContext.loadBeanDefinition(实现)
将xml文件读取工作转嫁给 XmlBeanDefinitionReader
AbstractXmlApplicationContext.loadBeanDefinitions
在这里循环读取每个的Resource;
AbstractBeanDefinitionReader.loadBeanDefinitions(String …locations)
AbstractBeanDefinitionReader.loadBeanDefinitions(String location)
AbstractBeanDefinitionReader.loadBeanDefinitions(String location,Set actualResource)
AbstractBeanDefinitionReader.loadBeanDefinitions(Resource… resources)
XmlBeanDefinitionReader.loadBeanDefinitions(Resource resource)
XmlBeanDefinitionReader.loadBeanDefinitions(EncodedREsource encodedResource)
这个方法通过流读取相应的Resource加载相应的bean
XmlBeanDefinitionReader.doLoadBeanDefinitions(InputSource inputSource,Resource resource)
使用w3c api解析xml文件,部分代码: protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource) throws BeanDefinitionStoreException { try { Document doc = doLoadDocument(inputSource, resource); return registerBeanDefinitions(doc, resource); } // n多异常catch代码省略
}
XmlBeanDefinitionReader.registerBeanDefinitions(Document doc,Resource resource)
将工作转嫁给 BeanDefinitionDocumentReader
public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
int countBefore = getRegistry().getBeanDefinitionCount();
documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
return getRegistry().getBeanDefinitionCount() - countBefore;
}
BeanDefinitionDocumentReader.registerBeanDefinitions(Document doc,XmlReaderContext readerContxt)
DefaultBeanDefinitionDocumentReader.registerBeanDefinitions(Document doc,XmlReaderContext readerContxt)
DefaultBeanDefinitionDocumentReader.doRegisterBeanDefinitions(Element root)
将工作转嫁给 BeanDefinitionParserDelegate protected void doRegisterBeanDefinitions(Element root) { // Any nested <beans> elements will cause recursion in this method. In // order to propagate and preserve <beans> default-* attributes correctly, // keep track of the current (parent) delegate, which may be null. Create // the new (child) delegate with a reference to the parent for fallback purposes, // then ultimately reset this.delegate back to its original (parent) reference. // this behavior emulates a stack of delegates without actually necessitating one. BeanDefinitionParserDelegate parent = this.delegate; this.delegate = createDelegate(getReaderContext(), root, parent); if (this.delegate.isDefaultNamespace(root)) { String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE); if (StringUtils.hasText(profileSpec)) { String[] specifiedProfiles = StringUtils.tokenizeToStringArray( profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS); if (!getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) { return; } } } preProcessXml(root); parseBeanDefinitions(root, this.delegate); postProcessXml(root); this.delegate = parent; }
DefaultBeanDefinitionDocumentReader.parseBeanDefinitions(Element root,BeanDefinitionParserDelegate delegate)
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); } }
解析则在此分流,对于默认namespace(默认namespace指是的beans),则调用 parseDefaultElement;否则调用delegate.parseCustomElement.由于我们要了解 等事务的配置,所以在此我们跟进delegate.parseCustomElement方法.
BeanDefinitionParserDelegate.parseCustomElement(Element ele)
BeanDefinitionParserDelegate.parseCustomElement(Element ele,BeanDefition containingBd);
public BeanDefinition parseCustomElement(Element ele, BeanDefinition containingBd) { String namespaceUri = getNamespaceURI(ele); 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)); }
在这个方法,获取相应的namespace的 NamespaceHandler 进行xml文件解析,也正是这个方法解决了spring不同namespace的标签的Handler.现在将工作转嫁给相应的 NamespaceHandler,我现在想了解 是如何解析,所以相应的NamespaceHandler为 AopNamespaceHandler.
AopNamespaceHandler.init()
在AopNamespaceHandler的init方法, 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()); } 对于 config标签,应用ConfigBeanDefinitionParser
ConfigBeanDefinitionParser.parse(Element element,ParserContext parserContext)
ConfigBeanDefinitionParser.configureAutoProxyCreator(ParserContext parserContext,Element element)这个方法注入一个AspectJAwareAdvisorAutoProxyCreator bean至DefaultListableBeanFactory实例,它的作用是自动装载aop切面。
对于 标签使用ConfigBeanDefinitionParser.parsePointcut(Element pointcutElement,ParserContext parserContext)方法解析,并注入DefaultListableBeanFactory.同理解析解析,等标签。
同样对于节点,我们可以找到相应的 NamespaceHandler,对于对应的TxNamespaceHandler.
TxNamespaceHandler.init方法
@Override public void init() { registerBeanDefinitionParser("advice", new TxAdviceBeanDefinitionParser()); registerBeanDefinitionParser("annotation-driven", new AnnotationDrivenBeanDefinitionParser()); registerBeanDefinitionParser("jta-transaction-manager", new JtaTransactionManagerBeanDefinitionParser()); }
TxAdviceBeanDefinitionParser.parse()
这个方法实现在其父类AbstractBeanDefinitionParser中AbstractBeanDefinitionParser.parse()
AbstractBeanDefinitionParser.parseInternal(Element element, ParserContext parserContext)
AbstractSingleBeanDefinitionParser.parseInternal(Element element, ParserContext parserContext)
AbstractSingleBeanDefinitionParser.getBeanClass(Element element)
这个方法在子类中被重写TxAdviceBeanDefinitionParser.getBeanClass(Element element)
@Override protected Class<?> getBeanClass(Element element) { return TransactionInterceptor.class; } TransactionInterceptor的类定义 @SuppressWarnings("serial") public class TransactionInterceptor extends TransactionAspectSupport implements MethodInterceptor, Serializable 我们可看到这是一个环绕通知,关于这个类的内容后续再分析。
至此我们已经了解了spring是如何解析xml,并生成相应的aop所需要的bean.这里只是粗略的了解了 spring是如何加载 bean,对于每个bean细细解析,只能自己去看源代码了。下一篇我们详细看一下TransactionInterceptor如何进行事务拦截。