代码块1:invoke
TransactionInterceptor.class
@Override
@Nullable
public Object invoke(MethodInvocation invocation) throws Throwable {
// Work out the target class: may be {@code null}.
// The TransactionAttributeSource should be passed the target class
// as well as the method, which may be from an interface.
//获取目标类 见 内部代码块1
Class<?> targetClass = (invocation.getThis() != null ? AopUtils.getTargetClass(invocation.getThis()) : null);
// Adapt to TransactionAspectSupport's invokeWithinTransaction...
//见 内部代码块2
return invokeWithinTransaction(invocation.getMethod(), targetClass, invocation::proceed);
}
内部代码块1:AopUtils.getTargetClass(invocation.getThis())
AopUtils.class
/**
* Determine the target class of the given bean instance which might be an AOP proxy.
* <p>Returns the target class for an AOP proxy or the plain class otherwise.
* @param candidate the instance to check (might be an AOP proxy)
* @return the target class (or the plain class of the given object as fallback;
* never {@code null})
* @see org.springframework.aop.TargetClassAware#getTargetClass()
* @see org.springframework.aop.framework.AopProxyUtils#ultimateTargetClass(Object)
*/
//如果是代理类,就返回代理类的目标类。否则,如果是普通类就返回该类本身
public static Class<?> getTargetClass(Object candidate) {
Assert.notNull(candidate, "Candidate object must not be null");
Class<?> result = null;
if (candidate instanceof TargetClassAware) {
result = ((TargetClassAware) candidate).getTargetClass();
}
if (result == null) {
//如果是cglib则返回目标对象的父类,否则为jdk的动态代理,直接返回目标对象
result = (isCglibProxy(candidate) ? candidate.getClass().getSuperclass() : candidate.getClass());
}
return result;
}
内部代码块2:
TransactionAspectSupport.class
/**
* General delegate for around-advice-based subclasses, delegating to several other template
* methods on this class. Able to handle {@link CallbackPreferringPlatformTransactionManager}
* as well as regular {@link PlatformTransactionManager} implementations.
* @param method the Method being invoked
* @param targetClass the target class that we're invoking the method on
* @param invocation the callback to use for proceeding with the target invocation
* @return the return value of the method, if any
* @throws Throwable propagated from the target invocation
*/
@Nullable
protected Object invokeWithinTransaction(Method method, @Nullable Class<?> targetClass,
final InvocationCallback invocation) throws Throwable {
// If the transaction attribute is null, the method is non-transactional.
//如果某个方法的事务属性为空,则这个方法是非事务的
//获取事务属性 见,内部代码块3:getTransactionAttributeSource
TransactionAttributeSource tas = getTransactionAttributeSource();
//获取与目标方法对应的TransactionAttribute (事件属性),见 内部代码块7 tas.getTransactionAttribute(method, targetClass)
final TransactionAttribute txAttr = (tas != null ? tas.getTransactionAttribute(method, targetClass) : null);
//获取事务管理器(用于做事务的提交、回滚等操作的)
//见 内部代码块8:determineTransactionManager
final PlatformTransactionManager tm = determineTransactionManager(txAttr);
//获取方法名字,做日志用的不重要
final String joinpointIdentification = methodIdentification(method, targetClass, txAttr);
//一般会执行if里面的语句
if (txAttr == null || !(tm instanceof CallbackPreferringPlatformTransactionManager)) {
// Standard transaction demarcation with getTransaction and commit/rollback calls.
//该对象能获取事务、提交事务、回滚事务
//这个方法内部会开启事务
// 见 内部代码块9:createTransactionIfNecessary
TransactionInfo txInfo = createTransactionIfNecessary(tm, txAttr, joinpointIdentification);
//下面的代码就是执行具体的我们所编写的业务逻辑
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.proceedWithInvocation();
}
catch (Throwable ex) {
// target invocation exception
//目标方法执行出现异常后,根据事务配置的信息判断是进行提交操作还是回滚操作
// 见:内部代码块14:completeTransactionAfterThrowing
completeTransactionAfterThrowing(txInfo, ex);
throw ex;
}
finally {
//恢复外出的事务:内层的事务执行完了,将当前ThreadLocal中的事务恢复成外层的事务,为外层事务的再次执行做准备
//事务的挂起操作就是这样执行的
cleanupTransactionInfo(txInfo);
}
//提交事务 见:内部代码块11:commitTransactionAfterReturning
commitTransactionAfterReturning(txInfo);
return retVal;
}
else {
final ThrowableHolder throwableHolder = new ThrowableHolder();
// It's a CallbackPreferringPlatformTransactionManager: pass a TransactionCallback in.
try {
Object result = ((CallbackPreferringPlatformTransactionManager) tm).execute(txAttr, status -> {
TransactionInfo txInfo = prepareTransactionInfo(tm, txAttr, joinpointIdentification, status);
try {
return invocation.proceedWithInvocation();
}
catch (Throwable ex) {
if (txAttr.rollbackOn(ex)) {
// A RuntimeException: will lead to a rollback.
if (ex instanceof RuntimeException) {
throw (RuntimeException) ex;
}
else {
throw new ThrowableHolderException(ex);
}
}
else {
// A normal return value: will lead to a commit.
throwableHolder.throwable = ex;
return null;
}
}
finally {
cleanupTransactionInfo(txInfo);
}
});
// Check result state: It might indicate a Throwable to rethrow.
if (throwableHolder.throwable != null) {
throw throwableHolder.throwable;
}
return result;
}
catch (ThrowableHolderException ex) {
throw ex.getCause();
}
catch (TransactionSystemException ex2) {
if (throwableHolder.throwable != null) {
logger.error("Application exception overridden by commit exception", throwableHolder.throwable);
ex2.initApplicationException(throwableHolder.throwable);
}
throw ex2;
}
catch (Throwable ex2) {
if (throwableHolder.throwable != null) {
logger.error("Application exception overridden by commit exception", throwableHolder.throwable);
}
throw ex2;
}
}
}
内部代码块3:getTransactionAttributeSource
TransactionAspectSupport.class 这个类是TransactionInterceptor 的父类
public TransactionAttributeSource getTransactionAttributeSource() {
//这里直接获取这个属性,那这个属性是在什么时候赋值的呢???
//见 内部代码块4
return this.transactionAttributeSource;
}
内部代码块4:
public void setTransactionAttributes(Properties transactionAttributes) {
NameMatchTransactionAttributeSource tas = new NameMatchTransactionAttributeSource();
//往NameMatchTransactionAttributeSource中设置好事件属性 见 内部代码块5
tas.setProperties(transactionAttributes);
//成员属性赋值,TransactionAttributeSource是对事件属性对象的包装
this.transactionAttributeSource = tas;
}
内部代码块5:
/**
* Parses the given properties into a name/attribute map.
* Expects method names as keys and String attributes definitions as values,
* parsable into TransactionAttribute instances via TransactionAttributeEditor.
* @see #setNameMap
* @see TransactionAttributeEditor
*/
//将给定的属性解析为名称/属性映射。期望方法名为键,字符串属性定义为值,可通过TransactionAttributeEditor解析为TransactionAttribute实例。
public void setProperties(Properties transactionAttributes) {
TransactionAttributeEditor tae = new TransactionAttributeEditor();
//获取属性名字的枚举
Enumeration<?> propNames = transactionAttributes.propertyNames();
//遍历属性名枚举
while (propNames.hasMoreElements()) {
//获取key,也就是方法名
String methodName = (String) propNames.nextElement();
//获取方法名对应的value,也就是属性值,这里获取到的value的格式 如:PROPAGATION_REQUIRED,readOnly
String value = transactionAttributes.getProperty(methodName);
//处理value 见 内部代码块6
tae.setAsText(value);
//获取事件属性,这个事件属性是当前methodName 所对应的事件属性,因为这个属性是刚刚在 内部代码块6 中设置好的
TransactionAttribute attr = (TransactionAttribute) tae.getValue();
//private Map<String, TransactionAttribute> nameMap = new HashMap<>();
//将方法名称和事件属性设置到nameMap (key:方法名称 value:事件属性)
addTransactionalMethod(methodName, attr);
}
}
内部代码块6:setAsText
TransactionAttributeEditor.class
/**
* Format is PROPAGATION_NAME,ISOLATION_NAME,readOnly,timeout_NNNN,+Exception1,-Exception2.
* Null or the empty string means that the method is non transactional.
* @see java.beans.PropertyEditor#setAsText(java.lang.String)
*/
@Override
public void setAsText(String text) throws IllegalArgumentException {
if (StringUtils.hasLength(text)) {
// tokenize it with ","
//通过 逗号 把value值分割成一个数组
String[] tokens = StringUtils.commaDelimitedListToStringArray(text);
//tokens 数组中的值会被注册成为RuleBasedTransactionAttribute 中的一个一个属性,也就是说TransactionAttribute对象的作用就是封装事务属性的
//通过观察RuleBasedTransactionAttribute 的继承体系,可以看出这个类里面定义了很多事务属性相关的变量,所以我们在配置文件中配置的事务属性就是来自于这里
RuleBasedTransactionAttribute attr = new RuleBasedTransactionAttribute();
//下面就是循环设值了
for (int i = 0; i < tokens.length; i++) {
// Trim leading and trailing whitespace.
String token = StringUtils.trimWhitespace(tokens[i].trim());
// Check whether token contains illegal whitespace within text.
if (StringUtils.containsWhitespace(token)) {
throw new IllegalArgumentException(
"Transaction attribute token contains illegal whitespace: [" + token + "]");
}
// Check token type.
if (token.startsWith(RuleBasedTransactionAttribute.PREFIX_PROPAGATION)) {
attr.setPropagationBehaviorName(token);
}
else if (token.startsWith(RuleBasedTransactionAttribute.PREFIX_ISOLATION)) {
attr.setIsolationLevelName(token);
}
else if (token.startsWith(RuleBasedTransactionAttribute.PREFIX_TIMEOUT)) {
String value = token.substring(DefaultTransactionAttribute.PREFIX_TIMEOUT.length());
attr.setTimeout(Integer.parseInt(value));
}
else if (token.equals(RuleBasedTransactionAttribute.READ_ONLY_MARKER)) {
attr.setReadOnly(true);
}
else if (token.startsWith(RuleBasedTransactionAttribute.PREFIX_COMMIT_RULE)) {
attr.getRollbackRules().add(new NoRollbackRuleAttribute(token.substring(1)));
}
else if (token.startsWith(RuleBasedTransactionAttribute.PREFIX_ROLLBACK_RULE)) {
attr.getRollbackRules().add(new RollbackRuleAttribute(token.substring(1)));
}
else {
throw new IllegalArgumentException("Invalid transaction attribute token: [" + token + "]");
}
}
//然后把事件属性对象设置进成员变量
setValue(attr);
}
else {
setValue(null);
}
}
内部代码块7:tas.getTransactionAttribute(method, targetClass)
NameMatchTransactionAttributeSource.class
@Override
@Nullable
public TransactionAttribute getTransactionAttribute(Method method, @Nullable Class<?> targetClass) {
if (!ClassUtils.isUserLevelMethod(method)) {
return null;
}
// Look for direct name match.
String methodName = method.getName();
//private Map<String, TransactionAttribute> nameMap = new HashMap<>();
TransactionAttribute attr = this.nameMap.get(methodName);
if (attr == null) {
// Look for most specific name match.
String bestNameMatch = null;
for (String mappedName : this.nameMap.keySet()) {
if (isMatch(methodName, mappedName) &&
(bestNameMatch == null || bestNameMatch.length() <= mappedName.length())) {
attr = this.nameMap.get(mappedName);
bestNameMatch = mappedName;
}
}
}
return attr;
}
内部代码块8:determineTransactionManager
/**
* Determine the specific transaction manager to use for the given transaction.
*/
//获取到给定事务中配置的事务管理器
@Nullable
protected PlatformTransactionManager determineTransactionManager(@Nullable TransactionAttribute txAttr) {
// Do not attempt to lookup tx manager if no tx attributes are set
if (txAttr == null || this.beanFactory == null) {
return getTransactionManager();
}
String qualifier = txAttr.getQualifier();
if (StringUtils.hasText(qualifier)) {
return determineQualifiedTransactionManager(this.beanFactory, qualifier);
}
else if (StringUtils.hasText(this.transactionManagerBeanName)) {
return determineQualifiedTransactionManager(this.beanFactory, this.transactionManagerBeanName);
}
else {
PlatformTransactionManager defaultTransactionManager = getTransactionManager();
if (defaultTransactionManager == null) {
defaultTransactionManager = this.transactionManagerCache.get(DEFAULT_TRANSACTION_MANAGER_KEY);
if (defaultTransactionManager == null) {
defaultTransactionManager = this.beanFactory.getBean(PlatformTransactionManager.class);
this.transactionManagerCache.putIfAbsent(
DEFAULT_TRANSACTION_MANAGER_KEY, defaultTransactionManager);
}
}
return defaultTransactionManager;
}
}
内部代码块9:createTransactionIfNecessary
/**
* Create a transaction if necessary based on the given TransactionAttribute.
* <p>Allows callers to perform custom TransactionAttribute lookups through
* the TransactionAttributeSource.
* @param txAttr the TransactionAttribute (may be {@code null})
* @param joinpointIdentification the fully qualified method name
* (used for monitoring and logging purposes)
* @return a TransactionInfo object, whether or not a transaction was created.
* The {@code hasTransaction()} method on TransactionInfo can be used to
* tell if there was a transaction created.
* @see #getTransactionAttributeSource()
*/
@SuppressWarnings("serial")
//如果需要,根据给定的TransactionAttribute创建一个事务
protected TransactionInfo createTransactionIfNecessary(@Nullable PlatformTransactionManager tm,
@Nullable TransactionAttribute txAttr, final String joinpointIdentification) {
// If no name specified, apply method identification as transaction name.
//给事务起一个名字,方便管理。如果没有指定名称,则应用方法标识作为事务名称。
if (txAttr != null && txAttr.getName() == null) {
txAttr = new DelegatingTransactionAttribute(txAttr) {
@Override
public String getName() {
return joinpointIdentification;
}
};
}
//表示事务运行时的状态,是TransactionInfo 中的一个属性
TransactionStatus status = null;
if (txAttr != null) {
if (tm != null) {
//通过事务管理器获取一个事务
//接口,见 内部代码块10:getTransaction
//具体实现类,见 第25章->代码块1 :getTransaction
status = tm.getTransaction(txAttr);
}
else {
if (logger.isDebugEnabled()) {
logger.debug("Skipping transactional joinpoint [" + joinpointIdentification +
"] because no transaction manager has been configured");
}
}
}
//见:第25章->代码块2 :prepareTransactionInfo
return prepareTransactionInfo(tm, txAttr, joinpointIdentification, status);
}
内部代码块10:getTransaction
PlatformTransactionManager.class
/**
* Return a currently active transaction or create a new one, according to
* the specified propagation behavior.
* <p>Note that parameters like isolation level or timeout will only be applied
* to new transactions, and thus be ignored when participating in active ones.
* <p>Furthermore, not all transaction definition settings will be supported
* by every transaction manager: A proper transaction manager implementation
* should throw an exception when unsupported settings are encountered.
* <p>An exception to the above rule is the read-only flag, which should be
* ignored if no explicit read-only mode is supported. Essentially, the
* read-only flag is just a hint for potential optimization.
* @param definition the TransactionDefinition instance (can be {@code null} for defaults),
* describing propagation behavior, isolation level, timeout etc.
* @return transaction status object representing the new or current transaction
* @throws TransactionException in case of lookup, creation, or system errors
* @throws IllegalTransactionStateException if the given transaction definition
* cannot be executed (for example, if a currently active transaction is in
* conflict with the specified propagation behavior)
* @see TransactionDefinition#getPropagationBehavior
* @see TransactionDefinition#getIsolationLevel
* @see TransactionDefinition#getTimeout
* @see TransactionDefinition#isReadOnly
*/
//返回当前活动的事务或创建一个新的事务指定的传播行为。注意,隔离级别(isolation level )或超时(timeout )之类的参数将只应用用于新事务,因此在参与活动事务时被忽略。
TransactionStatus getTransaction(@Nullable TransactionDefinition definition) throws TransactionException;
内部代码块11:commitTransactionAfterReturning
TransactionAspectSupport.class
/**
* Execute after successful completion of call, but not after an exception was handled.
* Do nothing if we didn't create a transaction.
* @param txInfo information about the current transaction
*/
protected void commitTransactionAfterReturning(@Nullable TransactionInfo txInfo) {
if (txInfo != null && txInfo.getTransactionStatus() != null) {
if (logger.isTraceEnabled()) {
logger.trace("Completing transaction for [" + txInfo.getJoinpointIdentification() + "]");
}
//提交事务 见:内部代码块12:commit
txInfo.getTransactionManager().commit(txInfo.getTransactionStatus());
}
}
内部代码块12:commit
AbstractPlatformTransactionManager.class
/**
* This implementation of commit handles participating in existing
* transactions and programmatic rollback requests.
* Delegates to {@code isRollbackOnly}, {@code doCommit}
* and {@code rollback}.
* @see org.springframework.transaction.TransactionStatus#isRollbackOnly()
* @see #doCommit
* @see #rollback
*/
@Override
public final void commit(TransactionStatus status) throws TransactionException {
if (status.isCompleted()) {
throw new IllegalTransactionStateException(
"Transaction is already completed - do not call commit or rollback more than once per transaction");
}
DefaultTransactionStatus defStatus = (DefaultTransactionStatus) status;
if (defStatus.isLocalRollbackOnly()) {
if (defStatus.isDebug()) {
logger.debug("Transactional code has requested rollback");
}
processRollback(defStatus, false);
return;
}
if (!shouldCommitOnGlobalRollbackOnly() && defStatus.isGlobalRollbackOnly()) {
if (defStatus.isDebug()) {
logger.debug("Global transaction is marked as rollback-only but transactional code requested commit");
}
processRollback(defStatus, true);
return;
}
//提交事务,最后这里面会执行:doCommit()方法 见 内部代码块13:doCommit
processCommit(defStatus);
}
内部代码块13:doCommit
DataSourceTransactionManager.class
@Override
protected void doCommit(DefaultTransactionStatus status) {
DataSourceTransactionObject txObject = (DataSourceTransactionObject) status.getTransaction();
Connection con = txObject.getConnectionHolder().getConnection();
if (status.isDebug()) {
logger.debug("Committing JDBC transaction on Connection [" + con + "]");
}
try {
//通过连接对象的事务提交方法,提交事务
con.commit();
}
catch (SQLException ex) {
throw new TransactionSystemException("Could not commit JDBC transaction", ex);
}
}
内部代码块14:completeTransactionAfterThrowing
TransactionAspectSupport.class
/**
* Handle a throwable, completing the transaction.
* We may commit or roll back, depending on the configuration.
* @param txInfo information about the current transaction
* @param ex throwable encountered
*/
protected void completeTransactionAfterThrowing(@Nullable TransactionInfo txInfo, Throwable ex) {
if (txInfo != null && txInfo.getTransactionStatus() != null) {
if (logger.isTraceEnabled()) {
logger.trace("Completing transaction for [" + txInfo.getJoinpointIdentification() +
"] after exception: " + ex);
}
if (txInfo.transactionAttribute != null && txInfo.transactionAttribute.rollbackOn(ex)) {
try {
//回滚事务
txInfo.getTransactionManager().rollback(txInfo.getTransactionStatus());
}
catch (TransactionSystemException ex2) {
logger.error("Application exception overridden by rollback exception", ex);
ex2.initApplicationException(ex);
throw ex2;
}
catch (RuntimeException | Error ex2) {
logger.error("Application exception overridden by rollback exception", ex);
throw ex2;
}
}
else {
// We don't roll back on this exception.
// Will still roll back if TransactionStatus.isRollbackOnly() is true.
try {
//提交事务
txInfo.getTransactionManager().commit(txInfo.getTransactionStatus());
}
catch (TransactionSystemException ex2) {
logger.error("Application exception overridden by commit exception", ex);
ex2.initApplicationException(ex);
throw ex2;
}
catch (RuntimeException | Error ex2) {
logger.error("Application exception overridden by commit exception", ex);
throw ex2;
}
}
}
}