Spring事务是基于Aop,具体而言是通过一个TransactionInterceptor的拦截器来实现。下面整理一下Spring实现事务操作的具体流程,以便于以后复习。
一.注解EnableTransactionManagement
使用EnableTransactionManagement注解可以开启Spring事务,而EnableTransactionManagement源代码如下:
@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Import(TransactionManagementConfigurationSelector.class) public @interface EnableTransactionManagement { boolean proxyTargetClass() default false; /** * 默认是使用代理的通知模式 */ AdviceMode mode() default AdviceMode.PROXY; int order() default Ordered.LOWEST_PRECEDENCE; }
阅读上述类的源代码,我们需要注意两点:
- 我们需要去了解TransactionManagementConfigurationSelector.class的功能
- Spring事务默认是使用Proxy代理模式
二. TransactionManagementConfigurationSelector
该类实现了ImportSelector接口,通过覆写selectImports()方法,手动将java类注册到Spring框架的IOC容器中
@Override protected String[] selectImports(AdviceMode adviceMode) { switch (adviceMode) { case PROXY: // 默认就是Proxy模式 return new String[] {AutoProxyRegistrar.class.getName(),ProxyTransactionManagementConfiguration.class.getName()}; case ASPECTJ: return new String[] {determineTransactionAspectClass()}; default: return null; } }
通过上述源代码可知,Spring默认将AutoProxyRegistrar.class和ProxyTransactionManagementConfiguration.class注入到IOC容器。
接下来,应该是看看这两个类到底干了什么事?
三. AutoProxyRegistrar
跟踪源代码可知,Spring会将InfrastructureAdvisorAutoProxyCreator.class注入到IOC容器,然后请看该类类图:
由图知InfrastructureAdvisorAutoProxyCreator.class是一个BeanPostProcessor.class的子类,理论上它可以在Spring初始化bean之前或之后进行功能增强,Sping框架原生选择是之后增强,具体的增强方法是在AbstractAutoProxyCreator#postProcessAfterInitialization()方法。
接下来请看看postProcessAfterInitialization()方法源码:
@Override public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) { if (bean != null) { Object cacheKey = getCacheKey(bean.getClass(), beanName); if (this.earlyProxyReferences.remove(cacheKey) != bean) { return wrapIfNecessary(bean, beanName, cacheKey); } } return bean; }
/** Wrap the given bean if necessary * 对bean进行包装,其实就是创建代理对象 */ protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) { // 省略。。。。 // Create proxy if we have advice. Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null); if (specificInterceptors != DO_NOT_PROXY) { this.advisedBeans.put(cacheKey, Boolean.TRUE); // 创建代理,jdk动态代理或者cglib代理 Object proxy = createProxy( bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean)); this.proxyTypes.put(cacheKey, proxy.getClass()); return proxy; } }
上述代码的作用就是,Spring在bean初始化之后,会判断该bean是否需要创建一个代理对象,如果需要,就会使用jdk动态代理或者cglib创建一个代理类(这一块不是本篇文章分析的重点)。
到此,AutoProxyRegistrar.class类的功能就分析完毕。
四. ProxyTransactionManagementConfiguration
该类主要是在IOC容器中注入事务拦截器TransactionInterceptor.class和Spring的事务注册解析器,具体源码如下:
@Configuration public class ProxyTransactionManagementConfiguration extends AbstractTransactionManagementConfiguration { /** * 事务注册解析器 */ @Bean @Role(BeanDefinition.ROLE_INFRASTRUCTURE) public TransactionAttributeSource transactionAttributeSource() { return new AnnotationTransactionAttributeSource(); } /** * 事务拦截器 */ @Bean @Role(BeanDefinition.ROLE_INFRASTRUCTURE) public TransactionInterceptor transactionInterceptor() { TransactionInterceptor interceptor = new TransactionInterceptor(); interceptor.setTransactionAttributeSource(transactionAttributeSource()); if (this.txManager != null) { interceptor.setTransactionManager(this.txManager); } return interceptor; } }
继续跟踪源码,咱们会发现AnnotationTransactionAttributeSource.class的底层调用了SpringTransactionAnnotationParser.class,由类名就可知道这个类的作用。事实上它也确实是解析@Transactional,具体可以参看该类源码,很简单的。
查看类图可知TransactionInterceptor.class是Advice的一个实现,而且是MethodInterceptor接口的一个实现,这说明它跟Spring Aop中前置、后置通知一样,事实上它就是一个环绕通知(around advice),完全遵守底层的责任链调用模式。
五. 事务调用链
为了便于理解,先创建一个测试demo
- DAO层
@Repository public class UserDao { @Autowired private JdbcTemplate jdbcTemplate; public void addUser() { jdbcTemplate.update("INSERT t_user(userName,age) VALUES ('test',100);"); } }
- Service层
public interface UserService { public void addUser(); }
@Service public class UserServiceImpl implements UserService { @Autowired private UserDao userDao; @Override @Transactional public void addUser() { userDao.addUser(); // int i = 1 / 0; } }
- 配置类
@Configuration @ComponentScan("qinfeng.zheng.spring01.v6") @EnableTransactionManagement // 开启事务 public class SpringConfig { @Bean public DataSource dataSource() { MysqlDataSource dataSource = new MysqlDataSource(); dataSource.setUser("root"); dataSource.setPassword("xxxxxxx"); dataSource.setURL("jdbc:mysql://xxx.xxx.xx.xx:3306/tb_user?useUnicode=true&characterEncoding=UTF-8"); // dataSource.setDatabaseName("tb_user"); return dataSource; } @Bean public JdbcTemplate jdbcTemplate() { return new JdbcTemplate(dataSource()); } @Bean public PlatformTransactionManager txManager() { return new DataSourceTransactionManager(dataSource()); } }
- 启动类
public class App { public static void main(String[] args) { AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class); UserService orderService = context.getBean(UserService.class); orderService.addUser(); } }
直接在启动类上的orderService.addUser();这一行代码上戳个断点,然后debug走起来。。。
由上图知orderService其实是一个JdkDynamicAopProxy的代理对象,然后咱们F7,会进入到JdkDynamicAopProxy#invoke()方法。
@Override @Nullable public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { // .... // 获取当前方法的拦截器链 List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass); if (chain.isEmpty()) { // 如果拦截链为空 //..... } else { // 创建一个MethodInvocation对象,其实就是对proxy, target, method, args, targetClass, chain这些参数的封装 MethodInvocation invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain); // 调用拦截器链 retVal = invocation.proceed(); } //...... return retVal; } //..... }
通过debug可知,chain链中有且只有一个 元素,而且这个元素就是前面注册的TransactionInterceptor.class, 还记得这个类吗?Spring的事务全靠它呢!
继续debug....
通过debug很容易发现invocation对象的真实类型是ReflectiveMethodInvocation.class, 这个类在分析Spring Aop的调用链时超级重要。因为本篇主要讲Spring事务,所以咱们直接进入该类的proceed()方法。
@Override @Nullable public Object proceed() throws Throwable { // 调用真实业务方法,底层也是通过反射 if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) { return invokeJoinpoint(); } Object interceptorOrInterceptionAdvice = his.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex); if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) { }else { // this很重要,这里会递归调用proceed() return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this); } }
因为interceptorOrInterceptionAdvice的真实类型是TransactionInterceptor.class,所以debug进入TransactionInterceptor#invoke()。
public Object invoke(MethodInvocation invocation) throws Throwable { //真实目标类 Class<?> targetClass = (invocation.getThis() != null ? AopUtils.getTargetClass(invocation.getThis()) : null); //重点分析该方法 return invokeWithinTransaction(invocation.getMethod(), targetClass, invocation::proceed); }
@Nullable protected Object invokeWithinTransaction(Method method, @Nullable Class<?> targetClass,final InvocationCallback invocation) throws Throwable { if (txAttr == null || !(tm instanceof CallbackPreferringPlatformTransactionManager)) { // 开启事务,底层会启用jdbc开启事务, TransactionInfo txInfo = createTransactionIfNecessary(tm, txAttr, joinpointIdentification); // 目标方法返回值 Object retVal; 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) { // 如果目标方法抛出异常,这里会回滚事务 completeTransactionAfterThrowing(txInfo, ex); throw ex; } finally { // 清埋事务 cleanupTransactionInfo(txInfo); } // commit事务 commitTransactionAfterReturning(txInfo); return retVal; }else{ //..... } }
当程序运行到invocation.proceedWithInvocation();这句代码时,注释写得很明白,它会去执行链中的下一个拦截器,所以程序又会回到ReflectiveMethodInvocation#proceed()方法。 我们debug跟踪一下。
通过debug很清楚看到了程序的调用步骤。
程序本次进入ReflectiveMethodInvocation#proceed()方法后,会进入if条件,然后执行invokeJoinpoint()方法,该方法的底层就是使用反射机制调用自定义的业务方法,于本例而言就是调用addUser()方法。
调用addUser()方法, 获取方法返回值 ,然后程序又会回到invokeWithinTransaction()方法。
六. 结束
Spring的事务的大体流程就说到这里了,示例结合debug应该还是很清楚的,至于其中的许多细节,还有待研究,后面继续补充