关于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