博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Spring事务源码梳理1----事务配置解析及切面织入
阅读量:6123 次
发布时间:2019-06-21

本文共 9008 字,大约阅读时间需要 30 分钟。

hot3.png

基于注解, 首先,我们会在配置文件中使用如下的配置来开启Spring事务注解配置.

当Spring解析配置文件的这一行时,发现元素的命名空间不是  则会

调用 BeanDefinitionParserDelegate.parseCustomElement() 方法来解析, 该方法的内部又是调用的下面方法来处理的

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));//调用处理器来处理元素, 内部会从map中获取对应的bean处理器来处理, 见后面说明}

在这里可以看到,是通过 this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri); 来获取对应的处理器, 具体代码继续跟踪

最后是调用DefaultNamespaceHandlerResolver.resolve(namespaceUri)方法来实现的, 

该方法内部通过查找classpath下面的/META-INF/spring.handlers属性文件来找到命名空间和处理器的对应关系, 

比如说在spring-tx的jar包中,可以看到/META-INF/spring.handlers的内容为

http\://www.springframework.org/schema/tx=org.springframework.transaction.config.TxNamespaceHandler

于是, 我们知道了, tx这个命名空间对应的命名空间处理器是 TxNamespaceHandler 我们来看它的代码

public class TxNamespaceHandler extends NamespaceHandlerSupport {	static final String TRANSACTION_MANAGER_ATTRIBUTE = "transaction-manager";	static final String DEFAULT_TRANSACTION_MANAGER_BEAN_NAME = "transactionManager";	static String getTransactionManagerName(Element element) {		return (element.hasAttribute(TRANSACTION_MANAGER_ATTRIBUTE) ?				element.getAttribute(TRANSACTION_MANAGER_ATTRIBUTE) : DEFAULT_TRANSACTION_MANAGER_BEAN_NAME);	}	public void init() {		registerBeanDefinitionParser("advice", new TxAdviceBeanDefinitionParser());		registerBeanDefinitionParser("annotation-driven", new AnnotationDrivenBeanDefinitionParser());		registerBeanDefinitionParser("jta-transaction-manager", new JtaTransactionManagerBeanDefinitionParser());	}}

代码很简单 NamespaceHandlerResolver 找到处理器后, 会反射创建实例, 然后调用init方法, 我们继续看看 registerBeanDefinitionParser做了什么处理

这个方法主要是将bean定义处理器加入到一个map中, 然后在 parse 方法中, 会根据名字去找到对应的bean定义处理器, 然后调用 处理器的parse方法

public BeanDefinition parse(Element element, ParserContext parserContext) {        //findParserForElement 在map中找到对应的bean定义处理器, 然后调用 parse	return findParserForElement(element, parserContext).parse(element, parserContext);}

这里 TxNamespaceHandler 注册了三个bean定义处理器 分别是 TxAdviceBeanDefinitionParser AnnotationDrivenBeanDefinitionParser JtaTransactionManagerBeanDefinitionParser

分别对应于 tx:advice    tx:annotation-driven    tx:jta-transaction-manager   这里我们用的注解, 所以来看看 AnnotationDrivenBeanDefinitionParser.parse() 做了啥. 具体代码如下

public BeanDefinition parse(Element element, ParserContext parserContext) {	String mode = element.getAttribute("mode");	if ("aspectj".equals(mode)) {		registerTransactionAspect(element, parserContext);// mode="aspectj"	} else {	        //对应配置文件中mode属性, 默认值proxy		AopAutoProxyConfigurer.configureAutoProxyCreator(element, parserContext); // mode="proxy"	}	return null;}

可以看到, 具体的逻辑在 AopAutoProxyConfigurer.configureAutoProxyCreator() 中, 通过名字可以看出, 和AOP有关, 代码如下

public static void configureAutoProxyCreator(Element element, ParserContext parserContext) {    //这里配置org.springframework.aop.config.internalAutoProxyCreator这个bean的exposeProxy属性为true,这个bean用来创建代理的 对应 xml里面 tx: proxy-target-class="true" 属性设置      //(如果配置了
, 这个bean类型就是AnnotationAwareAspectJAutoProxyCreator)    AopNamespaceUtils.registerAutoProxyCreatorIfNecessary(parserContext, element);    String txAdvisorBeanName = TransactionManagementConfigUtils.TRANSACTION_ADVISOR_BEAN_NAME;    if (!parserContext.getRegistry().containsBeanDefinition(txAdvisorBeanName)) {        Object eleSource = parserContext.extractSource(element);        // Create the TransactionAttributeSource definition.        //AnnotationTransactionAttributeSource 主要是用来解析注解属性 继承自AbstractFallbackTransactionAttributeSource        //主要作用就是解析方法注解, 将事物属性封装成对象缓存起来, 然后如果方法上没注解就去类上或者接口上找~~~        RootBeanDefinition sourceDef = new RootBeanDefinition("org.springframework.transaction.annotation.AnnotationTransactionAttributeSource");        sourceDef.setSource(eleSource);        sourceDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);        String sourceName = parserContext.getReaderContext().registerWithGeneratedName(sourceDef);        // Create the TransactionInterceptor definition.        //TransactionInterceptor 一看名字就知道是拦截方法的, 通过拦截方法的调用, 处理事务        RootBeanDefinition interceptorDef = new RootBeanDefinition(TransactionInterceptor.class);        interceptorDef.setSource(eleSource);        interceptorDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);        registerTransactionManager(element, interceptorDef);//这里通过bean name关联事务管理器        interceptorDef.getPropertyValues().add("transactionAttributeSource", new RuntimeBeanReference(sourceName));        String interceptorName = parserContext.getReaderContext().registerWithGeneratedName(interceptorDef);        // Create the TransactionAttributeSourceAdvisor definition.        //BeanFactoryTransactionAttributeSourceAdvisor 事务AOP配置 Pointcut:TransactionAttributeSourcePointcut, advice: TransactionInterceptor         RootBeanDefinition advisorDef = new RootBeanDefinition(BeanFactoryTransactionAttributeSourceAdvisor.class);        advisorDef.setSource(eleSource);        advisorDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);        advisorDef.getPropertyValues().add("transactionAttributeSource", new RuntimeBeanReference(sourceName));        advisorDef.getPropertyValues().add("adviceBeanName", interceptorName);//关联TransactionInterceptor        if (element.hasAttribute("order")) {            advisorDef.getPropertyValues().add("order", element.getAttribute("order"));        }        parserContext.getRegistry().registerBeanDefinition(txAdvisorBeanName, advisorDef);        CompositeComponentDefinition compositeDef = new CompositeComponentDefinition(element.getTagName(), eleSource);        compositeDef.addNestedComponent(new BeanComponentDefinition(sourceDef, sourceName));        compositeDef.addNestedComponent(new BeanComponentDefinition(interceptorDef, interceptorName));        compositeDef.addNestedComponent(new BeanComponentDefinition(advisorDef, txAdvisorBeanName));        parserContext.registerComponent(compositeDef);    }}

在这个方法中, 想Spring容器注册了三个bean定义:

一个是 AnnotationTransactionAttributeSource 主要是解析方法或类上的事务注解,封装成对应对象缓存

一个是 TransactionInterceptor 实现 MethodInterceptor 接口, 负责拦截指定方法, 处理事务(方法调用前获取连接,开启事务,方法调用后提交或回滚事务等等)

一个是 BeanFactoryTransactionAttributeSourceAdvisor 固定bean name 为 "org.springframework.transaction.config.internalTransactionAdvisor" 实现了Advisor接口

并通过名字引用了 TransactionInterceptor(Advice) , 且该类内部包含了  TransactionAttributeSourcePointcut (Pointcut)

OK 到这里, 事务的切面已经配置好了, 接下来要看Spring是怎么创建代理的吧. 前面注释中有说, 

如果配置了<aop:aspectj-autoproxy proxy-target-class="true" />, Spring就会注册一个bean定义 : AnnotationAwareAspectJAutoProxyCreator

这个类是实现了 BeanPostProcessor 在bean实例创建后, 会调用 BeanPostProcessor.postProcessAfterInitialization 方法来创建代理对象返回

在创建bean实例成功后, Spring自动调用所有实现了 BeanPostProcessor 接口的 bean 的 postProcessAfterInitialization 方法, 而AnnotationAwareAspectJAutoProxyCreator重写了该方法, 具体如下

//bean初始化成功, 参数, bean:bean实例 beanName:bean在Spring容器中的名字public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {	if (bean != null) {		Object cacheKey = getCacheKey(bean.getClass(), beanName);		//如果之前调用过getEarlyBeanReference获取包装目标对象到AOP代理对象(如果需要),则不再执行  		//getEarlyBeanReference 也是创建代理对象, 主要是通过代理来解决循环引用问题		if (!this.earlyProxyReferences.containsKey(cacheKey)) {			return wrapIfNecessary(bean, beanName, cacheKey);//创建代理对象		}	}	return bean;}

可以看到, 主要是wrapIfNecessary方法, 继续跟踪

protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {    // Create proxy if we have advice. //注释说的很明白了,如果偶们有advice就创建代理    Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);    if (specificInterceptors != DO_NOT_PROXY) {        this.advisedBeans.put(cacheKey, Boolean.TRUE);        Object proxy = createProxy(bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));//创建代理        this.proxyTypes.put(cacheKey, proxy.getClass());        return proxy;    }}

getAdvicesAndAdvisorsForBean方法内部通过内部在容器中找出所有的Advisor类型的bean,  然后根据条件来判断是否对当前bean应用Advisor.

这里事务是通过TransactionAttributeSourcePointcut继承而来的matches方法来判断, 而这个方法内部又是调用AnnotationTransactionAttributeSource的方法(判断是不是能取到事务配置).

源码大概路径是:

1.调用AbstractAdvisorAutoProxyCreator.findEligibleAdvisors()方法

    1.1调用AbstractAdvisorAutoProxyCreator.findCandidateAdvisors()方法, 具体就是通过Advisor.class在bean工厂中找到所有匹配的bean

    1.2调用AbstractAdvisorAutoProxyCreator.findAdvisorsThatCanApply()方法, 过滤掉不匹配的Advisor(具体过滤方法是调用AOPUtils.findAdvisorsThatCanApply()方法)

    1.3 AOPUtils.findAdvisorsThatCanApply() 方法内部又是通过调用TransactionAttributeSourcePointcut.getClassFilter().matches(targetClass)和getMethodMatcher().matches(method, targetClass)

          来过滤掉不符合的advisor.

2.调用AbstractAutoProxyCreator.createProxy()方法创建代理

到这里, 我们已经获取到了, 被作用了事务代理功能的bean实例, 接下来就是 方法调用的处理逻辑了. 博客字数限制, 下一篇再继续写.

转载于:https://my.oschina.net/haogrgr/blog/308199

你可能感兴趣的文章
2015第31周日
查看>>
在使用EF开发时候,遇到 using 语句中使用的类型必须可隐式转换为“System.IDisposable“ 这个问题。...
查看>>
Oracle 如何提交手册Cluster Table事务
查看>>
BeagleBone Black第八课板:建立Eclipse编程环境
查看>>
在服务器上用Fiddler抓取HTTPS流量
查看>>
文件类似的推理 -- 超级本征值(super feature)
查看>>
【XCode7+iOS9】http网路连接请求、MKPinAnnotationView自定义图片和BitCode相关错误--备用...
查看>>
各大公司容器云的技术栈对比
查看>>
记一次eclipse无法启动的排查过程
查看>>
【转】jmeter 进行java request测试
查看>>
读书笔记--MapReduce 适用场景 及 常见应用
查看>>
SignalR在Xamarin Android中的使用
查看>>
Eclipse和MyEclipse使用技巧--Eclipse中使用Git-让版本管理更简单
查看>>
[转]响应式表格jQuery插件 – Responsive tables
查看>>
8个3D视觉效果的HTML5动画欣赏
查看>>
C#如何在DataGridViewCell中自定义脚本编辑器
查看>>
【linux】crontab定时命令
查看>>
Android UI优化——include、merge 、ViewStub
查看>>
Office WORD如何取消开始工作右侧栏
查看>>
Android Jni调用浅述
查看>>