Spring 声明式事务 各阶段的流程图
声明式事务底层原理是基于AOP的, 换句话说比先学习了AOP, 才能看得懂其源码流程
一、Spring 声明式事务的入口点
org.springframework.beans.factory.xml.BeanDefinitionParserDelegate#parseCustomElement(org.w3c.dom.Element, org.springframework.beans.factory.config.BeanDefinition)
/**
* 拿到元素的命名空间URI, 再从 XmlReaderContext 找到对应的 NamespaceHandler 调用解析 `parse`方法解析到 BeanDefinition 返回
*
* Parse a custom element (outside the default namespace).
* @param ele the element to parse
* @param containingBd the containing bean definition (if any)
* @return the resulting bean definition
*/
@Nullable
public BeanDefinition parseCustomElement(Element ele, @Nullable BeanDefinition containingBd) {
//拿到 命名空间URI
String namespaceUri = getNamespaceURI(ele);
if (namespaceUri == null) {
return null;
}
/**
* 拿到对应命名空间的 Handler , this.readerContext 是在
* @see org.springframework.beans.factory.xml.XmlBeanDefinitionReader#registerBeanDefinitions(org.w3c.dom.Document, org.springframework.core.io.Resource) 创建的
* 它会从父属性的 namespaceHandlerResolver 中拿到命名空间处理器, 调用NamespaceHandler#parse 进行解析
* 它默认读取的配置是 `META-INF/spring.handlers` 文件
*
* 对于注解的支持:
* 配置<context:annotation-config />的标签以表示启用注解, 这里会拿到 org.springframework.context.annotation.AnnotationConfigBeanDefinitionParser 进行处理
* 往 beanfactory 注册了四个 BeanDefinition, 重点是以下这两个
* org.springframework.context.annotation.internalConfigurationAnnotationProcessor
* org.springframework.context.annotation.internalAutowiredAnnotationProcessor
* 实现了 BeanDefinitionRegistryPostProcessor 在这里进行扩展
*
* 对于AOP的支持:
* 在XML中配置 <aop:..> 启用Aop标签, 在解析XML自定义标签时, 这里会拿到 AopNamespaceHandler 命名空间处理器, 其内部的 ConfigBeanDefinitionParser 做了两件事
* 1. 注册了一个对AOP处理的 BeanDefinition 名称是
* org.springframework.aop.config.internalAutoProxyCreator 对应的类有根据情况有三个可能
* InfrastructureAdvisorAutoProxyCreator.class,
* AspectJAwareAdvisorAutoProxyCreator.class, AnnotationAwareAspectJAutoProxyCreator.class
* 它们都是实现 InstantiationAwareBeanPostProcessor接口的
* 2. 解析 <aop:config> 标签的子元素
* org.springframework.aop.config.ConfigBeanDefinitionParser#parse
*
* 对于TX事务的支持:
* org.springframework.transaction.config.TxNamespaceHandler
* 在XML中配置 <tx:..> 启用tx标签, 在解析XML自定义标签时, 这里会拿到 TxNamespaceHandler 命名空间处理器, 其主要工作就是注册事务相关的标签的解析器
* <tx:advice> 标签解析器:解析事务通知(核心事务规则配置) TxAdviceBeanDefinitionParser
* <tx:annotation-driven> 标签解析器:开启注解驱动的事务 AnnotationDrivenBeanDefinitionParser
*/
NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);
if (handler == null) {
error("Unable to locate Spring NamespaceHandler for XML schema namespace [" + namespaceUri + "]", ele);
return null;
}
// 调用 Handler 解析, 返回的是 BeanDefinition;
return handler.parse(ele, new ParserContext(this.readerContext, this, containingBd));
}对于XML入口点
org.springframework.transaction.config.TxNamespaceHandler
package org.springframework.transaction.config;
import org.w3c.dom.Element;
import org.springframework.beans.factory.xml.NamespaceHandlerSupport;
/**
* {@code NamespaceHandler} allowing for the configuration of
* declarative transaction management using either XML or using annotations. * * <p>This namespace handler is the central piece of functionality in the * Spring transaction management facilities and offers two approaches * to declaratively manage transactions. * * <p>One approach uses transaction semantics defined in XML using the * {@code <tx:advice>} elements, the other uses annotations
* in combination with the {@code <tx:annotation-driven>} element.
* Both approached are detailed to great extent in the Spring reference manual. * * @author Rob Harrop
* @author Juergen Hoeller
* @since 2.0
*/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());
}
}启用事务注解支持
当前启用注解<tx:annotation-driven> 配置时, 其解析处理器: org.springframework.transaction.config.AnnotationDrivenBeanDefinitionParser 根据 mode 参数
- 默认
mode="proxy"(代理模式): 这是最常用的方式, 基于 Spring AOP 动态代理实现, 也是解析器的核心处理逻辑 mode="aspectj"(AspectJ 模式): 基于 AspectJ 编译期 / 类加载期织入, 需额外注册 AspectJ 事务切面(TransactionAspect), 适用于需要拦截内部方法调用的场景
/**
* 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 {
// mode="proxy"
AopAutoProxyConfigurer.configureAutoProxyCreator(element, parserContext);
}
return null;
}注册几个 BeanDefinition, 其中构建事务增强器(BeanFactoryTransactionAttributeSourceAdvisor)
- Pointcut(切点): 默认匹配所有标注
@Transactional的类 / 方法(由TransactionAttributeSourcePointcut实现) - Advice(通知): 即
TransactionInterceptor(事务拦截器) - TransactionAttributeSource(注解解析器):即
AnnotationTransactionAttributeSource, 负责解析@Transactional注解的属性(传播行为、隔离级别等)
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);
}
}
}对于注解的入口
package org.yang.learn.spring.tx;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import org.springframework.transaction.annotation.Transactional;
import org.yang.learn.spring.dto.Book;
import org.yang.learn.spring.dto.User;
/**
* ${Description}
* @author yangfh
* @date 2023-12-14 21:20
**/
@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("org.yang.learn.spring.tx");
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("==========================================================");
}
}二、事务相关的 BeanDefinition 解析过程 (XML)
org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser#parseInternal
public abstract class AbstractSingleBeanDefinitionParser extends AbstractBeanDefinitionParser {
/**
* Creates a {@link BeanDefinitionBuilder} instance for the
* {@link #getBeanClass bean Class} and passes it to the
* {@link #doParse} strategy method.
* @param element the element that is to be parsed into a single BeanDefinition
* @param parserContext the object encapsulating the current state of the parsing process
* @return the BeanDefinition resulting from the parsing of the supplied {@link Element}
* @throws IllegalStateException if the bean {@link Class} returned from
* {@link #getBeanClass(org.w3c.dom.Element)} is {@code null}
* @see #doParse
*
*/
@Override
protected final AbstractBeanDefinition parseInternal(Element element, ParserContext parserContext) {
/**
*
*
* 1. 解析 <tx:advice ... 标签 封装为`GenericBeanDefinition`
* 其名称和class为org.springframework.transaction.interceptor.TransactionInterceptor
* 注意这个 TransactionInterceptor 实现了MethodInterceptor相当于是个Advice
*
* org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser
* #parseInternal(org.w3c.dom.Element, org.springframework.beans.factory.xml.ParserContext)
*
* org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser#parseInternal
*
* 2. 解析 <tx:attributes> 属性标签, 并将这些属性附加到上面的 GenericBeanDefinition中
* org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser
* #doParse(org.w3c.dom.Element, org.springframework.beans.factory.xml.ParserContext, org.springframework.beans.factory.support.BeanDefinitionBuilder)
*
*/
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition();
String parentName = getParentName(element);
if (parentName != null) {
builder.getRawBeanDefinition().setParentName(parentName);
}
Class<?> beanClass = getBeanClass(element);
if (beanClass != null) {
builder.getRawBeanDefinition().setBeanClass(beanClass);
}
else {
String beanClassName = getBeanClassName(element);
if (beanClassName != null) {
builder.getRawBeanDefinition().setBeanClassName(beanClassName);
}
}
builder.getRawBeanDefinition().setSource(parserContext.extractSource(element));
BeanDefinition containingBd = parserContext.getContainingBeanDefinition();
if (containingBd != null) {
// Inner bean definition must receive same scope as containing bean.
builder.setScope(containingBd.getScope());
}
if (parserContext.isDefaultLazyInit()) {
// Default-lazy-init applies to custom bean definitions as well.
builder.setLazyInit(true);
}
doParse(element, parserContext, builder);
return builder.getBeanDefinition();
}