spring源码学习系列1-spring事务代理深入分析

本文主要分析spring事务代理的源码,跟踪代码,了解事务代理的生命周期




1.学习资料和书籍

2.代理的生成(原理)

3.代理的使用-使用中遇到的常见问题


涉及的源码类:
org.springframework.aop.config.AopNamespaceUtils

org.springframework.aop.config.AopConfigUtils

org.springframework.aop.framework.autoproxy.InfrastructureAdvisorAutoProxyCreator

org.springframework.aop.framework.ProxyConfig

org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator

org.springframework.aop.support.AopUtils

org.springframework.aop.framework.ProxyFactory

org.springframework.transaction.config.TxNamespaceHandler

org.springframework.transaction.config.AnnotationDrivenBeanDefinitionParser

org.springframework.transaction.annotation.AnnotationTransactionAttributeSource

org.springframework.transaction.interceptor.TransactionInterceptor

org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction

org.springframework.transaction.interceptor.BeanFactoryTransactionAttributeSourceAdvisor



1.学习资料和书籍
grepcode源码及相关博客


2.代理的生成

涉及事务代理的spring元素及特性:


xml配置:
2.1 <tx:annotation-driven transaction-manager="transactionManager" />

当XML中存在“<tx:annotation-driven/>”时,命名空间为tx。从相关的jar包(如spring-tx.jar)中可查看标签处理类。从配置文件spring.handlers中查找到的NamespaceHandler为org.springframework.transaction.config.TxNamespaceHandler
。由TxNamespaceHandler负责具体的解析tx命名空间
部分代码如下:
static final String TRANSACTION_MANAGER_ATTRIBUTE = "transaction-manager";
static final String DEFAULT_TRANSACTION_MANAGER_BEAN_NAME = "transactionManager";
public void init() {
  registerBeanDefinitionParser("advice", new TxAdviceBeanDefinitionParser());
  registerBeanDefinitionParser("annotation-driven", new AnnotationDrivenBeanDefinitionParser());
  registerBeanDefinitionParser("jta-transaction-manager", new JtaTransactionManagerBeanDefinitionParser());
}


解析annotation-driven的类为org.springframework.transaction.config.AnnotationDrivenBeanDefinitionParser,源码可查看如下:

http://grepcode.com/file/repository.springsource.com/org.springframework/org.springframework.transaction/3.2.2/org/springframework/transaction/config/AnnotationDrivenBeanDefinitionParser.java?av=f

部分源码如下:
public static final String TRANSACTION_ADVISOR_BEAN_NAME =
			"org.springframework.transaction.config.internalTransactionAdvisor";



AnnotationDrivenBeanDefinitionParser#parse
public BeanDefinition parse(Element element, ParserContext parserContext) {
		String mode = element.getAttribute("mode");
		if ("aspectj".equals(mode)) {
			// mode="aspectj"
			registerTransactionAspect(element, parserContext);
		}
		else {
			// mode="proxy"
			AopAutoProxyConfigurer.configureAutoProxyCreator(element, parserContext);
		}
		return null;
	}


查看spring-tx-3.0.xsd可知,mode=proxy。内部类AopAutoProxyConfigurer为实际代理模式下引入aop框架,部分代码如下:






AopAutoProxyConfigurer.configureAutoProxyCreator方法分析:事务定义的入口
AnnotationDrivenBeanDefinitionParser.AopAutoProxyConfigurer#configureAutoProxyCreator
public static void configureAutoProxyCreator(Element element, ParserContext parserContext) {
			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.
				RootBeanDefinition sourceDef = new RootBeanDefinition(AnnotationTransactionAttributeSource.class);
				sourceDef.setSource(eleSource);
				sourceDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
				String sourceName = parserContext.getReaderContext().registerWithGeneratedName(sourceDef);

				// Create the TransactionInterceptor definition.
				RootBeanDefinition interceptorDef = new RootBeanDefinition(TransactionInterceptor.class);
				interceptorDef.setSource(eleSource);
				interceptorDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
				registerTransactionManager(element, interceptorDef);
				interceptorDef.getPropertyValues().add("transactionAttributeSource", new RuntimeBeanReference(sourceName));
				String interceptorName = parserContext.getReaderContext().registerWithGeneratedName(interceptorDef);

				// Create the TransactionAttributeSourceAdvisor definition.
				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);
				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);
			}
		}





创建InfrastructureAdvisorAutoProxyCreator的beanDefinition
a.定义后置处理器(InfrastructureAdvisorAutoProxyCreator)- 根据配置信息,定义生成代理的入口

AopNamespaceUtils.registerAutoProxyCreatorIfNecessary(parserContext, element);  

创建事务代理的后置处理器InfrastructureAdvisorAutoProxyCreator






----------------------代码直译start----------------------
第一行:创建名为AUTO_PROXY_CREATOR_BEAN_NAME=org.springframework.aop.config.internalAutoProxyCreator的后置处理器InfrastructureAdvisorAutoProxyCreator( 实现了BeanPostProcessor),且名为AUTO_PROXY_CREATOR_BEAN_NAME的后置处理器只有一个

尚未注册,第三行注册


第二行:给AUTO_PROXY_CREATOR_BEAN_NAME设置属性
解析
PROXY_TARGET_CLASS_ATTRIBUTE = "proxy-target-class"
EXPOSE_PROXY_ATTRIBUTE = "expose-proxy"
设置后置处理器相关属性值
proxyTargetClass=true或
exposeProxy=true
(这2个属性在org.springframework.aop.framework.ProxyConfig中)

第三行:注册到容器
----------------------代码直译end----------------------


InfrastructureAdvisorAutoProxyCreator源码:
http://grepcode.com/file/repository.springsource.com/org.springframework/org.springframework.aop/3.2.2/org/springframework/aop/framework/autoproxy/InfrastructureAdvisorAutoProxyCreator.java#InfrastructureAdvisorAutoProxyCreator

AbstractAdvisorAutoProxyCreator源码:
http://grepcode.com/file/repository.springsource.com/org.springframework/org.springframework.aop/3.2.2/org/springframework/aop/framework/autoproxy/AbstractAdvisorAutoProxyCreator.java#AbstractAdvisorAutoProxyCreator

AbstractAutoProxyCreator源码:
http://grepcode.com/file/repository.springsource.com/org.springframework/org.springframework.aop/3.2.2/org/springframework/aop/framework/autoproxy/AbstractAutoProxyCreator.java#AbstractAutoProxyCreator

执行InfrastructureAdvisorAutoProxyCreator
a.1 AbstractApplicationContext.refresh- 执行生成代理的入口,调用以上定义的入口生成代理

单一职责原则: AbstractAutoProxyCreator.postProcessAfterInitialization(Object bean, String beanName)(有图可知AbstractAutoProxyCreator为InfrastructureAdvisorAutoProxyCreator祖先类,祖先类中定义了模板方法),继续调用wrapIfNecessary方法

在实例化bean后,调用初始化方法后执行

该方法中:
(1)获取拦截器主要在后置处理器中完成 (2)创建代理委托给ProxyFactory完成

(1) 首先查找所有符合条件的Advisor类型的类(抽象方法:getAdvicesAndAdvisorsForBean)。
该任务委托由AbstractAdvisorAutoProxyCreator.getAdvicesAndAdvisorsForBean完成(有图可知 AbstractAdvisorAutoProxyCreator为AbstractAutoProxyCreator的子类,InfrastructureAdvisorAutoProxyCreator的父类),继续调用findEligibleAdvisors,在该方法中,

(1.1)首先调用findCandidateAdvisors()方法,查找所有advisor类型的类
abstractAutoProxyCreator.postProcessAfterInitialization->abstractAutoProxyCreator.wrapIfNecessary->abstractAdvisorAutoProxyCreator.getAdvicesAndAdvisorsForBean->abstractAdvisorAutoProxyCreator.findEligibleAdvisors->abstractAdvisorAutoProxyCreator.findCandidateAdvisors->advisorRetrievalHelper.findAdvisorBeans()->BeanFactoryUtils.beanNamesForTypeIncludingAncestors->beanFactory.getBean(name, Advisor.class)


advisorRetrievalHelper.findAdvisorBeans()方法中,循环advisorNames

BeanFactoryAdvisorRetrievalHelper源码:
http://grepcode.com/file/repository.springsource.com/org.springframework/org.springframework.aop/3.2.2/org/springframework/aop/framework/autoproxy/BeanFactoryAdvisorRetrievalHelper.java#BeanFactoryAdvisorRetrievalHelper.findAdvisorBeans%28%29

(1.2)其次调用findAdvisorsThatCanApply()方法,查找所有上一步中符合条件的advisor。

abstractAutoProxyCreator.postProcessAfterInitialization->abstractAutoProxyCreator.wrapIfNecessary->abstractAdvisorAutoProxyCreator.getAdvicesAndAdvisorsForBean->abstractAdvisorAutoProxyCreator.findEligibleAdvisors->abstractAdvisorAutoProxyCreator.findAdvisorsThatCanApply->AopUtils.findAdvisorsThatCanApply->advisor.getPointCut->pointcut.matches->tas.getTransactionAttribute 最终返回符合条件的advisor

AopUtils.findAdvisorsThatCanApply(candidateAdvisors, beanClass)方法,
该方法中循环candidateAdvisors,调用canApply(Advisor advisor, Class<?> targetClass, boolean hasIntroductions),根据advisor获取pointcut,继续调用canApply(Pointcut pc, Class<?> targetClass, boolean hasIntroductions),通过pc.getMethodMatcher()获取methodMatcher,这个类是真正判断该类或方法适合符合事物,即该类或方法是否有@Transaction注释

如果bean不适合该advisor,即没有@Transaction注释,则返回false,并将该bean放入this.advisedBeans.put(cacheKey, Boolean.FALSE),并最终返回bean

否则创建代理,(1)最终过滤符合条件的拦截器specificInterceptors


对于BeanFactoryTransactionAttributeSourceAdvisor持有对象TransactionAttributeSourcePointcut,具体分析见(d)




(2) 创建代理AopProxy,并通过aopProxy.getProxy返回最终代理bean。



abstractAutoProxyCreator.postProcessAfterInitialization->abstractAutoProxyCreator.wrapIfNecessary->abstractAutoProxyCreator.createProxy->proxyFactory.getProxy->proxyFactory.createAopProxy().getProxy->jdkDynamicAopProxy.getProxy或cglibProxy.getProxy->java.lang.reflect.Proxy.newProxyInstance(classLoader, proxiedInterfaces, this):  最终返回proxy

this即为aopProxy(jdkDynamicAopProxy或cglibProxy)其实现了InvocationHandler接口

proxy何时调用?
用户业务对象的代理调用时,最终调用invocationHandler.invoke方法

通过jdkDynamicAopProxy源码了解其invoke方法
http://grepcode.com/file/repository.springsource.com/org.springframework/org.springframework.aop/3.2.2/org/springframework/aop/framework/JdkDynamicAopProxy.java#JdkDynamicAopProxy



abstractAutoProxyCreator.createProxy(bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean)),在该方法中创建 ProxyFactory,并设置属性

ProxyFactory源码:
http://grepcode.com/file/repository.springsource.com/org.springframework/org.springframework.aop/3.2.2/org/springframework/aop/framework/ProxyFactory.java#ProxyFactory.getProxy%28java.lang.ClassLoader%29

ProxyFactory proxyFactory = new ProxyFactory();
		// Copy our properties (proxyTargetClass etc) inherited from ProxyConfig.
		proxyFactory.copyFrom(this);

		if (!shouldProxyTargetClass(beanClass, beanName)) {
			// Must allow for introductions; can't just set interfaces to
			// the target's interfaces only.
			Class<?>[] targetInterfaces = ClassUtils.getAllInterfacesForClass(beanClass, this.proxyClassLoader);
			for (Class<?> targetInterface : targetInterfaces) {
				proxyFactory.addInterface(targetInterface);
			}
		}

		Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
		for (Advisor advisor : advisors) {
			proxyFactory.addAdvisor(advisor);
		}

		proxyFactory.setTargetSource(targetSource);
		customizeProxyFactory(proxyFactory);

		proxyFactory.setFrozen(this.freezeProxy);
		if (advisorsPreFiltered()) {
			proxyFactory.setPreFiltered(true);
		}

		return proxyFactory.getProxy(this.proxyClassLoader);

最后一句proxyFactory.getProxy(this.proxyClassLoader);此处创建代理。

public Object getProxy(ClassLoader classLoader) {
		return createAopProxy().getProxy(classLoader);
	}


该方法中createAopProxy()返回AopProxy如下:
proxyCreatorSupport.createAopProxy()创建代理
protected final synchronized AopProxy createAopProxy() {
	if (!this.active) {
	        activate();
	}
	return getAopProxyFactory().createAopProxy(this);
}


getAopProxyFactory()方法中获取ProxyCreatorSupport的内置对象aopProxyFactory( new DefaultAopProxyFactory())。
DefaultAopProxyFactory源码:
http://grepcode.com/file/repository.springsource.com/org.springframework/org.springframework.aop/3.2.2/org/springframework/aop/framework/DefaultAopProxyFactory.java#DefaultAopProxyFactory

getAopProxyFactory().createAopProxy(this)该方法返回AopProxy
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
		if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {
			Class targetClass = config.getTargetClass();
			if (targetClass == null) {
				throw new AopConfigException("TargetSource cannot determine target class: " +
						"Either an interface or a target is required for proxy creation.");
			}
			if (targetClass.isInterface()) {
				return new JdkDynamicAopProxy(config);
			}
			return CglibProxyFactory.createCglibProxy(config);
		}
		else {
			return new JdkDynamicAopProxy(config);
		}
	}






createAopProxy().getProxy(classLoader);以jdk生成代理为例
jdkDynamicAopProxy.getProxy(classLoader)
public Object getProxy(ClassLoader classLoader) {
		if (logger.isDebugEnabled()) {
			logger.debug("Creating JDK dynamic proxy: target source is " + this.advised.getTargetSource());
		}
		Class[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised);
		findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
		return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
	}


最终返回代理对象


JdkDynamicAopProxy源码:
http://grepcode.com/file/repository.springsource.com/org.springframework/org.springframework.aop/3.2.2/org/springframework/aop/framework/JdkDynamicAopProxy.java#JdkDynamicAopProxy

此后置处理器处理@Transaction注释的bean,创建aopProxy。其他advisor如何处理,事务代理的外面再加一层代理?
尝试解释:
该后置处理器可以处理多个advisor(包括事务advisor,即BeanFactoryTransactionAttributeSourceAdvisor)
自定义advisor,实现相应接口,看否是可以识别?
自定义beanpostprocess,在此前代理上创建代理或者覆盖原先代理对象?


ProxyCreatorSupport源码:
http://grepcode.com/file/repository.springsource.com/org.springframework/org.springframework.aop/3.2.2/org/springframework/aop/framework/ProxyCreatorSupport.java#ProxyCreatorSupport.createAopProxy%28%29


断点2





创建AnnotationTransactionAttributeSource的beanDefinition
b.定义AnnotationTransactionAttributeSource- 事务属性,每个业务类或方法可能不同,大部分是一样的

// Create the TransactionAttributeSource definition.
				RootBeanDefinition sourceDef = new RootBeanDefinition(AnnotationTransactionAttributeSource.class);
				sourceDef.setSource(eleSource);
				sourceDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
				String sourceName = parserContext.getReaderContext().registerWithGeneratedName(sourceDef);

创建 AnnotationTransactionAttributeSource定义(事务属性来源于注解@Transactional)

单一职责原则:getTransactionAttribute(Method method, Class<?> targetClass)

判断方法或类是否有@Transactional注释,并解析返回TransactionAttribute或null。其内部调用SpringTransactionAnnotationParser来解析是否有@Transactional注解

AnnotationTransactionAttributeSource源码见:
http://grepcode.com/file/repository.springsource.com/org.springframework/org.springframework.transaction/3.2.2/org/springframework/transaction/annotation/AnnotationTransactionAttributeSource.java?av=f

在哪调用其getTransactionAttribute(Method method, Class<?> targetClass)方法,以获取事务属性?
(1) 在后置处理器,avvisor->pointcut.matches->getTransactionAttribute,用于判断advisor适合适合此bean

(2) 在TransactionInterceptor的invoke方法中调用,更确切的说是在TransactionAspectSupport的invokeWithinTransaction方法中。用于事务定义TransactionInfo

用于判断该方法或类是否可开启事务。

还有其他的事务属性来源,应用于不同的事务配置方式如:NameMatchTransactionAttributeSource





创建TransactionInterceptor的beanDefinition
c.定义TransactionInterceptor- 事务拦截器,执行事务开始,提交,回滚等操作




// Create the TransactionInterceptor definition.
				RootBeanDefinition interceptorDef = new RootBeanDefinition(TransactionInterceptor.class);
				interceptorDef.setSource(eleSource);
				interceptorDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
				registerTransactionManager(element, interceptorDef);
				interceptorDef.getPropertyValues().add("transactionAttributeSource", new RuntimeBeanReference(sourceName));
				String interceptorName = parserContext.getReaderContext().registerWithGeneratedName(interceptorDef);

创建TransactionInterceptor定义

单一职责原则:invoke(final MethodInvocation invocation)

invoke中调用TransactionAspectSupport的invokeWithinTransaction(Method method, Class targetClass, final InvocationCallback invocation)方法,执行真正的拦截逻辑。在该方法中会调用transactionAttributeSource判断类或方法是否可开启事务,调用transactionManager执行拦截逻辑,即开启提交事务等。

registerTransactionManager(element, interceptorDef);
这行代码,主要是设置TransactionAspectSupport的transactionManager(注册事务管理器)。调用invoke时,设置到生成的TransactionInfo中并管理事务状态。

TransactionInterceptor(拦截器)本身不保存数据,只是起到传递的作用,把真正的处理过程交给TransactionAspectSupport 去完成

在哪调用TransactionInterceptor.invoke(final MethodInvocation invocation)?
在(a)处后置处理器中,生成代理(jdk或cglib代理),invoke方法中调用

transactionInterceptor是advice,是否包装成advisor何时包装?
创建代理时(a(2))封装成advisor:
abstractAutoProxyCreator.buildAdvisors->advisorAdapterRegistry.wrap

调用代理方法时,执行的是methodInterceptor,advisor何时拆解成methodInterceptor?
执行代理方法invoke时,通过advised.getInterceptorsAndDynamicInterceptionAdvice获取methodInterceptor,其中会调用advisorAdapterRegistry.getInterceptors(advisor);


TransactionAspectSupport源码可见:
http://grepcode.com/file/repository.springsource.com/org.springframework/org.springframework.transaction/3.2.2/org/springframework/transaction/interceptor/TransactionAspectSupport.java#TransactionAspectSupport.TransactionInfo.bindToThread%28%29

joinpointIdentification

TransactionInterceptor源码见:
http://grepcode.com/file/repository.springsource.com/org.springframework/org.springframework.transaction/3.2.2/org/springframework/transaction/interceptor/TransactionInterceptor.java#TransactionInterceptor





创建BeanFactoryTransactionAttributeSourceAdvisor的beanDefinition
d.定义BeanFactoryTransactionAttributeSourceAdvisor- 事务集成到业务bean,连接中介类





// Create the TransactionAttributeSourceAdvisor definition.
				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);
				if (element.hasAttribute("order")) {
					advisorDef.getPropertyValues().add("order", element.getAttribute("order"));
				}
				parserContext.getRegistry().registerBeanDefinition(txAdvisorBeanName, advisorDef);

创建TransactionAttributeSourceAdvisor定义
BeanFactoryTransactionAttributeSourceAdvisor源码:
http://grepcode.com/file/repository.springsource.com/org.springframework/org.springframework.transaction/3.2.2/org/springframework/transaction/interceptor/BeanFactoryTransactionAttributeSourceAdvisor.java?av=f


BeanFactoryTransactionAttributeSourceAdvisor是一个标识类,使其能够被后置处理器(InfrastructureAdvisorAutoProxyCreator见(a)出分析)识别。
具体分析见:
http://www.cnblogs.com/youzhibing/p/6414780.html


持有对象TransactionAttributeSourcePointcut



public boolean matches(Method method, Class targetClass) {
		TransactionAttributeSource tas = getTransactionAttributeSource();
		return (tas == null || tas.getTransactionAttribute(method, targetClass) != null);
	}


后置处理器中调用此方法,判断bean或method是否适合此advisor



TransactionAttributeSourcePointcut源码见
http://grepcode.com/file/repository.springsource.com/org.springframework/org.springframework.transaction/3.1.2/org/springframework/transaction/interceptor/TransactionAttributeSourcePointcut.java#TransactionAttributeSourcePointcut






创建CompositeComponentDefinition的beanDefinition
e.定义组件之间的关系bean

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


该类的具体作用是什么?
定义事务处理之间的关系?

断点4:






总结:
条件语句里面创建了3个bean定义(TransactionAttributeSource ,TransactionInterceptor,TransactionAttributeSourceAdvisor ),将3个类组合嵌入compositeDef中,代表整个<tx:annotation-driven transaction-manager="transactionManager" />

还创建了一个后置处理器,bean实例化后,创建事务代理

创建3个定义或者后置处理器的过程中,多处可以继续跟踪代码,如如何创建aopProxy代理,transactioninterceptor中的invoke方法是如何执行的等等。限于篇幅,这里进一步跟踪,后续补上



2.2 @Transactionl
事务属性来源,主要在TransactionAttributeSource中判断bean或者method中是否有注解






3.代理的使用-使用中遇到的常见问题





参考:
https://www.ibm.com/developerworks/cn/education/opensource/os-cn-spring-trans/

http://www.myexception.cn/open-source/1942796.html

http://www.codeceo.com/article/software-outsourcing-and-lover.html

http://blog.csdn.net/qq418517226/article/details/51282035

http://jinnianshilongnian.iteye.com/blog/1901694

http://www.cnblogs.com/wade-luffy/p/6080183.html   Spring事务解析2-标签解析

http://jinnianshilongnian.iteye.com/blog/1508018   TransactionAttributeSource

http://lgbolgger.iteye.com/blog/2180251       Spring事务源码分析(一)Spring事务入门

猜你喜欢

转载自newjava-sina-cn.iteye.com/blog/2360484
今日推荐