主要目的为了解决如下问题:
spring是如何使用aop来实现声明式事务管理的?
为了解决上面这个问题,需解决如下两个问题:
1.spring如何解析xml文件中关于事务配置标签?
2.代码执行时aop是如何进行事务管理的?
本文主要解决第一个问题。
1.spring如何解析xml文件中关于事务配置标签?
对于spring xml文件的解析,我们要分析的代码片断为:
ClassPathXmlApplicationContext context=new ClassPathXmlApplicationContext("/com/test/spring.xml");
而对应的spring.xml内容片断为:
后文主要分析spring如何解析xml文件,并生成相应的bean数据结构BeanDefinition.阅读时,带着一个问题。
spring xml中配置的bean是如何加载进spring容器的?
我们先查看spring解析标签代码,再查看解析标签代码.spring代码版本v.4.2.4.RELEASE.
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 elements will cause recursion in this method. In
// order to propagate and preserve 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如何进行事务拦截。