SpringBoot 源碼解析 (八)----- Spring Boot 精髓:事務源碼解析


本篇來講一下SpringBoot是怎么自動開啟事務的,我們先來回顧一下以前SSM中是如何使用事務的

SSM使用事務

導入JDBC依賴包

眾所周知,凡是需要跟數據庫打交道的,基本上都要添加jdbc的依賴,在Spring項目中,加入的是spring-jdbc依賴:

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-jdbc</artifactId>
</dependency>

配置版事務

在使用配置文件的方式中,通常會在Spring的配置文件中配置事務管理器,並注入數據源:

<!-- 注冊數據源 -->
<bean id="dataSource" class="...">
    <property name="" value=""/>
</bean>

<!-- 注冊事務管理器 -->
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="dataSource" />
</bean>

<!-- 開啟事務注解 -->
<tx:annotation-driven transaction-manager="txManager" />

接下來可以直接在業務層Service的方法上或者類上添加@Transactional

注解版事務

首先需要注冊兩個Bean,分別對應上面Spring配置文件中的兩個Bean:

@EnableTransactionManagement//重要
@Configuration
public class TxConfig {

    @Bean
    public DataSource dataSource() {
        ComboPooledDataSource dataSource = new ComboPooledDataSource();
        dataSource.setUser("...");
        dataSource.setPassword("...");
        dataSource.setDriverClass("...");
        dataSource.setJdbcUrl("...");
        return dataSource;
    }
  
    //重要
 @Bean public PlatformTransactionManager platformTransactionManager() { return new DataSourceTransactionManager(dataSource());//放入數據源
 }
}

我們看到往Spring容器中注入了DataSource 和PlatformTransactionManager 對象,並且通過@EnableTransactionManagement注解開啟了事務,和上面的XML配置是一一對應的。PlatformTransactionManager這個Bean非常重要,要使用事務管理,就必須要在IOC容器中注冊一個事務管理器。

public interface PlatformTransactionManager {
    //獲取一個Transaction
    TransactionStatus getTransaction(TransactionDefinition var1) throws TransactionException;
    //提交事務
    void commit(TransactionStatus var1) throws TransactionException;
    //回滾事務
    void rollback(TransactionStatus var1) throws TransactionException;
}

我們看到事務管理器的作用就是獲取事務,提交回滾事務。DataSourceTransactionManager是PlatformTransactionManager的一個實現類,大家可以看看我以前的文章spring5 源碼深度解析----- Spring事務 是怎么通過AOP實現的?(100%理解Spring事務) 看一下Spring的聲明式事務的源碼。下面我們來看看SpringBoot是如何自動配置事務的

SpringBoot自動配置事務

引入JDBC

眾所周知,在SpringBoot中凡是需要跟數據庫打交道的,基本上都要顯式或者隱式添加jdbc的依賴:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>

也就是jdbc的場景啟動器,我們點進去看看

其實也是引入了spring-jdbc的依賴,接下來我們要看兩個重要的事務自動配置類

DataSourceTransactionManagerAutoConfiguration

我們看到在spring.factories中配置了事務管理器自動配置類DataSourceTransactionManagerAutoConfiguration,我們進去看看

 1 @Configuration
 2 //在類路徑下有這個類存在PlatformTransactionManager時,這個配置類才會生效  3 //而前面我們已經引入了spring-boot-starter-jdbc,那自然是存在了
 4 @ConditionalOnClass({ JdbcTemplate.class, PlatformTransactionManager.class })  5 @AutoConfigureOrder(Ordered.LOWEST_PRECEDENCE)
 6 @EnableConfigurationProperties(DataSourceProperties.class)
 7 public class DataSourceTransactionManagerAutoConfiguration {
 8 
 9     @Configuration
10     @ConditionalOnSingleCandidate(DataSource.class)
11     static class DataSourceTransactionManagerConfiguration {
12 
13         private final DataSource dataSource;
14 
15         private final TransactionManagerCustomizers transactionManagerCustomizers;
16 
17         DataSourceTransactionManagerConfiguration(DataSource dataSource,
18                 ObjectProvider<TransactionManagerCustomizers> transactionManagerCustomizers) {
19             this.dataSource = dataSource;
20             this.transactionManagerCustomizers = transactionManagerCustomizers
21                     .getIfAvailable();
22         }
23 
24         @Bean
25         //沒有當Spring容器中不存在PlatformTransactionManager這個對象時,創建DataSourceTransactionManager 26         //也就是如果我們自定義了DataSourceTransactionManager並注入Spring容器,這里將不會執行
27         @ConditionalOnMissingBean(PlatformTransactionManager.class) 28         public DataSourceTransactionManager transactionManager(DataSourceProperties properties) { 29             //創建DataSourceTransactionManager注入Spring容器,並且把dataSource傳進去
30             DataSourceTransactionManager transactionManager = new DataSourceTransactionManager(this.dataSource); 31             if (this.transactionManagerCustomizers != null) {
32                 this.transactionManagerCustomizers.customize(transactionManager);
33             }
34             return transactionManager; 35         }
36 
37     }
38 
39 }

很明顯只要我們導入了spring-boot-starter-jdbc場景啟動器,並且我們沒有自定義DataSourceTransactionManager,那么事務管理器自動配置類DataSourceTransactionManagerAutoConfiguration會自動為我們創建DataSourceTransactionManager並注入Spring容器中。但是這還不夠,我們前面還是需要通過@EnableTransactionManagement開啟事務呢,如果不開啟事務,@Transactional是不起任何作用的。下面我們就來看看是如何開啟事務的

TransactionAutoConfiguration

我們看到在spring.factories中配置了事務自動開啟配置類TransactionAutoConfiguration,我們進去看看

 1 @Configuration
 2 //和DataSourceTransactionManagerAutoConfiguration中是一樣的
 3 //引入了spring-boot-starter-jdbc,那自然是存在了PlatformTransactionManager
 4 @ConditionalOnClass({PlatformTransactionManager.class})
 5 //這個自動配置類必須要在DataSourceTransactionManagerAutoConfiguration這個自動配置類之后才能生效  6 //也就是前面我們已經往Spring容器中注入了DataSourceTransactionManager這個對象才執行這個配置類
 7 @AutoConfigureAfter({JtaAutoConfiguration.class, HibernateJpaAutoConfiguration.class, DataSourceTransactionManagerAutoConfiguration.class, Neo4jDataAutoConfiguration.class})  8 @EnableConfigurationProperties({TransactionProperties.class})
 9 public class TransactionAutoConfiguration {
10     public TransactionAutoConfiguration() {
11     }
12 
13     @Configuration
14     @ConditionalOnBean({PlatformTransactionManager.class})
15     @ConditionalOnMissingBean({AbstractTransactionManagementConfiguration.class})
16     public static class EnableTransactionManagementConfiguration {
17         public EnableTransactionManagementConfiguration() {
18         }
19 
20  @Configuration 21         //重點:通過 @EnableTransactionManagement注解開啟事務 22         //可以看到和我們自己使用@EnableTransactionManagement是一樣的
23  @EnableTransactionManagement( 24             proxyTargetClass = true
25         )
26         @ConditionalOnProperty(
27             prefix = "spring.aop",
28             name = {"proxy-target-class"},
29             havingValue = "true",
30             matchIfMissing = true
31         )
32         public static class CglibAutoProxyConfiguration {
33             public CglibAutoProxyConfiguration() {
34             }
35         }
36 
37         @Configuration
38         @EnableTransactionManagement(
39             proxyTargetClass = false
40         )
41         @ConditionalOnProperty(
42             prefix = "spring.aop",
43             name = {"proxy-target-class"},
44             havingValue = "false",
45             matchIfMissing = false
46         )
47         public static class JdkDynamicAutoProxyConfiguration {
48             public JdkDynamicAutoProxyConfiguration() {
49             }
50         }
51     }
52 
53     @Configuration
54     @ConditionalOnSingleCandidate(PlatformTransactionManager.class)
55     public static class TransactionTemplateConfiguration {
56         private final PlatformTransactionManager transactionManager;
57 
58         public TransactionTemplateConfiguration(PlatformTransactionManager transactionManager) {
59             this.transactionManager = transactionManager;
60         }
61 
62         @Bean
63         @ConditionalOnMissingBean
64         public TransactionTemplate transactionTemplate() {
65             return new TransactionTemplate(this.transactionManager);
66         }
67     }
68 }

我們看到TransactionAutoConfiguration這個自動配置類必須要在DataSourceTransactionManagerAutoConfiguration這個配置類之后才能生效,也就是前面我們已經往Spring容器中注入了DataSourceTransactionManager這個對象才執行這個配置類,然后通過

@EnableTransactionManagement這個注解開啟事務,其實和我們自己使用@EnableTransactionManagement是一樣的

因此,只要我們在SpringBoot中引入了spring-boot-starter-jdbc這個場景啟動器,就會幫我們自動開啟事務了,我們只需要使用@Transactional就可以了

mybatis-spring-boot-starter

大多數時候我們在SpringBoot中會引入Mybatis這個orm框架,Mybaits的場景啟動器如下

<dependency>
  <groupId>org.mybatis.spring.boot</groupId>
  <artifactId>mybatis-spring-boot-starter</artifactId>
  <version>1.3.0</version>
</dependency>

我們點進去看看

我們看到mybatis-spring-boot-starter這個場景啟動器是引入了spring-boot-starter-jdbc這個場景啟動器的,因此只要我們在SpringBoot中使用Mybaits,是自動幫我們開啟了Spring事務的

總結

springboot 開啟事物很簡單,只需要加一行注解@Transactional就可以了,前提你用的是jdbctemplate, jpa, Mybatis,這種常見的orm。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM