Spring的事务及其的灵活,他构建在AOP的基础上,采用事务声明的方式,使得我们很容易在hibernate jdbc,jta等事务方式中切换;
在前几节,我们重新复习了数据源,连接池,以及分布式事务的知识,在这一节中,我们详细的来分析一下Spring的事务的实现;
Spring事务的实现是建立在Aop的基础上,在Aop的基础上,Spring避免了硬编码的事务声明方式,改在配置文件中声明,从而增强了灵活性,并且了紧耦合;
首先,我们来看一下Spring的配置文件的生成;
<bean id="coreyDao" name="coreyDao"
class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean"
abstract="false" lazy-init="default" autowire="default"
dependency-check="default">
<property name="target">
<ref bean="coreyRealDao"></ref>
</property>
<property name="transactionManager">
<ref bean="transactionManager"></ref>
</property>
<property name="transactionAttributes">
<props>
<prop key="*">PROPAGATION_REQUIRED</prop>
</props>
</property>
</bean>
我们通过获取了coreyDao能够得到一个具有事务的coreyRealDao的代理对象,他的代理规则被详细的描述在transactionAttributes的properties中;
那么,现在,我们就开始分析一个个具体的类;
从上面的类图我们可以看见,首先由一个代理类代理了普通的数据库事务类,这个ProxyFactoryBean含有一个拦截器,并且对拦截器进行初始化;
下面是该ProxyFacrotyBean的属性;
//拦截器;
private final TransactionInterceptor transactionInterceptor = new TransactionInterceptor();
//代理的目标类。同proxyFactoryBean
private Object target;
//代理接口
private Class[] proxyInterfaces;
//切面;
private Pointcut pointcut;
//前拦截器
private Object[] preInterceptors;
//后拦截器
private Object[] postInterceptors;
//最后生成的代理类,利用FactoryBean的getObject()返回;
private Object proxy;
在这个类中,我们可以设置transactionAttributes,PlatformTransactionManager等等,目的是初始化transactionInterceptor;
public void setTransactionManager(PlatformTransactionManager transactionManager) {
this.transactionInterceptor.setTransactionManager(transactionManager);
}
public void setTransactionAttributes(Properties transactionAttributes) {
this.transactionInterceptor.setTransactionAttributes(transactionAttributes);
}
public void setTransactionAttributeSource(TransactionAttributeSource transactionAttributeSource) {
this.transactionInterceptor.setTransactionAttributeSource(transactionAttributeSource);
}
在下面这段中,实现了一个非常有趣的功能;
public void setBeanFactory(BeanFactory beanFactory) {
if (this.transactionInterceptor.getTransactionManager() == null &&
beanFactory instanceof ListableBeanFactory) {
ListableBeanFactory lbf = (ListableBeanFactory) beanFactory;
PlatformTransactionManager ptm = (PlatformTransactionManager)
BeanFactoryUtils.beanOfTypeIncludingAncestors(lbf, PlatformTransactionManager.class);
this.transactionInterceptor.setTransactionManager(ptm);
}
}
如果我们没有显示的为该ProxyFactoryBean制定TM,那么就会默认把ioc容器里面的唯一的一个PlatformTransactionManager类型的bean设置给他(但是如果超过一个,就会抛出异常);
其下,我们来好好琢磨琢磨这个具有事务功能的代理类是如何生成的;
public void afterPropertiesSet() {
//这个类判断你是否设置了TM和transactionAttributes
this.transactionInterceptor.afterPropertiesSet();
//检查是否设置类代理的目标类
if (this.target == null) {
throw new IllegalArgumentException("'target' is required");
}
//代理类不能为String类型;
if (this.target instanceof String) {
throw new IllegalArgumentException("'target' needs to be a bean reference, not a bean name as value");
}
//实例化代理工厂,为生成代理类做准备,我们在AOP一节已经分析过了;
ProxyFactory proxyFactory = new ProxyFactory();
//结合我们所提供的装备和接口以及切面,生成了一个代理类;
if (this.preInterceptors != null) {
for (int i = 0; i < this.preInterceptors.length; i++) {
proxyFactory.addAdvisor(this.advisorAdapterRegistry.wrap(this.preInterceptors[i]));
}
}
if (this.pointcut != null) {
Advisor advice = new DefaultPointcutAdvisor(this.pointcut, this.transactionInterceptor);
proxyFactory.addAdvisor(advice);
}
else {
// Rely on default pointcut.
proxyFactory.addAdvisor(new TransactionAttributeSourceAdvisor(this.transactionInterceptor));
// Could just do the following, but it's usually less efficient because of AOP advice chain caching.
// proxyFactory.addAdvice(transactionInterceptor);
}
if (this.postInterceptors != null) {
for (int i = 0; i < this.postInterceptors.length; i++) {
proxyFactory.addAdvisor(this.advisorAdapterRegistry.wrap(this.postInterceptors[i]));
}
}
proxyFactory.copyFrom(this);
TargetSource targetSource = createTargetSource(this.target);
proxyFactory.setTargetSource(targetSource);
if (this.proxyInterfaces != null) {
proxyFactory.setInterfaces(this.proxyInterfaces);
}
else if (!isProxyTargetClass()) {
// Rely on AOP infrastructure to tell us what interfaces to proxy.
proxyFactory.setInterfaces(ClassUtils.getAllInterfacesForClass(targetSource.getTargetClass()));
}
//代理类生成了;
this.proxy = getProxy(proxyFactory);
}
经过上面的步骤,我们已经知道了代理类的生成过程,那么这个代理类是如何具有事务功能的呢,我们只知道他被transactionInterceptor进行了拦截,那么在这个拦截器中具体做了什么样的操作,我们再来具体的分析一下transactionInterceptor;
上图我们可看见了transactionInterceptor的基本的类图,他包含一组TransactionInfo,TransactionInfo是线程变量,这说明,一个线程只可能拥有一个TransactionInfo,线程和线程之间的事务是互不关联,互不影响,线程安全的;
ThreadLocal我们在前几节已经介绍了:
private static final ThreadLocal currentTransactionInfo = new ThreadLocal();
public static TransactionStatus currentTransactionStatus() throws NoTransactionException {
return currentTransactionInfo().transactionStatus;
}
protected static TransactionInfo currentTransactionInfo() throws NoTransactionException {
TransactionInfo info = (TransactionInfo) currentTransactionInfo.get();
if (info == null) {
throw new NoTransactionException("No transaction aspect-managed TransactionStatus in scope");
}
return info;
}
事务管理器对系统的事务进行同意管理,在这里PlatformTransactionManager 屏蔽了事务管理器之间的不同,比如jdbc事务管理,hibernate事务管理,jms事务管理等等,在这里,使得事务的实现和事务管理器之间解耦开来,跟我们前几节中大对象的生成了数据库之间的耦合有异曲同工之妙,到时候,我们只要改变配置就可以更换事务的实现;
protected PlatformTransactionManager transactionManager;
现在,有人不仅仅要问,代理类是怎么知道在目标代理类中,什么方法(现在事务声明的细粒度是方法)需要进行事务管理,什么方法不要,下面我们就会说到这个功能的实现;
protected TransactionAttributeSource transactionAttributeSource;
public interface TransactionAttributeSource {
TransactionAttribute getTransactionAttribute(Method method, Class targetClass);
}
TransactionAttributeSource 是一个TransactionAttribute的管理类,他有许多具体的实现,其中最为常用的是也是默认的是:
在transactionInterceptor初始化的时候:
public void setTransactionAttributes(Properties transactionAttributes) {
NameMatchTransactionAttributeSource tas = new NameMatchTransactionAttributeSource();
tas.setProperties(transactionAttributes);
this.transactionAttributeSource = tas;
}
NameMatchTransactionAttributeSource tas = new NameMatchTransactionAttributeSource();被作为了默认的实现,我们现在来看看看这个
NameMatchTransactionAttributeSource类的实现细节;他含有一个hashMap来存储transactionAttribute,其中transactionAttribute为值,需要拦截的方法为key;
private Map nameMap = new HashMap();
public void setProperties(Properties transactionAttributes) {
TransactionAttributeEditor tae = new TransactionAttributeEditor();
for (Iterator it = transactionAttributes.keySet().iterator(); it.hasNext(); ) {
String methodName = (String) it.next();
String value = transactionAttributes.getProperty(methodName);
tae.setAsText(value);
TransactionAttribute attr = (TransactionAttribute) tae.getValue();
//形成方法名和事务属性对象的映射;
addTransactionalMethod(methodName, attr);
}
}
我们可以从上看见properties的entry到transactionAttribute的转换,这个是从value到Object的转换,这让我们想起了什么,对就是textEditor,我们来看看TransactionAttributeEditor是怎么进行这次移花接木的:
public void setAsText(String text) throws IllegalArgumentException {
if (StringUtils.hasLength(text)) {
//把<prop key="*">PROPAGATION_REQUIRED,timeout_21,ISOLATIONXX</prop>中的PROPAGATION_REQUIRED拿出来用 //逗号隔开,分成数组;
String[] tokens = StringUtils.commaDelimitedListToStringArray(text);
//生成RuleBasedTransactionAttribute();
RuleBasedTransactionAttribute attr = new RuleBasedTransactionAttribute();
for (int i = 0; i < tokens.length; i++) {
//除去前后空白字符串
String token = StringUtils.trimWhitespace(tokens[i].trim());
如果中间含有空白字符,抛出异常;
if (StringUtils.containsWhitespace(token)) {
throw new IllegalArgumentException(
"Transaction attribute token contains illegal whitespace: [" + token + "]");
}
//辨别属性,并且设置到RuleBasedTransactionAttribute相应的属性字段里面;
if (token.startsWith(TransactionDefinition.PROPAGATION_CONSTANT_PREFIX)) {
attr.setPropagationBehaviorName(token);
}
else if (token.startsWith(TransactionDefinition.ISOLATION_CONSTANT_PREFIX)) {
attr.setIsolationLevelName(token);
}
else if (token.startsWith(DefaultTransactionAttribute.TIMEOUT_PREFIX)) {
String value = token.substring(DefaultTransactionAttribute.TIMEOUT_PREFIX.length());
attr.setTimeout(Integer.parseInt(value));
}
else if (token.equals(DefaultTransactionAttribute.READ_ONLY_MARKER)) {
attr.setReadOnly(true);
}
else if (token.startsWith(DefaultTransactionAttribute.COMMIT_RULE_PREFIX)) {
attr.getRollbackRules().add(new NoRollbackRuleAttribute(token.substring(1)));
}
else if (token.startsWith(DefaultTransactionAttribute.ROLLBACK_RULE_PREFIX)) {
attr.getRollbackRules().add(new RollbackRuleAttribute(token.substring(1)));
}
else {
throw new IllegalArgumentException("Invalid transaction attribute token: [" + token + "]");
}
}
setValue(attr);
}
else {
setValue(null);
}
}
到时候如何取出这个事务属性对象呢,我们看见在配置文件中有配置*,这好像是正则表达式的应用,但是很遗憾的是,这里并不支持完整的正则表达式匹配,只是支持简单的行首和行尾的*代表任意多的任意字符而已,不过,这是一个很好的扩展点,我们自己可以试着实现;
public TransactionAttribute getTransactionAttribute(Method method, Class targetClass) {
//首先,得到方法元对象的方法名字;
String methodName = method.getName();
//从hashMap中取出;
TransactionAttribute attr = (TransactionAttribute) this.nameMap.get(methodName);
if (attr == null) {
//如果为空;进行*的匹配
String bestNameMatch = null;
for (Iterator it = this.nameMap.keySet().iterator(); it.hasNext();) {
String mappedName = (String) it.next();
//*号开头的只要能匹配后面的字符即可,*结尾的只要能匹配前面的字符串即可;
if (isMatch(methodName, mappedName) &&
(bestNameMatch == null || bestNameMatch.length() <= mappedName.length())) {
attr = (TransactionAttribute) this.nameMap.get(mappedName);
bestNameMatch = mappedName;
}
}
}
return attr;
}
//*号开头的只要能匹配后面的字符即可,*结尾的只要能匹配前面的字符串即可;
protected boolean isMatch(String methodName, String mappedName) {
return (mappedName.endsWith("*") && methodName.startsWith(mappedName.substring(0, mappedName.length() - 1))) ||
(mappedName.startsWith("*") && methodName.endsWith(mappedName.substring(1, mappedName.length())));
}
接下来,我们可以先来看下,到底这个transactionAttribute这个对象;
public interface TransactionDefinition {
String PROPAGATION_CONSTANT_PREFIX = "PROPAGATION";
String ISOLATION_CONSTANT_PREFIX = "ISOLATION";
//传播途径
int getPropagationBehavior();
//隔离级别
int getIsolationLevel();
//有效时间
int getTimeout();
//是否只读
boolean isReadOnly();
//对象名字
String getName();
}
public interface TransactionAttribute extends TransactionDefinition {
//在此基础上增加了回滚判断机制,以便事务在遇到制定异常的时候进行回滚;
boolean rollbackOn(Throwable ex);
}
在下面,我们来介绍一下TransactionInfo;TransactionInfo其实就犹如TransactionAttributeSource hashMap中的一项;
TransactionInfo是TransactionAspectSupport的一个内部类,它的主要功能是记录方法和对应的事务属性
protected class TransactionInfo {
private final TransactionAttribute transactionAttribute;
private final Method method;
private TransactionStatus transactionStatus;
private TransactionInfo oldTransactionInfo;
public TransactionInfo(TransactionAttribute transactionAttribute, Method method) {
this.transactionAttribute = transactionAttribute;
this.method = method;
}
下面我们来看一下,这个拦截器的具体的拦截方式把;
public Object invoke(MethodInvocation invocation) throws Throwable {
//获取代理目标类的类型;
Class targetClass = (invocation.getThis() != null ? invocation.getThis().getClass() : null);
//根据当前拦截的方法,取得一个相对应的transactionInfo,不过当然不一定就有,所以名字都叫necessary;
TransactionInfo txInfo = createTransactionIfNecessary(invocation.getMethod(), targetClass);
Object retVal = null;
try {
//执行该方法;
retVal = invocation.proceed();
}
catch (Throwable ex) {
//如果方法抛出异常,那么采用异常处理机制;
doCloseTransactionAfterThrowing(txInfo, ex);
throw ex;
}
finally {
//采用finally处理;
doFinally(txInfo);
}
//正常结束的处理;
doCommitTransactionAfterReturning(txInfo);
return retVal;
}
在开始的时候,我们的TransactionAttributeSource只是存储了代表方法的字符串和TransactionAttribute的对应哈西表,但没有建立方法对象Method实例与TransactionAttribute之间的对应,那么createTransactionIfNecessary就是为了实现这个功能;
protected TransactionInfo createTransactionIfNecessary(Method method, Class targetClass) {
// 根据方法找到对应的TransactionAttribute对象,如果没有找到的话,那么该方法就不会被拦截;
final TransactionAttribute sourceAttr =
this.transactionAttributeSource.getTransactionAttribute(method, targetClass);
TransactionAttribute txAttr = sourceAttr;
// 如果该TransacrionAttribute没有设置名字,那么会根据将className.methodName作为该TransactionAttribute的名字,
//这里是典型的代理模式的应用;
if (txAttr != null && txAttr.getName() == null) {
final String name = methodIdentification(method);
txAttr = new DelegatingTransactionAttribute(sourceAttr) {
public String getName() {
return name;
}
};
}
//生成了method和transactionAttribute相对应的transactionInfo实例;
TransactionInfo txInfo = new TransactionInfo(txAttr, method);
if (txAttr != null) {
// We need a transaction for this method
if (logger.isDebugEnabled()) {
logger.debug("Getting transaction for " + txInfo.joinpointIdentification());
}
// The transaction manager will flag an error if an incompatible tx already exists
txInfo.newTransactionStatus(this.transactionManager.getTransaction(txAttr));
}
else {
// The TransactionInfo.hasTransaction() method will return
// false. We created it only to preserve the integrity of
// the ThreadLocal stack maintained in this class.
if (logger.isDebugEnabled())
logger.debug("Don't need to create transaction for [" + methodIdentification(method) +
"]: this method isn't transactional");
}
//在这里,我们可以看见这个transactionInfo绑定到该线程上去;
//如果当前线程存在未结束的事务,那么我们会把旧transactionInfo设置为新的transactionInfo的oldTransactionInfo
txInfo.bindToThread();
return txInfo;
}
//保存旧的transactionInfo是因为考虑到事务传播途径的判断;
private void bindToThread() {
// Expose current TransactionStatus, preserving any existing transactionStatus for
// restoration after this transaction is complete.
oldTransactionInfo = (TransactionInfo) currentTransactionInfo.get();
currentTransactionInfo.set(this);
}
事务的新状态;
public final TransactionStatus getTransaction(TransactionDefinition definition) throws TransactionException {
//留给子类实现,比如jdbc会获取DatabaseTransaction,而jta会从jndi获取UserTrasction获取transaction
Object transaction = doGetTransaction();
// Cache debug flag to avoid repeated checks.
boolean debugEnabled = logger.isDebugEnabled();
if (debugEnabled) {
logger.debug("Using transaction object [" + transaction + "]");
}
if (definition == null) {
//如果为空,就会创建一个默认的trasnactionDefinition;
definition = new DefaultTransactionDefinition();
}
if (isExistingTransaction(transaction)) {
//处理已经存在的transaction,返回其状态;
return handleExistingTransaction(definition, transaction, debugEnabled);
}
// Check definition settings for new transaction.
if (definition.getTimeout() < TransactionDefinition.TIMEOUT_DEFAULT) {
throw new InvalidTimeoutException("Invalid transaction timeout", definition.getTimeout());
}
// No existing transaction found -> check propagation behavior to find out how to proceed.
if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_MANDATORY) {
throw new IllegalTransactionStateException(
"No existing transaction found for transaction marked with propagation 'mandatory'");
}
else if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRED ||
definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW ||
definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NESTED) {
Object suspendedResources = suspend(null);
if (debugEnabled) {
logger.debug("Creating new transaction with name [" + definition.getName() + "]: " +
definition);
}
doBegin(transaction, definition);
boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
return newTransactionStatus(
definition, transaction, true, newSynchronization, debugEnabled, suspendedResources);
}
else {
// Create "empty" transaction: no actual transaction, but potentially synchronization.
boolean newSynchronization = (getTransactionSynchronization() == SYNCHRONIZATION_ALWAYS);
return newTransactionStatus(definition, null, false, newSynchronization, debugEnabled, null);
}
}
//会根据传播途径来返回相应的事务状态类;
private TransactionStatus handleExistingTransaction(
TransactionDefinition definition, Object transaction, boolean debugEnabled)
throws TransactionException {
//never不能处在事务中,否则抛出异常;
if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NEVER) {
throw new IllegalTransactionStateException(
"Existing transaction found for transaction marked with propagation 'never'");
}
//NOT_SUPPORTED不能处在事务中,否则将当前事务挂起;
if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NOT_SUPPORTED) {
if (debugEnabled) {
logger.debug("Suspending current transaction");
}
//挂起当前事务;
Object suspendedResources = suspend(transaction);
boolean newSynchronization = (getTransactionSynchronization() == SYNCHRONIZATION_ALWAYS);
//不是新的事务;
return newTransactionStatus(
definition, null, false, newSynchronization, debugEnabled, suspendedResources);
}
//REQUIRES_NEW要求挂起当前事务并且要求一个新的事务;
if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW) {
if (debugEnabled) {
logger.debug("Suspending current transaction, creating new transaction with name [" +
definition.getName() + "]");
}
SuspendedResourcesHolder suspendedResources = suspend(transaction);
try {
doBegin(transaction, definition);
}
catch (TransactionException beginEx) {
try {
resume(transaction, suspendedResources);
}
catch (TransactionException resumeEx) {
logger.error(
"Inner transaction begin exception overridden by outer transaction
resume exception", beginEx);
throw resumeEx;
}
throw beginEx;
}
boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
//新的事务;
return newTransactionStatus(
definition, transaction, true, newSynchronization, debugEnabled, suspendedResources);
}
//PROPAGATION_NESTED代表嵌入式事务;
if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NESTED) {
if (!isNestedTransactionAllowed()) {
throw new NestedTransactionNotSupportedException(
"Transaction manager does not allow nested transactions by default - " +
"specify 'nestedTransactionAllowed' property with value 'true'");
}
if (debugEnabled) {
logger.debug("Creating nested transaction with name [" + definition.getName() + "]");
}
if (useSavepointForNestedTransaction()) {
//生成新的储存点
DefaultTransactionStatus status =
newTransactionStatus(definition, transaction, false, false, debugEnabled,
null);
status.createAndHoldSavepoint();
return status;
}
else {
//在这里会开始新的事务,至于这个新的事务如何开始,与具体的实现有关系,所以会利通模板模式
//推迟到子类中实现,比如下面的两种实现方式;
doBegin(transaction, definition);
boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
return newTransactionStatus(definition, transaction, true, newSynchronization, debugEnabled,
null);
}
}
// Assumably PROPAGATION_SUPPORTS.
if (debugEnabled) {
logger.debug("Participating in existing transaction");
}
boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
return newTransactionStatus(definition, transaction, false, newSynchronization, debugEnabled, null);
}
JDBC的doBegin:
protected void doBegin(Object transaction, TransactionDefinition definition) {
DataSourceTransactionObject txObject = (DataSourceTransactionObject) transaction;
Connection con = null;
try {
if (txObject.getConnectionHolder() == null ||
txObject.getConnectionHolder().isSynchronizedWithTransaction()) {
Connection newCon = this.dataSource.getConnection();
if (logger.isDebugEnabled()) {
logger.debug("Acquired Connection [" + newCon + "] for JDBC transaction");
}
txObject.setConnectionHolder(new ConnectionHolder(newCon), true);
}
txObject.getConnectionHolder().setSynchronizedWithTransaction(true);
con = txObject.getConnectionHolder().getConnection();
Integer previousIsolationLevel = DataSourceUtils.prepareConnectionForTransaction(con, definition);
txObject.setPreviousIsolationLevel(previousIsolationLevel);
// Switch to manual commit if necessary. This is very expensive in some JDBC drivers,
// so we don't want to do it unnecessarily (for example if we've explicitly
// configured the connection pool to set it already).
if (con.getAutoCommit()) {
txObject.setMustRestoreAutoCommit(true);
if (logger.isDebugEnabled()) {
logger.debug("Switching JDBC Connection [" + con + "] to manual commit");
}
con.setAutoCommit(false);
}
txObject.getConnectionHolder().setTransactionActive(true);
int timeout = determineTimeout(definition);
if (timeout != TransactionDefinition.TIMEOUT_DEFAULT) {
txObject.getConnectionHolder().setTimeoutInSeconds(timeout);
}
// Bind the session holder to the thread.
if (txObject.isNewConnectionHolder()) {
TransactionSynchronizationManager.bindResource(getDataSource(),
txObject.getConnectionHolder());
}
}
catch (SQLException ex) {
DataSourceUtils.releaseConnection(con, this.dataSource);
throw new CannotCreateTransactionException("Could not open JDBC Connection for transaction", ex);
}
}
利用了JDBC的setAutoCommit()来实现事务的开始;
JTA事务的doBegin:
protected void doJtaBegin(JtaTransactionObject txObject, TransactionDefinition definition)
throws NotSupportedException, SystemException {
applyIsolationLevel(txObject, definition.getIsolationLevel());
applyTimeout(txObject, definition.getTimeout());
txObject.getUserTransaction().begin();
}
利用了Usertransaction.begin来实现事务的开始;
事务状态的5个基本属性;
public DefaultTransactionStatus(
Object transaction, boolean newTransaction, boolean newSynchronization,
boolean readOnly, boolean debug, Object suspendedResources) {
//当前事务属性的事务
this.transaction = transaction;
//是否是一个新的事务;
this.newTransaction = newTransaction;
//事务同步
this.newSynchronization = newSynchronization;
//这个事务是只读事务;
this.readOnly = readOnly;
//是否显示调试信息;
this.debug = debug;
//当前事务的被挂载起来的资源装载对象;
this.suspendedResources = suspendedResources;
}
//在方法拦截中,会根据不同的传播途径生成的事务状态来执行不同的操作;
public Object invoke(MethodInvocation invocation) throws Throwable {
// Work out the target class: may be <code>null</code>.
// The TransactionAttributeSource should be passed the target class
// as well as the method, which may be from an interface
Class targetClass = (invocation.getThis() != null ? invocation.getThis().getClass() : null);
// Create transaction if necessary.
TransactionInfo txInfo = createTransactionIfNecessary(invocation.getMethod(), targetClass);
Object retVal = null;
try {
// This is an around advice.
// Invoke the next interceptor in the chain.
// This will normally result in a target object being invoked.
retVal = invocation.proceed();
}
catch (Throwable ex) {
// target invocation exception
doCloseTransactionAfterThrowing(txInfo, ex);
throw ex;
}
finally {
doFinally(txInfo);
}
doCommitTransactionAfterReturning(txInfo);
return retVal;
}
}
doFinally操作是无论那个方法不管什么事务属性都会要做的:
protected void doFinally(TransactionInfo txInfo) {
if (txInfo != null) {
txInfo.restoreThreadLocalStatus();
}
}
他把上一个事务信息传入了线程中间,回复了当前线程的事务信息;
在这里,jiwenke发表在javaeye中的解释,已经很详细了:
其中的doFinally(txInfo)那一行很重要,也就是说不管如何,这个doFinally方法都是要被调用的,为什么它这么重要呢,举个例子:
我们还是以propregation_required来举例子吧,假设情况是这样的,AService中有一个方法调用了BService中的,这两个方法都处在事务体之
中,他们的传播途径都是required。那么调用开始了,AService的方法首先入方法栈,并创建了 TransactionInfo的实例,接着BService的方
法入栈,又创建了一个TransactionInfo的实例,而重点要说明的是 TransactionInfo是一个自身关联的内部类,第二个方法入栈时,会给新创
建的TransactionInfo的实例设置一个属性,就是 TransactionInfo对象中的private TransactionInfo oldTransactionInfo;属性,这个属性
表明BService方法的创建的TransactionInfo对象是有一个old的 transactionInfo对象的,这个oldTransactionInfo对象就是AService方法入
栈时创建的 TransactionInfo对象,我们还记得在createTransactionIfNecessary方法里有这样一个方法吧:
protected TransactionInfo createTransactionIfNecessary(Method method, Class targetClass) {
// We always bind the TransactionInfo to the thread, even if we didn't create
// a new transaction here. This guarantees that the TransactionInfo stack
// will be managed correctly even if no transaction was created by this aspect.
txInfo.bindToThread();
return txInfo;
}
就是这个bindToThread()方法在作怪:
private void bindToThread() {
// Expose current TransactionStatus, preserving any existing transactionStatus for
// restoration after this transaction is complete.
oldTransactionInfo = (TransactionInfo) currentTransactionInfo.get();
currentTransactionInfo.set(this);
}
如果当前线程中已经有了一个TransactionInfo,则拿出来放到新建的transactionInfo对象的oldTransactionInfo属性中,然后再把新建的Tra
nsactionInfo设置到当前线程中。
这里有一个概念要搞清楚,就是TransactionInfo对象并不是表明事务状态的对象,表明事务状态的对象是TransactionStatus对象,这个对象
同样是TransactionInfo的一个属性(这一点,我在前面一篇文章中并没有讲清楚)。
接下来BService中的那个方法返回,那么该它退栈了,它退栈后要做的就是doFinally方法,即把它的 oldTransactionInfo设置到当前线程中
(这个TransactionInfo对象显然就是AService方法入栈时创建的,怎么现在又要设置到线程中去呢,原因就是BService的方法出栈时并不提交
事务,因为BService的传播途径是required,所以要把栈顶的方法所创建 transactioninfo给设置到当前线程中),即调用AService的方法时
所创建的TransactionInfo对象。那么在 AServie的方法出栈时同样会设置TransactionInfo对象的oldTransactionInfo到当前线程,这时候显
然 oldTransactionInfo是空的,但AService中的方法会提交事务,所以它的oldTransactionInfo也应该是空了。
在这个小插曲之后,么接下来就应该是到提交事务了,之前在AService的方法出栈时,我们拿到了它入栈时创建的 TransactionInfo对象,这
个对象中包含了AService的方法事务状态。即TransactionStatus对象,很显然,太显然了,事务提交中的任何属性都和事务开始时的创建的对
象息息相关,这个TransactionStatus对象哪里来的,我们再回头看看 createTransactionIfNessary方法吧:
如果事务是一个独立的新事务的话,那么就会提交,不然不会做出动作,而把提交的动作给了doFinally中恢复的oldTrasactionInfo了;
protected void doCommitTransactionAfterReturning(TransactionInfo txInfo) {
if (txInfo != null && txInfo.hasTransaction()) {
if (logger.isDebugEnabled()) {
logger.debug("Invoking commit for transaction on " + txInfo.joinpointIdentification());
}
this.transactionManager.commit(txInfo.getTransactionStatus());
}
}
在前几节,我们重新复习了数据源,连接池,以及分布式事务的知识,在这一节中,我们详细的来分析一下Spring的事务的实现;
Spring事务的实现是建立在Aop的基础上,在Aop的基础上,Spring避免了硬编码的事务声明方式,改在配置文件中声明,从而增强了灵活性,并且了紧耦合;
首先,我们来看一下Spring的配置文件的生成;
<bean id="coreyDao" name="coreyDao"
class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean"
abstract="false" lazy-init="default" autowire="default"
dependency-check="default">
<property name="target">
<ref bean="coreyRealDao"></ref>
</property>
<property name="transactionManager">
<ref bean="transactionManager"></ref>
</property>
<property name="transactionAttributes">
<props>
<prop key="*">PROPAGATION_REQUIRED</prop>
</props>
</property>
</bean>
我们通过获取了coreyDao能够得到一个具有事务的coreyRealDao的代理对象,他的代理规则被详细的描述在transactionAttributes的properties中;
那么,现在,我们就开始分析一个个具体的类;
从上面的类图我们可以看见,首先由一个代理类代理了普通的数据库事务类,这个ProxyFactoryBean含有一个拦截器,并且对拦截器进行初始化;
下面是该ProxyFacrotyBean的属性;
//拦截器;
private final TransactionInterceptor transactionInterceptor = new TransactionInterceptor();
//代理的目标类。同proxyFactoryBean
private Object target;
//代理接口
private Class[] proxyInterfaces;
//切面;
private Pointcut pointcut;
//前拦截器
private Object[] preInterceptors;
//后拦截器
private Object[] postInterceptors;
//最后生成的代理类,利用FactoryBean的getObject()返回;
private Object proxy;
在这个类中,我们可以设置transactionAttributes,PlatformTransactionManager等等,目的是初始化transactionInterceptor;
public void setTransactionManager(PlatformTransactionManager transactionManager) {
this.transactionInterceptor.setTransactionManager(transactionManager);
}
public void setTransactionAttributes(Properties transactionAttributes) {
this.transactionInterceptor.setTransactionAttributes(transactionAttributes);
}
public void setTransactionAttributeSource(TransactionAttributeSource transactionAttributeSource) {
this.transactionInterceptor.setTransactionAttributeSource(transactionAttributeSource);
}
在下面这段中,实现了一个非常有趣的功能;
public void setBeanFactory(BeanFactory beanFactory) {
if (this.transactionInterceptor.getTransactionManager() == null &&
beanFactory instanceof ListableBeanFactory) {
ListableBeanFactory lbf = (ListableBeanFactory) beanFactory;
PlatformTransactionManager ptm = (PlatformTransactionManager)
BeanFactoryUtils.beanOfTypeIncludingAncestors(lbf, PlatformTransactionManager.class);
this.transactionInterceptor.setTransactionManager(ptm);
}
}
如果我们没有显示的为该ProxyFactoryBean制定TM,那么就会默认把ioc容器里面的唯一的一个PlatformTransactionManager类型的bean设置给他(但是如果超过一个,就会抛出异常);
其下,我们来好好琢磨琢磨这个具有事务功能的代理类是如何生成的;
public void afterPropertiesSet() {
//这个类判断你是否设置了TM和transactionAttributes
this.transactionInterceptor.afterPropertiesSet();
//检查是否设置类代理的目标类
if (this.target == null) {
throw new IllegalArgumentException("'target' is required");
}
//代理类不能为String类型;
if (this.target instanceof String) {
throw new IllegalArgumentException("'target' needs to be a bean reference, not a bean name as value");
}
//实例化代理工厂,为生成代理类做准备,我们在AOP一节已经分析过了;
ProxyFactory proxyFactory = new ProxyFactory();
//结合我们所提供的装备和接口以及切面,生成了一个代理类;
if (this.preInterceptors != null) {
for (int i = 0; i < this.preInterceptors.length; i++) {
proxyFactory.addAdvisor(this.advisorAdapterRegistry.wrap(this.preInterceptors[i]));
}
}
if (this.pointcut != null) {
Advisor advice = new DefaultPointcutAdvisor(this.pointcut, this.transactionInterceptor);
proxyFactory.addAdvisor(advice);
}
else {
// Rely on default pointcut.
proxyFactory.addAdvisor(new TransactionAttributeSourceAdvisor(this.transactionInterceptor));
// Could just do the following, but it's usually less efficient because of AOP advice chain caching.
// proxyFactory.addAdvice(transactionInterceptor);
}
if (this.postInterceptors != null) {
for (int i = 0; i < this.postInterceptors.length; i++) {
proxyFactory.addAdvisor(this.advisorAdapterRegistry.wrap(this.postInterceptors[i]));
}
}
proxyFactory.copyFrom(this);
TargetSource targetSource = createTargetSource(this.target);
proxyFactory.setTargetSource(targetSource);
if (this.proxyInterfaces != null) {
proxyFactory.setInterfaces(this.proxyInterfaces);
}
else if (!isProxyTargetClass()) {
// Rely on AOP infrastructure to tell us what interfaces to proxy.
proxyFactory.setInterfaces(ClassUtils.getAllInterfacesForClass(targetSource.getTargetClass()));
}
//代理类生成了;
this.proxy = getProxy(proxyFactory);
}
经过上面的步骤,我们已经知道了代理类的生成过程,那么这个代理类是如何具有事务功能的呢,我们只知道他被transactionInterceptor进行了拦截,那么在这个拦截器中具体做了什么样的操作,我们再来具体的分析一下transactionInterceptor;
上图我们可看见了transactionInterceptor的基本的类图,他包含一组TransactionInfo,TransactionInfo是线程变量,这说明,一个线程只可能拥有一个TransactionInfo,线程和线程之间的事务是互不关联,互不影响,线程安全的;
ThreadLocal我们在前几节已经介绍了:
private static final ThreadLocal currentTransactionInfo = new ThreadLocal();
public static TransactionStatus currentTransactionStatus() throws NoTransactionException {
return currentTransactionInfo().transactionStatus;
}
protected static TransactionInfo currentTransactionInfo() throws NoTransactionException {
TransactionInfo info = (TransactionInfo) currentTransactionInfo.get();
if (info == null) {
throw new NoTransactionException("No transaction aspect-managed TransactionStatus in scope");
}
return info;
}
事务管理器对系统的事务进行同意管理,在这里PlatformTransactionManager 屏蔽了事务管理器之间的不同,比如jdbc事务管理,hibernate事务管理,jms事务管理等等,在这里,使得事务的实现和事务管理器之间解耦开来,跟我们前几节中大对象的生成了数据库之间的耦合有异曲同工之妙,到时候,我们只要改变配置就可以更换事务的实现;
protected PlatformTransactionManager transactionManager;
现在,有人不仅仅要问,代理类是怎么知道在目标代理类中,什么方法(现在事务声明的细粒度是方法)需要进行事务管理,什么方法不要,下面我们就会说到这个功能的实现;
protected TransactionAttributeSource transactionAttributeSource;
public interface TransactionAttributeSource {
TransactionAttribute getTransactionAttribute(Method method, Class targetClass);
}
TransactionAttributeSource 是一个TransactionAttribute的管理类,他有许多具体的实现,其中最为常用的是也是默认的是:
在transactionInterceptor初始化的时候:
public void setTransactionAttributes(Properties transactionAttributes) {
NameMatchTransactionAttributeSource tas = new NameMatchTransactionAttributeSource();
tas.setProperties(transactionAttributes);
this.transactionAttributeSource = tas;
}
NameMatchTransactionAttributeSource tas = new NameMatchTransactionAttributeSource();被作为了默认的实现,我们现在来看看看这个
NameMatchTransactionAttributeSource类的实现细节;他含有一个hashMap来存储transactionAttribute,其中transactionAttribute为值,需要拦截的方法为key;
private Map nameMap = new HashMap();
public void setProperties(Properties transactionAttributes) {
TransactionAttributeEditor tae = new TransactionAttributeEditor();
for (Iterator it = transactionAttributes.keySet().iterator(); it.hasNext(); ) {
String methodName = (String) it.next();
String value = transactionAttributes.getProperty(methodName);
tae.setAsText(value);
TransactionAttribute attr = (TransactionAttribute) tae.getValue();
//形成方法名和事务属性对象的映射;
addTransactionalMethod(methodName, attr);
}
}
我们可以从上看见properties的entry到transactionAttribute的转换,这个是从value到Object的转换,这让我们想起了什么,对就是textEditor,我们来看看TransactionAttributeEditor是怎么进行这次移花接木的:
public void setAsText(String text) throws IllegalArgumentException {
if (StringUtils.hasLength(text)) {
//把<prop key="*">PROPAGATION_REQUIRED,timeout_21,ISOLATIONXX</prop>中的PROPAGATION_REQUIRED拿出来用 //逗号隔开,分成数组;
String[] tokens = StringUtils.commaDelimitedListToStringArray(text);
//生成RuleBasedTransactionAttribute();
RuleBasedTransactionAttribute attr = new RuleBasedTransactionAttribute();
for (int i = 0; i < tokens.length; i++) {
//除去前后空白字符串
String token = StringUtils.trimWhitespace(tokens[i].trim());
如果中间含有空白字符,抛出异常;
if (StringUtils.containsWhitespace(token)) {
throw new IllegalArgumentException(
"Transaction attribute token contains illegal whitespace: [" + token + "]");
}
//辨别属性,并且设置到RuleBasedTransactionAttribute相应的属性字段里面;
if (token.startsWith(TransactionDefinition.PROPAGATION_CONSTANT_PREFIX)) {
attr.setPropagationBehaviorName(token);
}
else if (token.startsWith(TransactionDefinition.ISOLATION_CONSTANT_PREFIX)) {
attr.setIsolationLevelName(token);
}
else if (token.startsWith(DefaultTransactionAttribute.TIMEOUT_PREFIX)) {
String value = token.substring(DefaultTransactionAttribute.TIMEOUT_PREFIX.length());
attr.setTimeout(Integer.parseInt(value));
}
else if (token.equals(DefaultTransactionAttribute.READ_ONLY_MARKER)) {
attr.setReadOnly(true);
}
else if (token.startsWith(DefaultTransactionAttribute.COMMIT_RULE_PREFIX)) {
attr.getRollbackRules().add(new NoRollbackRuleAttribute(token.substring(1)));
}
else if (token.startsWith(DefaultTransactionAttribute.ROLLBACK_RULE_PREFIX)) {
attr.getRollbackRules().add(new RollbackRuleAttribute(token.substring(1)));
}
else {
throw new IllegalArgumentException("Invalid transaction attribute token: [" + token + "]");
}
}
setValue(attr);
}
else {
setValue(null);
}
}
到时候如何取出这个事务属性对象呢,我们看见在配置文件中有配置*,这好像是正则表达式的应用,但是很遗憾的是,这里并不支持完整的正则表达式匹配,只是支持简单的行首和行尾的*代表任意多的任意字符而已,不过,这是一个很好的扩展点,我们自己可以试着实现;
public TransactionAttribute getTransactionAttribute(Method method, Class targetClass) {
//首先,得到方法元对象的方法名字;
String methodName = method.getName();
//从hashMap中取出;
TransactionAttribute attr = (TransactionAttribute) this.nameMap.get(methodName);
if (attr == null) {
//如果为空;进行*的匹配
String bestNameMatch = null;
for (Iterator it = this.nameMap.keySet().iterator(); it.hasNext();) {
String mappedName = (String) it.next();
//*号开头的只要能匹配后面的字符即可,*结尾的只要能匹配前面的字符串即可;
if (isMatch(methodName, mappedName) &&
(bestNameMatch == null || bestNameMatch.length() <= mappedName.length())) {
attr = (TransactionAttribute) this.nameMap.get(mappedName);
bestNameMatch = mappedName;
}
}
}
return attr;
}
//*号开头的只要能匹配后面的字符即可,*结尾的只要能匹配前面的字符串即可;
protected boolean isMatch(String methodName, String mappedName) {
return (mappedName.endsWith("*") && methodName.startsWith(mappedName.substring(0, mappedName.length() - 1))) ||
(mappedName.startsWith("*") && methodName.endsWith(mappedName.substring(1, mappedName.length())));
}
接下来,我们可以先来看下,到底这个transactionAttribute这个对象;
public interface TransactionDefinition {
String PROPAGATION_CONSTANT_PREFIX = "PROPAGATION";
String ISOLATION_CONSTANT_PREFIX = "ISOLATION";
//传播途径
int getPropagationBehavior();
//隔离级别
int getIsolationLevel();
//有效时间
int getTimeout();
//是否只读
boolean isReadOnly();
//对象名字
String getName();
}
public interface TransactionAttribute extends TransactionDefinition {
//在此基础上增加了回滚判断机制,以便事务在遇到制定异常的时候进行回滚;
boolean rollbackOn(Throwable ex);
}
在下面,我们来介绍一下TransactionInfo;TransactionInfo其实就犹如TransactionAttributeSource hashMap中的一项;
TransactionInfo是TransactionAspectSupport的一个内部类,它的主要功能是记录方法和对应的事务属性
protected class TransactionInfo {
private final TransactionAttribute transactionAttribute;
private final Method method;
private TransactionStatus transactionStatus;
private TransactionInfo oldTransactionInfo;
public TransactionInfo(TransactionAttribute transactionAttribute, Method method) {
this.transactionAttribute = transactionAttribute;
this.method = method;
}
下面我们来看一下,这个拦截器的具体的拦截方式把;
public Object invoke(MethodInvocation invocation) throws Throwable {
//获取代理目标类的类型;
Class targetClass = (invocation.getThis() != null ? invocation.getThis().getClass() : null);
//根据当前拦截的方法,取得一个相对应的transactionInfo,不过当然不一定就有,所以名字都叫necessary;
TransactionInfo txInfo = createTransactionIfNecessary(invocation.getMethod(), targetClass);
Object retVal = null;
try {
//执行该方法;
retVal = invocation.proceed();
}
catch (Throwable ex) {
//如果方法抛出异常,那么采用异常处理机制;
doCloseTransactionAfterThrowing(txInfo, ex);
throw ex;
}
finally {
//采用finally处理;
doFinally(txInfo);
}
//正常结束的处理;
doCommitTransactionAfterReturning(txInfo);
return retVal;
}
在开始的时候,我们的TransactionAttributeSource只是存储了代表方法的字符串和TransactionAttribute的对应哈西表,但没有建立方法对象Method实例与TransactionAttribute之间的对应,那么createTransactionIfNecessary就是为了实现这个功能;
protected TransactionInfo createTransactionIfNecessary(Method method, Class targetClass) {
// 根据方法找到对应的TransactionAttribute对象,如果没有找到的话,那么该方法就不会被拦截;
final TransactionAttribute sourceAttr =
this.transactionAttributeSource.getTransactionAttribute(method, targetClass);
TransactionAttribute txAttr = sourceAttr;
// 如果该TransacrionAttribute没有设置名字,那么会根据将className.methodName作为该TransactionAttribute的名字,
//这里是典型的代理模式的应用;
if (txAttr != null && txAttr.getName() == null) {
final String name = methodIdentification(method);
txAttr = new DelegatingTransactionAttribute(sourceAttr) {
public String getName() {
return name;
}
};
}
//生成了method和transactionAttribute相对应的transactionInfo实例;
TransactionInfo txInfo = new TransactionInfo(txAttr, method);
if (txAttr != null) {
// We need a transaction for this method
if (logger.isDebugEnabled()) {
logger.debug("Getting transaction for " + txInfo.joinpointIdentification());
}
// The transaction manager will flag an error if an incompatible tx already exists
txInfo.newTransactionStatus(this.transactionManager.getTransaction(txAttr));
}
else {
// The TransactionInfo.hasTransaction() method will return
// false. We created it only to preserve the integrity of
// the ThreadLocal stack maintained in this class.
if (logger.isDebugEnabled())
logger.debug("Don't need to create transaction for [" + methodIdentification(method) +
"]: this method isn't transactional");
}
//在这里,我们可以看见这个transactionInfo绑定到该线程上去;
//如果当前线程存在未结束的事务,那么我们会把旧transactionInfo设置为新的transactionInfo的oldTransactionInfo
txInfo.bindToThread();
return txInfo;
}
//保存旧的transactionInfo是因为考虑到事务传播途径的判断;
private void bindToThread() {
// Expose current TransactionStatus, preserving any existing transactionStatus for
// restoration after this transaction is complete.
oldTransactionInfo = (TransactionInfo) currentTransactionInfo.get();
currentTransactionInfo.set(this);
}
事务的新状态;
public final TransactionStatus getTransaction(TransactionDefinition definition) throws TransactionException {
//留给子类实现,比如jdbc会获取DatabaseTransaction,而jta会从jndi获取UserTrasction获取transaction
Object transaction = doGetTransaction();
// Cache debug flag to avoid repeated checks.
boolean debugEnabled = logger.isDebugEnabled();
if (debugEnabled) {
logger.debug("Using transaction object [" + transaction + "]");
}
if (definition == null) {
//如果为空,就会创建一个默认的trasnactionDefinition;
definition = new DefaultTransactionDefinition();
}
if (isExistingTransaction(transaction)) {
//处理已经存在的transaction,返回其状态;
return handleExistingTransaction(definition, transaction, debugEnabled);
}
// Check definition settings for new transaction.
if (definition.getTimeout() < TransactionDefinition.TIMEOUT_DEFAULT) {
throw new InvalidTimeoutException("Invalid transaction timeout", definition.getTimeout());
}
// No existing transaction found -> check propagation behavior to find out how to proceed.
if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_MANDATORY) {
throw new IllegalTransactionStateException(
"No existing transaction found for transaction marked with propagation 'mandatory'");
}
else if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRED ||
definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW ||
definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NESTED) {
Object suspendedResources = suspend(null);
if (debugEnabled) {
logger.debug("Creating new transaction with name [" + definition.getName() + "]: " +
definition);
}
doBegin(transaction, definition);
boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
return newTransactionStatus(
definition, transaction, true, newSynchronization, debugEnabled, suspendedResources);
}
else {
// Create "empty" transaction: no actual transaction, but potentially synchronization.
boolean newSynchronization = (getTransactionSynchronization() == SYNCHRONIZATION_ALWAYS);
return newTransactionStatus(definition, null, false, newSynchronization, debugEnabled, null);
}
}
//会根据传播途径来返回相应的事务状态类;
private TransactionStatus handleExistingTransaction(
TransactionDefinition definition, Object transaction, boolean debugEnabled)
throws TransactionException {
//never不能处在事务中,否则抛出异常;
if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NEVER) {
throw new IllegalTransactionStateException(
"Existing transaction found for transaction marked with propagation 'never'");
}
//NOT_SUPPORTED不能处在事务中,否则将当前事务挂起;
if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NOT_SUPPORTED) {
if (debugEnabled) {
logger.debug("Suspending current transaction");
}
//挂起当前事务;
Object suspendedResources = suspend(transaction);
boolean newSynchronization = (getTransactionSynchronization() == SYNCHRONIZATION_ALWAYS);
//不是新的事务;
return newTransactionStatus(
definition, null, false, newSynchronization, debugEnabled, suspendedResources);
}
//REQUIRES_NEW要求挂起当前事务并且要求一个新的事务;
if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW) {
if (debugEnabled) {
logger.debug("Suspending current transaction, creating new transaction with name [" +
definition.getName() + "]");
}
SuspendedResourcesHolder suspendedResources = suspend(transaction);
try {
doBegin(transaction, definition);
}
catch (TransactionException beginEx) {
try {
resume(transaction, suspendedResources);
}
catch (TransactionException resumeEx) {
logger.error(
"Inner transaction begin exception overridden by outer transaction
resume exception", beginEx);
throw resumeEx;
}
throw beginEx;
}
boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
//新的事务;
return newTransactionStatus(
definition, transaction, true, newSynchronization, debugEnabled, suspendedResources);
}
//PROPAGATION_NESTED代表嵌入式事务;
if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NESTED) {
if (!isNestedTransactionAllowed()) {
throw new NestedTransactionNotSupportedException(
"Transaction manager does not allow nested transactions by default - " +
"specify 'nestedTransactionAllowed' property with value 'true'");
}
if (debugEnabled) {
logger.debug("Creating nested transaction with name [" + definition.getName() + "]");
}
if (useSavepointForNestedTransaction()) {
//生成新的储存点
DefaultTransactionStatus status =
newTransactionStatus(definition, transaction, false, false, debugEnabled,
null);
status.createAndHoldSavepoint();
return status;
}
else {
//在这里会开始新的事务,至于这个新的事务如何开始,与具体的实现有关系,所以会利通模板模式
//推迟到子类中实现,比如下面的两种实现方式;
doBegin(transaction, definition);
boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
return newTransactionStatus(definition, transaction, true, newSynchronization, debugEnabled,
null);
}
}
// Assumably PROPAGATION_SUPPORTS.
if (debugEnabled) {
logger.debug("Participating in existing transaction");
}
boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
return newTransactionStatus(definition, transaction, false, newSynchronization, debugEnabled, null);
}
JDBC的doBegin:
protected void doBegin(Object transaction, TransactionDefinition definition) {
DataSourceTransactionObject txObject = (DataSourceTransactionObject) transaction;
Connection con = null;
try {
if (txObject.getConnectionHolder() == null ||
txObject.getConnectionHolder().isSynchronizedWithTransaction()) {
Connection newCon = this.dataSource.getConnection();
if (logger.isDebugEnabled()) {
logger.debug("Acquired Connection [" + newCon + "] for JDBC transaction");
}
txObject.setConnectionHolder(new ConnectionHolder(newCon), true);
}
txObject.getConnectionHolder().setSynchronizedWithTransaction(true);
con = txObject.getConnectionHolder().getConnection();
Integer previousIsolationLevel = DataSourceUtils.prepareConnectionForTransaction(con, definition);
txObject.setPreviousIsolationLevel(previousIsolationLevel);
// Switch to manual commit if necessary. This is very expensive in some JDBC drivers,
// so we don't want to do it unnecessarily (for example if we've explicitly
// configured the connection pool to set it already).
if (con.getAutoCommit()) {
txObject.setMustRestoreAutoCommit(true);
if (logger.isDebugEnabled()) {
logger.debug("Switching JDBC Connection [" + con + "] to manual commit");
}
con.setAutoCommit(false);
}
txObject.getConnectionHolder().setTransactionActive(true);
int timeout = determineTimeout(definition);
if (timeout != TransactionDefinition.TIMEOUT_DEFAULT) {
txObject.getConnectionHolder().setTimeoutInSeconds(timeout);
}
// Bind the session holder to the thread.
if (txObject.isNewConnectionHolder()) {
TransactionSynchronizationManager.bindResource(getDataSource(),
txObject.getConnectionHolder());
}
}
catch (SQLException ex) {
DataSourceUtils.releaseConnection(con, this.dataSource);
throw new CannotCreateTransactionException("Could not open JDBC Connection for transaction", ex);
}
}
利用了JDBC的setAutoCommit()来实现事务的开始;
JTA事务的doBegin:
protected void doJtaBegin(JtaTransactionObject txObject, TransactionDefinition definition)
throws NotSupportedException, SystemException {
applyIsolationLevel(txObject, definition.getIsolationLevel());
applyTimeout(txObject, definition.getTimeout());
txObject.getUserTransaction().begin();
}
利用了Usertransaction.begin来实现事务的开始;
事务状态的5个基本属性;
public DefaultTransactionStatus(
Object transaction, boolean newTransaction, boolean newSynchronization,
boolean readOnly, boolean debug, Object suspendedResources) {
//当前事务属性的事务
this.transaction = transaction;
//是否是一个新的事务;
this.newTransaction = newTransaction;
//事务同步
this.newSynchronization = newSynchronization;
//这个事务是只读事务;
this.readOnly = readOnly;
//是否显示调试信息;
this.debug = debug;
//当前事务的被挂载起来的资源装载对象;
this.suspendedResources = suspendedResources;
}
//在方法拦截中,会根据不同的传播途径生成的事务状态来执行不同的操作;
public Object invoke(MethodInvocation invocation) throws Throwable {
// Work out the target class: may be <code>null</code>.
// The TransactionAttributeSource should be passed the target class
// as well as the method, which may be from an interface
Class targetClass = (invocation.getThis() != null ? invocation.getThis().getClass() : null);
// Create transaction if necessary.
TransactionInfo txInfo = createTransactionIfNecessary(invocation.getMethod(), targetClass);
Object retVal = null;
try {
// This is an around advice.
// Invoke the next interceptor in the chain.
// This will normally result in a target object being invoked.
retVal = invocation.proceed();
}
catch (Throwable ex) {
// target invocation exception
doCloseTransactionAfterThrowing(txInfo, ex);
throw ex;
}
finally {
doFinally(txInfo);
}
doCommitTransactionAfterReturning(txInfo);
return retVal;
}
}
doFinally操作是无论那个方法不管什么事务属性都会要做的:
protected void doFinally(TransactionInfo txInfo) {
if (txInfo != null) {
txInfo.restoreThreadLocalStatus();
}
}
他把上一个事务信息传入了线程中间,回复了当前线程的事务信息;
在这里,jiwenke发表在javaeye中的解释,已经很详细了:
其中的doFinally(txInfo)那一行很重要,也就是说不管如何,这个doFinally方法都是要被调用的,为什么它这么重要呢,举个例子:
我们还是以propregation_required来举例子吧,假设情况是这样的,AService中有一个方法调用了BService中的,这两个方法都处在事务体之
中,他们的传播途径都是required。那么调用开始了,AService的方法首先入方法栈,并创建了 TransactionInfo的实例,接着BService的方
法入栈,又创建了一个TransactionInfo的实例,而重点要说明的是 TransactionInfo是一个自身关联的内部类,第二个方法入栈时,会给新创
建的TransactionInfo的实例设置一个属性,就是 TransactionInfo对象中的private TransactionInfo oldTransactionInfo;属性,这个属性
表明BService方法的创建的TransactionInfo对象是有一个old的 transactionInfo对象的,这个oldTransactionInfo对象就是AService方法入
栈时创建的 TransactionInfo对象,我们还记得在createTransactionIfNecessary方法里有这样一个方法吧:
protected TransactionInfo createTransactionIfNecessary(Method method, Class targetClass) {
// We always bind the TransactionInfo to the thread, even if we didn't create
// a new transaction here. This guarantees that the TransactionInfo stack
// will be managed correctly even if no transaction was created by this aspect.
txInfo.bindToThread();
return txInfo;
}
就是这个bindToThread()方法在作怪:
private void bindToThread() {
// Expose current TransactionStatus, preserving any existing transactionStatus for
// restoration after this transaction is complete.
oldTransactionInfo = (TransactionInfo) currentTransactionInfo.get();
currentTransactionInfo.set(this);
}
如果当前线程中已经有了一个TransactionInfo,则拿出来放到新建的transactionInfo对象的oldTransactionInfo属性中,然后再把新建的Tra
nsactionInfo设置到当前线程中。
这里有一个概念要搞清楚,就是TransactionInfo对象并不是表明事务状态的对象,表明事务状态的对象是TransactionStatus对象,这个对象
同样是TransactionInfo的一个属性(这一点,我在前面一篇文章中并没有讲清楚)。
接下来BService中的那个方法返回,那么该它退栈了,它退栈后要做的就是doFinally方法,即把它的 oldTransactionInfo设置到当前线程中
(这个TransactionInfo对象显然就是AService方法入栈时创建的,怎么现在又要设置到线程中去呢,原因就是BService的方法出栈时并不提交
事务,因为BService的传播途径是required,所以要把栈顶的方法所创建 transactioninfo给设置到当前线程中),即调用AService的方法时
所创建的TransactionInfo对象。那么在 AServie的方法出栈时同样会设置TransactionInfo对象的oldTransactionInfo到当前线程,这时候显
然 oldTransactionInfo是空的,但AService中的方法会提交事务,所以它的oldTransactionInfo也应该是空了。
在这个小插曲之后,么接下来就应该是到提交事务了,之前在AService的方法出栈时,我们拿到了它入栈时创建的 TransactionInfo对象,这
个对象中包含了AService的方法事务状态。即TransactionStatus对象,很显然,太显然了,事务提交中的任何属性都和事务开始时的创建的对
象息息相关,这个TransactionStatus对象哪里来的,我们再回头看看 createTransactionIfNessary方法吧:
如果事务是一个独立的新事务的话,那么就会提交,不然不会做出动作,而把提交的动作给了doFinally中恢复的oldTrasactionInfo了;
protected void doCommitTransactionAfterReturning(TransactionInfo txInfo) {
if (txInfo != null && txInfo.hasTransaction()) {
if (logger.isDebugEnabled()) {
logger.debug("Invoking commit for transaction on " + txInfo.joinpointIdentification());
}
this.transactionManager.commit(txInfo.getTransactionStatus());
}
}