Spring IOC源码中,声明式事务入口点是如何实现的?

摘要:一、Spring 声明式事务的入口点 对于XML入口点 XML配置定义 <?xml version="1.0" encoding="UTF-
一、Spring 声明式事务的入口点 对于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&amp;characterEncoding=utf8&amp;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 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()); } } 启用事务注解支持 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; } 注册三剑客 /** * 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 事务拦截器 对于注解的入口 @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 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 /* * 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; } }