【spring事务源码学习】--- spring事务核心组件创建过程

源码地址:https://github.com/nieandsun/spring-study


1 通过注解方式配置数据源+事务管理器+持久层框架

比较简单,直接上代码了:

package com.nrsc.springstudy.c11_Transaction01.config;

import com.alibaba.druid.pool.DruidDataSource;
import com.mchange.v2.c3p0.ComboPooledDataSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;

import javax.sql.DataSource;
import java.beans.PropertyVetoException;

/***
 * @author : Sun Chuan
 * @date : 2019/11/24 19:44
 * Description:
 */

@Configuration
@ComponentScan(value = "com.nrsc.springstudy.c11_Transaction")
@EnableTransactionManagement //开启事务注解功能
public class C11Config01 {

    //创建数据源
    @Bean
    public DataSource dataSource() {
        DruidDataSource dataSource = new DruidDataSource();
        dataSource.setUsername("root");
        dataSource.setPassword("123456");
        dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");
        dataSource.setUrl("jdbc:mysql://127.0.0.1:3306/nrsc-transaction?characterEncoding=utf-8&serverTimezone=GMT&useSSL=false");
        return dataSource;
    }
    
    //注册事务管理器
    @Bean
    public PlatformTransactionManager platformTransactionManager() throws PropertyVetoException {
        return new DataSourceTransactionManager(dataSource());
    }

    //使用jdbcTemplate持久层框架~~~之后整理Mybatis的时候这里会换成Mybatis
    @Bean
    public JdbcTemplate jdbcTemplate() {
        return new JdbcTemplate(dataSource());
    }
}

2 spring事务核心组件的注册

2.1 @EnableTransactionManagement注解

【Spring - AOP】— AOP核心后置处理器的创建过程》那篇文章讲到AOP核心后置处理器是通过注解@EnableAspectJAutoProxy注册到Spring容器的。与AOP类似,spring事务的核心组件也是通过一个注解注入到Spring容器的,这个注解就是1中的@EnableTransactionManagement。其源码如下:

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
//向容器中导入TransactionManagementConfigurationSelector类
@Import(TransactionManagementConfigurationSelector.class) 
public @interface EnableTransactionManagement {

	/***true强制使用CGLIB代理,false非强制*/
	boolean proxyTargetClass() default false;

	/***使用的代理模式:PROXY--JDK代理模式(默认);ASPECTJ -- ASPECTJ代理模式*/
	AdviceMode mode() default AdviceMode.PROXY;

	/**
	 * Indicate the ordering of the execution of the transaction advisor
	 * when multiple advices are applied at a specific joinpoint.
	 * <p>The default is {@link Ordered#LOWEST_PRECEDENCE}.
	 */
	int order() default Ordered.LOWEST_PRECEDENCE;
}

2.2 TransactionManagementConfigurationSelector类

通过2.1的源码我们又看到了Import注解 — @Import(TransactionManagementConfigurationSelector.class) ,它的作用我在前面多篇文章里介绍过,就是往IOC容器里注入TransactionManagementConfigurationSelector这个类。接下来看一下TransactionManagementConfigurationSelector的源码:
所在类:TransactionManagementConfigurationSelector

public class TransactionManagementConfigurationSelector extends AdviceModeImportSelector<EnableTransactionManagement> {
	@Override
	protected String[] selectImports(AdviceMode adviceMode) {
		switch (adviceMode) {
			case PROXY: 
			 	//向IOC容器中注入AutoProxyRegistrar和ProxyTransactionManagementConfiguration两个类
				return new String[] {AutoProxyRegistrar.class.getName(),
						ProxyTransactionManagementConfiguration.class.getName()};
			case ASPECTJ:
				return new String[] {determineTransactionAspectClass()};
			default:
				return null;
		}
	}

	private String determineTransactionAspectClass() {
		return (ClassUtils.isPresent("javax.transaction.Transactional", getClass().getClassLoader()) ?
				TransactionManagementConfigUtils.JTA_TRANSACTION_ASPECT_CONFIGURATION_CLASS_NAME :
				TransactionManagementConfigUtils.TRANSACTION_ASPECT_CONFIGURATION_CLASS_NAME);
	}
}

可以看到该类继承了AdviceModeImportSelector,而跟进AdviceModeImportSelector源码可以发现该类实现了ImportSelector接口,在《【Spring注解】@Import》那篇文章里介绍到过,Import一个实现了ImportSelector接口的类时可以通过该类的selectImports方法批量的向IOC容器里导入单例bean —> 也就是说该类会向IOC容器里导入AutoProxyRegistrarProxyTransactionManagementConfiguration两个类。


2.3 ProxyTransactionManagementConfiguration — 三大核心组件

ProxyTransactionManagementConfiguration类其实是一个配置类,其源码如下:

@Configuration
public class ProxyTransactionManagementConfiguration extends AbstractTransactionManagementConfiguration {
	//事务通知 --- 动态代理机制创建增强对象时的关键类
	@Bean(name = TransactionManagementConfigUtils.TRANSACTION_ADVISOR_BEAN_NAME)
	@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
	public BeanFactoryTransactionAttributeSourceAdvisor transactionAdvisor() {
		BeanFactoryTransactionAttributeSourceAdvisor advisor = new BeanFactoryTransactionAttributeSourceAdvisor();
		advisor.setTransactionAttributeSource(transactionAttributeSource());
		advisor.setAdvice(transactionInterceptor());
		if (this.enableTx != null) {
			advisor.setOrder(this.enableTx.<Integer>getNumber("order"));
		}
		return advisor;
	}
	//事务属性源对象 --- 用于解析@Transactional注解,获取当前事务的属性对象
	@Bean
	@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
	public TransactionAttributeSource transactionAttributeSource() {
		return new AnnotationTransactionAttributeSource();
	}
	//事务拦截器 --- 可以与AOP中通知转换后的方法拦截器对比
	@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;
	}
}

小结:

(1)BeanFactoryTransactionAttributeSourceAdvisor 和 TransactionAttributeSource两个组件用来拦截标注了 @Transactional注解的方法、类或接口并解析该注解的属性信息,然后借助动态代理机制创建代理对象,从而完成对目标类的增强 — 说白了spring声明式事务的核心原理其实和AOP一样就是利用动态代理机制对目标对象进行代理增强,从而使其具有处理事务的能力。

(2)TransactionInterceptor组件用在目标调用过程中,它的主要功能是对目标对象进行拦截增强,使其真正具有事务的能力。


2.4 AutoProxyRegistrar — 事务核心后置处理器

AutoProxyRegistrar类主要用来导入事务核心后置处理器 — InfrastructureAdvisorAutoProxyCreator
这块其实和AOP核心后置处理器AnnotationAwareAspectJAutoProxyCreator的注册和创建过程基本一致,这里不过多介绍了,有兴趣的可以 以《【Spring - AOP】— AOP核心后置处理器的创建过程》这篇文章为例,跟踪一下事务核心后置处理器的注册+创建过程。
这里简单看一下InfrastructureAdvisorAutoProxyCreator类的继承关系图:
在这里插入图片描述
再对比一下AnnotationAwareAspectJAutoProxyCreator类的继承关系图
在这里插入图片描述
可以看到两者其实有很大的相似性,比如说:

  • 两者都继承了BeanPostProcessor、InstantiationAwareBeanPostProcessor接口,说明两者都是后置处理器
  • 两者都继承了Order接口,说明两者注入IOC的时机是一致的
  • 两者都继承了BeanFactoryAware接口,说明两者都可以直接获得BeanFactory对象
  • 两者都继承了AbstractAutoProxyCreator和AbstractAdvisorAutoProxyCreator抽象类 — 从这里我发现了自己一个认识的误区,我以前一直以为AOP的前置处理方法啥事都没做,但是事务的后置处理器也实现了InstantiationAwareBeanPostProcessor接口,并继承了AbstractAutoProxyCreator抽象类,因此它会和AOP一样调用前置处理方法,这让我意识到事情应该不止是这么简单 — 下篇文章再具体说吧。

前置处理方法的入口:
所在类: AbstractAutowireCapableBeanFactory
所在方法: createBean

try {
	// Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.
	Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
	if (bean != null) {
		return bean;
	}
}

注意: 该方法虽然每次获得的bean都为null,但是该方法却并不是只遛一圈啥都不做。 — 因此《【Spring - AOP】 — 目标对象增强核心源码解读》那篇文章说前置处理方法一般不会做什么是不正确的 ::>_<::。。。


3 总结

spring利用一个@EnableTransactionManagement注解向IOC容器里导入了四个核心组件,可以概况成下图:
在这里插入图片描述

发布了189 篇原创文章 · 获赞 187 · 访问量 39万+

猜你喜欢

转载自blog.csdn.net/nrsc272420199/article/details/103648215