Spring-tx-TransactionInterceptor类

关于TransactionInterceptor类的解析,将是对spring-tx模块最重要的解析,该类是spring事务模块核心框架代码,为此我费了很大力气,仅以此篇文章,献给我做梦都想睡到的马银霜(虽然她不知道spring是个什么东西),下面开启真的探索源码,而不是网上其他人那种假装探索(贴源码并且翻译注释)

TransactionInterceptor继承了TransactionAspectSupport类,所以有一个较为重要的静态方法,该方法由ThreadLocal实现,所以在任何地方都可以获取当前线程的TransactionStatus

public static TransactionStatus currentTransactionStatus()

第一步:首先,有一个类,类的全限定名是org.springframework.aop.framework.CglibAopProxy,而该类里面有一个内部类,是CglibMethodInvocation,该内部类签名如下

private static class CglibMethodInvocation extends ReflectiveMethodInvocation

这个内部类继承了ReflectiveMethodInvocation,但是这个内部是私有的,且该类是spring-tx模块至关重要的类,为了阐述spring-tx,要用到这个类,为此,需要我们自己新建一个类,并且将内部类CglibMethodInvocation的代码,全部都复制出来,将其修饰符改成public,方便我们自己使用,代码如下


import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.UndeclaredThrowableException;
import java.util.List;

import org.springframework.aop.framework.ReflectiveMethodInvocation;
import org.springframework.aop.support.AopUtils;
import org.springframework.cglib.proxy.MethodProxy;
import org.springframework.lang.Nullable;
import org.springframework.util.ReflectionUtils;
/**
 * 这个类与CglibAopProxy.CglibMethodInvocation类内容完全一模一样
 * 只不过修饰符是public,为了方便我自己使用
 */
public class MysCglibMethodInvocation extends ReflectiveMethodInvocation {
    
    

	@Nullable
	private final MethodProxy methodProxy;

	public MysCglibMethodInvocation(Object proxy, @Nullable Object target, Method method,
			Object[] arguments, @Nullable Class<?> targetClass,
			List<Object> interceptorsAndDynamicMethodMatchers, MethodProxy methodProxy) {
    
    

		super(proxy, target, method, arguments, targetClass, interceptorsAndDynamicMethodMatchers);

		// Only use method proxy for public methods not derived from java.lang.Object
		this.methodProxy = (Modifier.isPublic(method.getModifiers()) &&
				method.getDeclaringClass() != Object.class && !AopUtils.isEqualsMethod(method) &&
				!AopUtils.isHashCodeMethod(method) && !AopUtils.isToStringMethod(method) ?
				methodProxy : null);
	}

	@Override
	@Nullable
	public Object proceed() throws Throwable {
    
    
		try {
    
    
			return super.proceed();
		}
		catch (RuntimeException ex) {
    
    
			throw ex;
		}
		catch (Exception ex) {
    
    
			if (ReflectionUtils.declaresException(getMethod(), ex.getClass())) {
    
    
				throw ex;
			}
			else {
    
    
				throw new UndeclaredThrowableException(ex);
			}
		}
	}

	/**
	 * Gives a marginal performance improvement versus using reflection to
	 * invoke the target when invoking public methods.
	 */
	@Override
	protected Object invokeJoinpoint() throws Throwable {
    
    
		if (this.methodProxy != null) {
    
    
			return this.methodProxy.invoke(this.target, this.arguments);
		}
		else {
    
    
			return super.invokeJoinpoint();
		}
	}
}

下面的代码更重要,下面的代码就是spring-tx模块声明式事务最重要的流程,了解该流程,彻底了解spring-tx,我在示例当中使用的是西卡里(Hikari)数据源,使用其他数据源也是可以的

import java.lang.reflect.Method;
import java.util.ArrayList;
import javax.sql.DataSource;
import org.aopalliance.intercept.MethodInvocation;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.annotation.AnnotationTransactionAttributeSource;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.interceptor.TransactionInterceptor;
import com.zaxxer.hikari.HikariDataSource;

public class TransactionInterceptorTestMain {
    
    

	public static DataSource dataSource;

	static {
    
    
		HikariDataSource ds = new HikariDataSource();
		// 设置数据库名称,不要忘记修改这个地方
		ds.setJdbcUrl("jdbc:mysql://localhost:3306/swttest?serverTimezone=UTC&&useSSL=false");
		ds.setUsername("root");
		ds.setPassword("123456");
		dataSource = ds;
	}
	// 能看到这个文章的对这个注解肯定熟悉,别忘了加上就行
	@Transactional(rollbackFor = Exception.class)
	public void create() {
    
    
		JdbcTemplate jdbc = new JdbcTemplate();
		jdbc.setDataSource(dataSource);
		// 执行sql语句,我在数据库中的表名叫t1,里面只有两个字段
		jdbc.update("insert into t1 values ('1','做梦都想睡了马银霜')");
		// 如果下面的注释打开,则因为@Transactional的存在,导致事务回滚
		// 如果下面的注释打开,则因为@Transactional的存在,导致事务回滚
		// 如果下面的注释打开,则因为@Transactional的存在,导致事务回滚
		// throw new RuntimeException("MYS");
	}

	public static void main(String[] args) throws Throwable {
    
    
		TransactionInterceptor ti = new TransactionInterceptor();
		ti.setTransactionManager(new DataSourceTransactionManager(dataSource));
		ti.setTransactionAttributeSource(new AnnotationTransactionAttributeSource());

		TransactionInterceptorTestMain obj = new TransactionInterceptorTestMain();
		Method createMethod = TransactionInterceptorTestMain.class.getMethod("create");
		MethodInvocation mi = new MysCglibMethodInvocation(null, obj, createMethod, null, null, new ArrayList<>(),
				null);
		ti.invoke(mi);
	}
}

上面的代码就是spring-tx模块声明式事务的核心流程(了解了这个之后,编程式事务轻而易举就能了解),从这个代码中可以清晰的看到几大步骤
1.创建TransactionInterceptor
2.设置TransactionManager
3.设置TransactionAttributeSource
4.执行要执行的方法,本文中就是TransactionInterceptorTestMain.create方法

步骤2和3在相应的链接中我已经阐述过,本文着重分析步骤4

下面是TransactionAspectSupport.invokeWithinTransaction方法的代码片段

// 创建事务
TransactionInfo txInfo = createTransactionIfNecessary(tm, txAttr, joinpointIdentification);
Object retVal = null;
try {
    
    
	//执行我们的方法,本文中的create方法用来插入数据
	retVal = invocation.proceedWithInvocation();
}
catch (Throwable ex) {
    
    
	// 如果create方法出异常则代码到这里,并执行回滚
	completeTransactionAfterThrowing(txInfo, ex);
	throw ex;
}
finally {
    
    
	// 清空当前线程变量里的事务信息
	cleanupTransactionInfo(txInfo);
}
// 提交事务
commitTransactionAfterReturning(txInfo);

一:createTransactionIfNecessary
该方法主要使用了DataSourceTransactionManager对象的相关方法开启一个事务,其本质上使用了JDBC的Connection.setAutoCommit,最终返回TransactionInfo,所以我将创建事务的细节都挪到此处讲解,以便于更好理解DataSourceTransactionManager类,理解了这个类,就知道spring是开启一个事务的了

TODO 文章尚未完成,2021年1月18日 09:22:08

猜你喜欢

转载自blog.csdn.net/u011624903/article/details/112598464