正文

XML标签的解析


<tx:annotation-driven transaction-manager="transactionManager"/>

配置过事务的应该都不陌生,上面这个配置就是Spring开启事务注解(@Transactional)支持的配置,而看过我之前文章的应该知道,这个带前缀的标签叫自定义标签,我在之前的文章也分析过自定义标签的解析过程,所以这里我直接找到对应的handler:


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);}@Overridepublic void init() {registerBeanDefinitionParser("advice", new TxAdviceBeanDefinitionParser());registerBeanDefinitionParser("annotation-driven", new AnnotationDrivenBeanDefinitionParser());registerBeanDefinitionParser("jta-transaction-manager", new JtaTransactionManagerBeanDefinitionParser());}}

可以看到对应的注解解析器就是AnnotationDrivenBeanDefinitionParser类,在该类中一定会有一个parse方法:

 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("javax.transaction.Transactional", getClass().getClassLoader())) {registerJtaTransactionAspect(element, parserContext);}}else {// mode="proxy"AopAutoProxyConfigurer.configureAutoProxyCreator(element, parserContext);}return null;}

首先拿到mode属性的值判断是使用AspectJ生成代理还是JDK生成代理,这里我们主要看proxy模式,进入configureAutoProxyCreator方法:

public static void configureAutoProxyCreator(Element element, ParserContext parserContext) {// 注册AOP的入口类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.// @Transactional注解的属性封装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.// AOP执行链RootBeanDefinition interceptorDef = new RootBeanDefinition(TransactionInterceptor.class);interceptorDef.setSource(eleSource);interceptorDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);// 拿到transaction-manager属性的值registerTransactionManager(element, interceptorDef);interceptorDef.getPropertyValues().add("transactionAttributeSource", new RuntimeBeanReference(sourceName));String interceptorName = parserContext.getReaderContext().registerWithGeneratedName(interceptorDef);// 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);}}

这里的流程比较长,但逻辑很简单。首先来看注册事务AOP入口类是哪个:

public static void registerAutoProxyCreatorIfNecessary(ParserContext parserContext, Element sourceElement) {// 将优先级更高的AOP入口类放入到IOC容器中BeanDefinition beanDefinition = AopConfigUtils.registerAutoProxyCreatorIfNecessary(parserContext.getRegistry(), parserContext.extractSource(sourceElement));// 设置代理生成的方式以及是否缓存代理类到当前线程useClassProxyingIfNecessary(parserContext.getRegistry(), sourceElement);registerComponentIfNecessary(beanDefinition, parserContext);}

主要看registerAutoProxyCreatorIfNecessary方法:

public static BeanDefinition registerAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry, @Nullable Object source) {return registerOrEscalateApcAsRequired(InfrastructureAdvisorAutoProxyCreator.class, registry, source);}private static BeanDefinition registerOrEscalateApcAsRequired(Class<?> cls, BeanDefinitionRegistry registry, @Nullable Object source) {Assert.notNull(registry, "BeanDefinitionRegistry must not be null");// 判断传进来的类和ICO中当前存在的类哪个优先级更高,将更高的放入IOC中if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) {BeanDefinition apcDefinition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME);if (!cls.getName().equals(apcDefinition.getBeanClassName())) {int currentPriority = findPriorityForClass(apcDefinition.getBeanClassName());int requiredPriority = findPriorityForClass(cls);if (currentPriority < requiredPriority) {apcDefinition.setBeanClassName(cls.getName());}}return null;}//把AOP入口类封装成beanDefinition对象,要实例化RootBeanDefinition beanDefinition = new RootBeanDefinition(cls);beanDefinition.setSource(source);beanDefinition.getPropertyValues().add("order", Ordered.HIGHEST_PRECEDENCE);beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);//注解aop入口类的beanName名称 AopConfigUtils.AUTO_PROXY_CREATOR_BEAN_NAMEregistry.registerBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME, beanDefinition);return beanDefinition;}

首先判断容器中是否已经存在AOP入口类,如果不存在则直接创建InfrastructureAdvisorAutoProxyCreator的BeanDefinition对象注册到容器中,这个类也是我之前分析的AOP入口类AbstractAutoProxyCreator的子类,再来看看其继承关系:

你会不会疑惑,这么多子类,到底会使用哪一个呢?回到刚刚的代码中,可以看到如果已经存在一个入口类了,就会通过findPriorityForClass获取两个类的优先级,最终就会使用优先级更大的那个,那么它们的优先级顺序是怎样的呢?

private static final List<Class<?>> APC_PRIORITY_LIST = new ArrayList<>(3);static {// Set up the escalation list...APC_PRIORITY_LIST.add(InfrastructureAdvisorAutoProxyCreator.class);APC_PRIORITY_LIST.add(AspectJAwareAdvisorAutoProxyCreator.class);APC_PRIORITY_LIST.add(AnnotationAwareAspectJAutoProxyCreator.class);}private static int findPriorityForClass(@Nullable String className) {// 索引即是优先级,越大优先级越高,IOC中只会存在一个事务AOP入口类for (int i = 0; i < APC_PRIORITY_LIST.size(); i++) {Class<?> clazz = APC_PRIORITY_LIST.get(i);if (clazz.getName().equals(className)) {return i;}}throw new IllegalArgumentException("Class name [" + className + "] is not a known auto-proxy creator class");}

可以看到,InfrastructureAdvisorAutoProxyCreator是优先级最低的,基本上不会起作用;AspectJAwareAdvisorAutoProxyCreator是当我们配置了aop:config标签时会注册,也就是xml配置的AOP的入口类;而AnnotationAwareAspectJAutoProxyCreator是当我们配置了aop:aspectj-autoproxy或使用@EnableAspectJAutoProxy注解时注册,因此大部分情况下都是使用的AnnotationAwareAspectJAutoProxyCreator。 注册完AOP的入口类后,回到configureAutoProxyCreator方法:


RootBeanDefinition sourceDef = new RootBeanDefinition("org.springframework.transaction.annotation.AnnotationTransactionAttributeSource");
sourceDef.setSource(eleSource);
sourceDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
String sourceName =parserContext.getReaderContext().registerWithGeneratedName(sourceDef);

AnnotationTransactionAttributeSource类的作用就是封装事务注解@Transactional的属性,这里需要记住其继承体系以及熟悉该类和其父类的属性和方法,对后面分析事物切面执行原理有帮助:

紧接着就是创建了TransactionInterceptor对象,专门的事务拦截器,并且该类是MethodInterceptor的子类,看到这个应该不陌生了,我们知道AOP调用链在执行过程中主要就是调用该类的invoke的方法,因此它是事务切面执行的入口。既然有了Interceptor,那么必不可少的还应该有Advisor,而Advisor又是由Advice和Poincut组成的,这样才能构成一个完整的切面,所以该方法后面就是创建这两个对象。以上就是xml配置AOP注解支持的原理,很简单,下面再来看看零配置又是如何实现的。

最后

毕竟工作也这么久了 ,除了途虎一轮,也七七八八面试了不少大厂,像阿里、饿了么、美团、滴滴这些面试过程就不一一写在这篇文章上了。我会整理一份详细的面试过程及大家想知道的一些问题细节

美团面试经验


字节面试经验

菜鸟面试经验

蚂蚁金服面试经验

唯品会面试经验

因篇幅有限,图文无法详细发出,感兴趣的朋友可以点击这里前往我的腾讯文档免费获取上述资料!

[外链图片转存中…(img-cZTidlhQ-1628590898366)]
蚂蚁金服面试经验
[外链图片转存中…(img-KAzcha37-1628590898367)]
唯品会面试经验
[外链图片转存中…(img-RHxDynbe-1628590898368)]

因篇幅有限,图文无法详细发出,感兴趣的朋友可以点击这里前往我的腾讯文档免费获取上述资料!

Spring事务原理(1),区区一个SpringBoot问题就被干趴下了相关推荐

  1. 不同类的方法 事务问题_深入理解 Spring 事务原理

    Spring事务的基本原理 Spring事务的本质其实就是数据库对事务的支持,没有数据库的事务支持,spring是无法提供事务功能的.对于纯JDBC操作数据库,想要用到事务,可以按照以下步骤进行: 获 ...

  2. Spring 事务原理和使用

    转载自  Spring 事务原理和使用 1.Spring@Transactional的配置 步骤一.在Spring配置文件中引入命名空间 <beans xmlns="http://ww ...

  3. Spring事务原理分析-部分一

    Spring事务原理分析-部分一 什么事务 事务:逻辑上的一组操作,组成这组操作的各个单元,要么全都成功,要么全都失败. 事务基本特性 ⑴ 原子性(Atomicity) 原子性是指事务包含的所有操作要 ...

  4. Spring事务原理分析(一)--@EnableTransactionManagement 到底做了什么?

    目录 一.概述 二.事务的ACID属性 三.事务的隔离级别 四.事务的传播行为 五.Spring声明式事务环境搭建 六.@EnableTransactionManagement分析 七.AutoPro ...

  5. Spring事务原理-1-transactionManager以及Connection的本质

    Spring事务原理 1.spring事务配置 2.Connection本质的探究 3. Spring事务的底层原理 1.spring事务配置 <bean id="transactio ...

  6. 【Mybatis+spring整合源码探秘】--- mybatis整合spring事务原理

    文章目录 1 mybatis整合spring事务原理 1 mybatis整合spring事务原理 本篇文章不再对源码进行具体的解读了,仅仅做了下面一张图: 该图整理了spring+mybatis整合后 ...

  7. Spring事务原理

    目录 一.Spring事务原理 1.图解(待补) 2.DynamicAdvisedInterceptor组件的intercept()逻辑 2.1.DynamicAdvisedInterceptor组件

  8. spring 事务原理_Spring声明式事务处理的实现原理,来自面试官的穷追拷问

    公众号[JavaQ]原创,专注分享Java基础原理分析.实战技术.微服务架构.分布式系统构建,诚邀点赞关注! 面试官:有如下代码场景,A类的a1方法没有标注@Transactional注解,a2方法标 ...

  9. Spring事务原理一探

    概括来讲,事务是一个由有限操作集合组成的逻辑单元.事务操作包含两个目的,数据一致以及操作隔离.数据一致是指事务提交时保证事务内的所有操作都成功完成,并且更改永久生效:事务回滚时,保证能够恢复到事务执行 ...

最新文章

  1. php时区问题导致php页面显示不正常
  2. 如何实时查看mysql当前连接数
  3. Factorial Trailing Zeroes
  4. 科学前进的车轮永不停歇 2018-04-28
  5. Jquery 获取 radio选中值
  6. OpenCV-通道分离cv::split
  7. linux zk服务 关闭_ORACLE数据库RAC安装部署--一键关闭Linux非必要服务
  8. JavaScript编程用法——JavaScript运行环境
  9. win10PPT不支持Flash动画
  10. 连载31:软件体系设计新方向:数学抽象、设计模式、系统架构与方案设计(简化版)(袁晓河著)...
  11. 正规矩阵的谱分解MATLAB,正规矩阵的谱分解.PDF
  12. java class命名_Java中class文件命名规则
  13. UVA-12304 Race(递推)
  14. 金融级湖仓一体架构——SequoiaDB巨杉数据库初探
  15. linux 百度云 备份软件下载,Linux 安装百度云,自动备份服务器资料
  16. WOS(六)——导出数据格式及处理
  17. 几何光学类毕业论文文献有哪些?
  18. 提升算法数据结构的几个网站
  19. 微信小程序做店铺收费吗?【微信小程序店铺】
  20. android 点赞 1,GoodView Android 点赞+1 效果,支持文本和图像 @codeKK Android开源站

热门文章

  1. centertrack
  2. Ubuntu tensorflow自定义GPU版本op节点
  3. 复数的物理意义是什么
  4. ffmpeg编译 c++ 常量中有换行符
  5. c++ django上传图片
  6. jni invalid jobject
  7. 基于相关滤波器的追踪(Correlation Filter-based Tracking)原理
  8. opencv双目测距资料整理
  9. HTTPS 建立连接的过程
  10. 73 Zabbix 微信告警