当前位置: 首页 > news >正文

8.2-spring 事务-声明式事务(@Transactional原理)

8.2-spring 事务-声明式事务(@Transactional原理)

在 8.1-spring 事务-声明式事务(使用) 一文中我们了解到 spring 通过 @Transactional 注解实现事务的操作,开发者只需要关注具体业务,而事务操作是通过 spring aop 实现的,即给使用了 @Transactional 注解的类生成代理类,然后执行具体的事务操作。生成代理类后执行事务的方式和 jdbc 提供的编程式事务方式类似,可以通过 jdbc 提供的事务 这篇文章查看详情。

何时生成代理类

spring 通过 AOP 生成代理类,了解 AOP 知识之前需要了解 IOC 相关知识点。IOC 即将对象的创建和销毁交给容器管理,简单点讲可以分为以下步骤:

  1. 解析bean
  2. 注册bean
  3. 实例化bean

而 AOP 创建代理类是在实例化bean后对原有bean进行加强,一般通过 BeanPostProcessor 的后置方法 postProcessAfterInstantiation 实现。

① 解析bean并注册 BeanPostProcessor 和切点通知类

1) spring/springboot 通过 ConfigurationClassPostProcessor.parse 解析 .class 文件,查找包含 @Component、@Service 等类似注解的类,将这些类注册到容器,同时查找包含 @Import 注解的类,这里以事务注解 EnableTransactionManagement 举例:

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import({TransactionManagementConfigurationSelector.class})
public @interface EnableTransactionManagement {boolean proxyTargetClass() default false;AdviceMode mode() default AdviceMode.PROXY;int order() default Integer.MAX_VALUE;
}

解析 @Import 具体方法在 ConfigurationClassParser 类 doProcessConfigurationClass 方法中

// Process any @Import annotations
processImports(configClass, sourceClass, getImports(sourceClass), filter, true);

2)找到 @Import 注解的值并实例化,这里是 TransactionManagementConfigurationSelector:

public class TransactionManagementConfigurationSelector extends AdviceModeImportSelector<EnableTransactionManagement> {public TransactionManagementConfigurationSelector() {}protected String[] selectImports(AdviceMode adviceMode) {switch (adviceMode) {case PROXY:return new String[]{AutoProxyRegistrar.class.getName(), ProxyTransactionManagementConfiguration.class.getName()};case ASPECTJ:return new String[]{this.determineTransactionAspectClass()};default:return null;}}private String determineTransactionAspectClass() {return ClassUtils.isPresent("javax.transaction.Transactional", this.getClass().getClassLoader()) ? "org.springframework.transaction.aspectj.AspectJJtaTransactionManagementConfiguration" : "org.springframework.transaction.aspectj.AspectJTransactionManagementConfiguration";}
}

该代码也在 processImports 方法中,实例化后调用 selectImports 方法:
在这里插入图片描述
3)调用 selectImports 方法后获取列名称返回值,这里是 AutoProxyRegistrar 和 ProxyTransactionManagementConfiguration ,再次调用 processImports 方法,
实例化 org.springframework.context.annotation.AutoProxyRegistrar(实例化后后面会用到)

解析 ProxyTransactionManagementConfiguration (后续会将里面的bean注册到容器中)
ProxyTransactionManagementConfiguration:


package org.springframework.transaction.annotation;@Configuration(proxyBeanMethods = false
)
@Role(2)
public class ProxyTransactionManagementConfiguration extends AbstractTransactionManagementConfiguration {public ProxyTransactionManagementConfiguration() {}@Bean(name = {"org.springframework.transaction.config.internalTransactionAdvisor"})@Role(2)public BeanFactoryTransactionAttributeSourceAdvisor transactionAdvisor(TransactionAttributeSource transactionAttributeSource, TransactionInterceptor transactionInterceptor) {BeanFactoryTransactionAttributeSourceAdvisor advisor = new BeanFactoryTransactionAttributeSourceAdvisor();advisor.setTransactionAttributeSource(transactionAttributeSource);advisor.setAdvice(transactionInterceptor);if (this.enableTx != null) {advisor.setOrder((Integer)this.enableTx.getNumber("order"));}return advisor;}@Bean@Role(2)public TransactionAttributeSource transactionAttributeSource() {return new AnnotationTransactionAttributeSource();}@Bean@Role(2)public TransactionInterceptor transactionInterceptor(TransactionAttributeSource transactionAttributeSource) {TransactionInterceptor interceptor = new TransactionInterceptor();interceptor.setTransactionAttributeSource(transactionAttributeSource);if (this.txManager != null) {interceptor.setTransactionManager(this.txManager);}return interceptor;}
}

4)注册上述bean到容器
调用的是ConfigurationClassPostProcessor 类 processConfigBeanDefinitions 方法里面的 this.reader.loadBeanDefinitions(configClasses); 方法,在这个方法里会调用 AutoProxyRegistrar 的 registerBeanDefinitions 方法


这里会注册 一个 InfrastructureAdvisorAutoProxyCreator 类到容器中:

public class InfrastructureAdvisorAutoProxyCreator extends AbstractAdvisorAutoProxyCreator {@Nullableprivate ConfigurableListableBeanFactory beanFactory;public InfrastructureAdvisorAutoProxyCreator() {}protected void initBeanFactory(ConfigurableListableBeanFactory beanFactory) {super.initBeanFactory(beanFactory);this.beanFactory = beanFactory;}protected boolean isEligibleAdvisorBean(String beanName) {return this.beanFactory != null && this.beanFactory.containsBeanDefinition(beanName) && this.beanFactory.getBeanDefinition(beanName).getRole() == 2;}
}

它是一个 BeanPostProcessor 类型

② 使用 BeanPostProcessor(InfrastructureAdvisorAutoProxyCreator) 生成代理类

1) 上述 bean 注册完成后会随着 IOC 容器实例化,包括 InfrastructureAdvisorAutoProxyCreator(BeanPostProcessor,在此类 postProcessAfterInstantiation 方法生成代理类对象),BeanFactoryTransactionAttributeSourceAdvisor (@Transactional 切点和通知),TransactionInterceptor (通知的具体实现方式,即拦截后的处理操作)

2)生成代理类对象
调用 AbstractAutoProxyCreator类的 postProcessAfterInitialization 方法,

public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {if (bean != null) {Object cacheKey = this.getCacheKey(bean.getClass(), beanName);if (this.earlyProxyReferences.remove(cacheKey) != bean) {// 调用此方法return this.wrapIfNecessary(bean, beanName, cacheKey);}}return bean;
}
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {return bean;} else if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {return bean;} else if (!this.isInfrastructureClass(bean.getClass()) && !this.shouldSkip(bean.getClass(), beanName)) {// 在这里会判断当前类 UserService 符不符合 @Transactional 切点,// 由于 UserService 加了事务注解,所以 specificInterceptors 不为空,即会创建 UserService  的代理对象Object[] specificInterceptors = this.getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, (TargetSource)null);if (specificInterceptors != DO_NOT_PROXY) {this.advisedBeans.put(cacheKey, Boolean.TRUE);// 在此创建代理对象Object proxy = this.createProxy(bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));this.proxyTypes.put(cacheKey, proxy.getClass());return proxy;} else {this.advisedBeans.put(cacheKey, Boolean.FALSE);return bean;}} else {this.advisedBeans.put(cacheKey, Boolean.FALSE);return bean;}
}

在 getAdvicesAndAdvisorsForBean 方法中会调用 TransactionAttributeSourcePointcut 类的 matches 方法判断被代理类的方法有没有加@Transactional注解,即是否符合事务的切点

@Nullableprotected Object[] getAdvicesAndAdvisorsForBean(Class<?> beanClass, String beanName, @Nullable TargetSource targetSource) {List<Advisor> advisors = this.findEligibleAdvisors(beanClass, beanName);return advisors.isEmpty() ? DO_NOT_PROXY : advisors.toArray();
}

使用事务

调用加了spring事务的方法时,spring会调用切点通知的方法,这里是 TransactionInterceptor 类的 invoke 方法

package org.springframework.transaction.interceptor;
。。。。 省略 。。。。
public class TransactionInterceptor extends TransactionAspectSupport implements MethodInterceptor, Serializable {。。。。 省略 。。。。@Nullablepublic Object invoke(final MethodInvocation invocation) throws Throwable {Class<?> targetClass = invocation.getThis() != null ? AopUtils.getTargetClass(invocation.getThis()) : null;return this.invokeWithinTransaction(invocation.getMethod(), targetClass, new TransactionAspectSupport.CoroutinesInvocationCallback() {@Nullablepublic Object proceedWithInvocation() throws Throwable {return invocation.proceed();}public Object getTarget() {return invocation.getThis();}public Object[] getArguments() {return invocation.getArguments();}});}。。。。 省略 。。。。
}

执行事务的具体操作在其父类 TransactionAspectSupport invokeWithinTransaction 方法中


上述讲解只是列出了一些关键性的步骤,如果需要了解各个细节需要对 IOC 容器非常熟悉,强烈建议自行阅读源码,也可以通过SpringBoot源码解析(1.4)-自动装配原理(总结) 这篇文章了解

http://www.dtcms.com/a/392005.html

相关文章:

  • 数据分类分级:数据安全与治理的核心框架
  • STM32---看门狗
  • 标签肽V5 tag,V5 Tag Peptide
  • Hello Robot Stretch 3 技术解析(上):极简结构与全身力感知如何加速科研?
  • FPGA学习
  • 栈序列:合法与非法判定法则
  • Postgresql17数据库中的扩展插件说明
  • pwn知识点——字节流
  • 39、AI Agent系统开发:智能代理的完整构建体系
  • Qt自定义标题栏拖动延迟问题解决方式分享
  • 招聘数字化转型如何落地?
  • 每日一题(10)
  • 费马小定理的证明
  • GPS和北斗导航信号特点一览表
  • 开发避坑指南(51):达梦数据库查看索引与建立索引的方法
  • Science Robotics最新研究:腿足机器人控制的革新性进展
  • CSP时间复杂度解析:从理论到实践
  • 手搓FOC-环路激励的实现
  • DNN人脸识别和微笑检测
  • 从API调用到UI效果:直播美颜SDK特效面具功能的集成实战
  • 神经网络学习笔记13——高效卷积神经网络架构ShuffleNet
  • MySQL双写缓冲区:数据安全的终极防线
  • 第八章 惊喜09 运维支持VS产品迭代
  • sward入门到实战(2) - 如何管理知识库
  • Vue: 依赖注入(Provide Inject)
  • nethunter 中文乱码解决
  • 【软件测试】第5章 测试分类(上)
  • [硬件电路-262]:MPH6250SQ 管脚定义、概述、功能、技术指标、使用场景及原理分析
  • git status
  • synchronized的高频面试题以及答案