一、Spring 声明式事务的入口点
对于XML入口点
XML配置定义
xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/tx
https://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/aop
https://www.springframework.org/schema/aop/spring-aop.xsd">
<tx:annotation-driven></tx:annotation-driven>
<!-- dao bean-->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate" >
<property name="dataSource" ref = "dataSource"></property>
</bean>
<!-- service bean-->
<bean id="bookService" class="org.yang.learn.spring.tx.BookService" >
<property name="jdbcTemplate" ref="jdbcTemplate"></property>
</bean>
<!-- 数据源 bean-->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" >
<property name="driverClassName" value="com.mysql.cj.jdbc.Driver"></property>
<property name="url"
value="jdbc:mysql://192.168.40.171:3306/workflow_test?serverTimezone=Asia/Shanghai&characterEncoding=utf8&useSSL=false"/>
<property name="username" value="user_dev"></property>
<property name="password" value="dev-sny.com"></property>
</bean>
<!-- 事务管理bean-->
<bean id="transactionManager" class="org.springframework.jdbc.support.JdbcTransactionManager" >
<constructor-arg ref="dataSource"></constructor-arg>
</bean>
<aop:config>
<!--切点配置 -->
<aop:pointcut id="serviceOperation"
expression="execution(* org.yang.learn.spring.tx.BookService.*(..))"/>
<!-- 通知/增强 配置 (关键是这个通知指向 txAdvice '事务增强')-->
<aop:advisor pointcut-ref="serviceOperation" advice-ref="txAdvice"/>
</aop:config>
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="get*" read-only="true"/>
<tx:method name="insertWithTransaction" propagation="REQUIRED" />
<tx:method name="insertWithNoTransaction" propagation="NEVER" />
</tx:attributes>
</tx:advice>
</beans>
在XML中配置 tx:.. 启用tx标签, 在解析XML自定义标签时, 会拿到 TxNamespaceHandler 命名空间处理器, 其主要工作就是注册事务相关的标签的解析器
- tx:advice 标签解析器:负责XML相关的标签解析
TxAdviceBeanDefinitionParser - tx:annotation-driven 标签解析器:负责注解相关的解析
AnnotationDrivenBeanDefinitionPar
org.springframework.transaction.config.TxNamespaceHandler
java
public class TxNamespaceHandler extends NamespaceHandlerSupport {
static final String TRANSACTION_MANAGER_ATTRIBUTE = "transaction-manager";
static final String DEFAULT_TRANSACTION_MANAGER_BEAN_NAME = "transactionManager";
static String getTransactionManagerName(Element element) {
return (element.hasAttribute(TRANSACTION_MANAGER_ATTRIBUTE) ?
element.getAttribute(TRANSACTION_MANAGER_ATTRIBUTE) : DEFAULT_TRANSACTION_MANAGER_BEAN_NAME);
}
@Override
public void init() {
// <tx:advice> 标签解析器:负责解析XML <tx:advice> 事务标签配置 TxAdviceBeanDefinitionParser
registerBeanDefinitionParser("advice", new TxAdviceBeanDefinitionParser());
// <tx:annotation-driven> 标签解析器:负责解析注解相关的事务配置 AnnotationDrivenBeanDefinitionParser
registerBeanDefinitionParser("annotation-driven", new AnnotationDrivenBeanDefinitionParser());
// JTA 规范的分布式事务管理器(管理跨多个资源的事务) TODO
registerBeanDefinitionParser("jta-transaction-manager", new JtaTransactionManagerBeanDefinitionParser());
}
}
启用事务注解支持
java
class AnnotationDrivenBeanDefinitionParser implements BeanDefinitionParser {
/**
* Parses the {@code <tx:annotation-driven/>} tag. Will
* {@link AopNamespaceUtils#registerAutoProxyCreatorIfNecessary register an AutoProxyCreator}
* with the container as necessary.
*/
@Override
@Nullable
public BeanDefinition parse(Element element, ParserContext parserContext) {
registerTransactionalEventListenerFactory(parserContext);
String mode = element.getAttribute("mode");
if ("aspectj".equals(mode)) {
// mode="aspectj"
registerTransactionAspect(element, parserContext);
if (ClassUtils.isPresent("jakarta.transaction.Transactional", getClass().getClassLoader())) {
registerJtaTransactionAspect(element, parserContext);
}
}
else {
// 默认是 proxy 模式
// mode="proxy"
AopAutoProxyConfigurer.configureAutoProxyCreator(element, parserContext);
}
return null;
}
注册三剑客
java
/**
* Inner class to just introduce an AOP framework dependency when actually in proxy mode.
*/
private static class AopAutoProxyConfigurer {
public static void configureAutoProxyCreator(Element element, ParserContext parserContext) {
AopNamespaceUtils.registerAutoProxyCreatorIfNecessary(parserContext, element);
String txAdvisorBeanName = TransactionManagementConfigUtils.TRANSACTION_ADVISOR_BEAN_NAME;
if (!parserContext.getRegistry().containsBeanDefinition(txAdvisorBeanName)) {
Object eleSource = parserContext.extractSource(element);
// Create the TransactionAttributeSource definition.
RootBeanDefinition sourceDef = new RootBeanDefinition(
"org.springframework.transaction.annotation.AnnotationTransactionAttributeSource");
sourceDef.setSource(eleSource);
sourceDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
String sourceName = parserContext.getReaderContext().registerWithGeneratedName(sourceDef);
// Create the TransactionInterceptor definition.
RootBeanDefinition interceptorDef = new RootBeanDefinition(TransactionInterceptor.class);
interceptorDef.setSource(eleSource);
interceptorDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
registerTransactionManager(element, interceptorDef);
interceptorDef.getPropertyValues().add("transactionAttributeSource", new RuntimeBeanReference(sourceName));
String interceptorName = parserContext.getReaderContext().registerWithGeneratedName(interceptorDef);
/**
* 其中构建事务增强器(BeanFactoryTransactionAttributeSourceAdvisor)
* - **Pointcut(切点)**: 默认匹配所有标注 `@Transactional` 的类 / 方法(由 `TransactionAttributeSourcePointcut` 实现)
* - **Advice(通知)**: 即 `TransactionInterceptor`(事务拦截器)
* - **TransactionAttributeSource(注解解析器)**:即 `AnnotationTransactionAttributeSource`, 负责解析 `@Transactional` 注解的属性(传播行为、隔离级别等)。
*/
// Create the TransactionAttributeSourceAdvisor definition.
RootBeanDefinition advisorDef = new RootBeanDefinition(BeanFactoryTransactionAttributeSourceAdvisor.class);
advisorDef.setSource(eleSource);
advisorDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
advisorDef.getPropertyValues().add("transactionAttributeSource", new RuntimeBeanReference(sourceName));
advisorDef.getPropertyValues().add("adviceBeanName", interceptorName);
if (element.hasAttribute("order")) {
advisorDef.getPropertyValues().add("order", element.getAttribute("order"));
}
parserContext.getRegistry().registerBeanDefinition(txAdvisorBeanName, advisorDef);
CompositeComponentDefinition compositeDef = new CompositeComponentDefinition(element.getTagName(), eleSource);
compositeDef.addNestedComponent(new BeanComponentDefinition(sourceDef, sourceName));
compositeDef.addNestedComponent(new BeanComponentDefinition(interceptorDef, interceptorName));
compositeDef.addNestedComponent(new BeanComponentDefinition(advisorDef, txAdvisorBeanName));
parserContext.registerComponent(compositeDef);
}
}
}
事务注解支持的三剑客
- AnnotationTransactionAttributeSource
↓(解析注解) - TransactionInterceptor
↓(执行事务逻辑) - BeanFactoryTransactionAttributeSourceAdvisor
↓(组装切点+通知)
总结一下XML入口, 就是无论 xml 支持 还是注解支持都会构造 org.springframework.transaction.interceptor.TransactionInterceptor 这个核心 advice 事务拦截器
对于注解的入口
java
@EnableTransactionManagement
public class TXMain {
@Transactional
public static void main(String[] args) throws Exception {
System.out.println("==========================================================");
//ApplicationContext context = new ClassPathXmlApplicationContext("application-tx.xml");
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(TXMain.class);
BookService bookService = context.getBean("bookService", BookService.class);
Book book = new Book();
book.setName("30秒精通javascript,一分钟精通java");
book.setCode(""+System.currentTimeMillis());
// bookService.insertWithTransaction(book );
bookService.insertWithNoTransaction(book);
System.out.println("bookService = "+bookService);
System.out.println("bookService getList = "+bookService.getList());
System.out.println("==========================================================");
}
}
@EnableTransactionManagement 注解导入了 TransactionManagementConfigurationSelector 默认选中的是 ProxyTransactionManagementConfiguration
java
public class TransactionManagementConfigurationSelector extends AdviceModeImportSelector<EnableTransactionManagement> {
/**
* Returns {@link ProxyTransactionManagementConfiguration} or
* {@code AspectJ(Jta)TransactionManagementConfiguration} for {@code PROXY}
* and {@code ASPECTJ} values of {@link EnableTransactionManagement#mode()},
* respectively.
*/
@Override
protected String[] selectImports(AdviceMode adviceMode) {
return switch (adviceMode) {
case PROXY -> new String[] {AutoProxyRegistrar.class.getName(),
ProxyTransactionManagementConfiguration.class.getName()};
case ASPECTJ -> new String[] {determineTransactionAspectClass()};
};
}
private String determineTransactionAspectClass() {
return (ClassUtils.isPresent("jakarta.transaction.Transactional", getClass().getClassLoader()) ?
TransactionManagementConfigUtils.JTA_TRANSACTION_ASPECT_CONFIGURATION_CLASS_NAME :
TransactionManagementConfigUtils.TRANSACTION_ASPECT_CONFIGURATION_CLASS_NAME);
}
}
同样注解的三剑客
- AnnotationTransactionAttributeSource
↓(解析注解) - TransactionInterceptor
↓(执行事务逻辑) - BeanFactoryTransactionAttributeSourceAdvisor
↓(组装切点+通知)
org.springframework.transaction.annotation.ProxyTransactionManagementConfiguration
java
/*
* Copyright 2002-2021 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.transaction.annotation;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.ImportRuntimeHints;
import org.springframework.context.annotation.Role;
import org.springframework.transaction.config.TransactionManagementConfigUtils;
import org.springframework.transaction.interceptor.BeanFactoryTransactionAttributeSourceAdvisor;
import org.springframework.transaction.interceptor.TransactionAttributeSource;
import org.springframework.transaction.interceptor.TransactionInterceptor;
/**
* {@code @Configuration} class that registers the Spring infrastructure beans
* necessary to enable proxy-based annotation-driven transaction management.
*
* @author Chris Beams
* @author Sebastien Deleuze
* @since 3.1
* @see EnableTransactionManagement
* @see TransactionManagementConfigurationSelector
*/
@Configuration(proxyBeanMethods = false)
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
@ImportRuntimeHints(TransactionRuntimeHints.class)
public class ProxyTransactionManagementConfiguration extends AbstractTransactionManagementConfiguration {
@Bean(name = TransactionManagementConfigUtils.TRANSACTION_ADVISOR_BEAN_NAME)
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public BeanFactoryTransactionAttributeSourceAdvisor transactionAdvisor(
TransactionAttributeSource transactionAttributeSource, TransactionInterceptor transactionInterceptor) {
BeanFactoryTransactionAttributeSourceAdvisor advisor = new BeanFactoryTransactionAttributeSourceAdvisor();
advisor.setTransactionAttributeSource(transactionAttributeSource);
advisor.setAdvice(transactionInterceptor);
if (this.enableTx != null) {
advisor.setOrder(this.enableTx.<Integer>getNumber("order"));
}
return advisor;
}
@Bean
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public TransactionAttributeSource transactionAttributeSource() {
// Accept protected @Transactional methods on CGLIB proxies, as of 6.0.
return new AnnotationTransactionAttributeSource(false);
}
@Bean
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public TransactionInterceptor transactionInterceptor(TransactionAttributeSource transactionAttributeSource) {
TransactionInterceptor interceptor = new TransactionInterceptor();
interceptor.setTransactionAttributeSource(transactionAttributeSource);
if (this.txManager != null) {
interceptor.setTransactionManager(this.txManager);
}
return interceptor;
}
}