电脑知识|欧美黑人一区二区三区|软件|欧美黑人一级爽快片淫片高清|系统|欧美黑人狂野猛交老妇|数据库|服务器|编程开发|网络运营|知识问答|技术教程文章 - 好吧啦网

您的位置:首頁技術文章
文章詳情頁

這一次搞懂Spring事務注解的解析方式

瀏覽:45日期:2023-08-19 10:11:42

前言

事務我們都知道是什么,而Spring事務就是在數據庫之上利用AOP提供聲明式事務和編程式事務幫助我們簡化開發,解耦業務邏輯和系統邏輯。但是Spring事務原理是怎樣?事務在方法間是如何傳播的?為什么有時候事務會失效?接下來幾篇文章將重點分析Spring事務源碼,讓我們徹底搞懂Spring事務的原理。

正文

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); } @Override public 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_NAME registry.registerBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME, beanDefinition); return beanDefinition; }

首先判斷容器中是否已經存在AOP入口類,如果不存在則直接創建InfrastructureAdvisorAutoProxyCreator的BeanDefinition對象注冊到容器中,這個類也是我上一篇文章分析的AOP入口類AbstractAutoProxyCreator的子類,再來看看其繼承關系:

這一次搞懂Spring事務注解的解析方式

你會不會疑惑,這么多子類,到底會使用哪一個呢?回到剛剛的代碼中,可以看到如果已經存在一個入口類了,就會通過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的屬性,這里需要記住其繼承體系以及熟悉該類和其父類的屬性和方法,對后面分析事物切面執行原理有幫助:

這一次搞懂Spring事務注解的解析方式

緊接著就是創建了TransactionInterceptor對象,專門的事務攔截器,并且該類是MethodInterceptor的子類,看到這個應該不陌生了,我們知道AOP調用鏈在執行過程中主要就是調用該類的invoke的方法,因此它是事務切面執行的入口。既然有了Interceptor,那么必不可少的還應該有Advisor,而Advisor又是由Advice和Poincut組成的,這樣才能構成一個完整的切面,所以該方法后面就是創建這兩個對象。以上就是xml配置AOP注解支持的原理,很簡單,下面再來看看零配置又是如何實現的。

AOP零配置原理

使用過SpringBoot的都知道,如果需要開啟事務注解的支持,只需要一個注解就能搞定:@EnableTransactionManagement,不用再配置xml文件,這個又是怎么做到的呢?不多說,我們直接來看其源碼:

@Import(TransactionManagementConfigurationSelector.class)public @interface EnableTransactionManagement { boolean proxyTargetClass() default false; AdviceMode mode() default AdviceMode.PROXY; int order() default Ordered.LOWEST_PRECEDENCE;}

在該注解下使用@Import導入了一個類TransactionManagementConfigurationSelector,首先該注解的作用就是導入一個類的實例到IOC容器中,你可能會說不是在類上加@Component注解就行了么,但是有些類它并不在你掃描的路徑下,而該注解依然可以將其導入進來,所以我么主要看TransactionManagementConfigurationSelector類中做了些啥:

public class TransactionManagementConfigurationSelector extends AdviceModeImportSelector<EnableTransactionManagement> { @Override protected String[] selectImports(AdviceMode adviceMode) { switch (adviceMode) { case PROXY: return new String[] {AutoProxyRegistrar.class.getName(), ProxyTransactionManagementConfiguration.class.getName()}; case ASPECTJ: return new String[] {determineTransactionAspectClass()}; default: return null; } } private String determineTransactionAspectClass() { return (ClassUtils.isPresent('javax.transaction.Transactional', getClass().getClassLoader()) ? TransactionManagementConfigUtils.JTA_TRANSACTION_ASPECT_CONFIGURATION_CLASS_NAME : TransactionManagementConfigUtils.TRANSACTION_ASPECT_CONFIGURATION_CLASS_NAME); }}

可以看到在selectImports方法中返回了AutoProxyRegistrar和ProxyTransactionManagementConfiguration類,返回后會被封裝為BeanDefinition對象,那這個方法是在哪里調用的呢?這個在之前的文章中也分析過,ConfigurationClassPostProcessor類中會調用ConfigurationClassParser類的parse方法解析@Configuration、@Import、@ImportSource等注解,具體過程這里就不再贅述了。我們繼續來分別看看AutoProxyRegistrar和ProxyTransactionManagementConfiguration類:

public class AutoProxyRegistrar implements ImportBeanDefinitionRegistrar { private final Log logger = LogFactory.getLog(getClass()); @Override public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) { boolean candidateFound = false; Set<String> annoTypes = importingClassMetadata.getAnnotationTypes(); for (String annoType : annoTypes) { AnnotationAttributes candidate = AnnotationConfigUtils.attributesFor(importingClassMetadata, annoType); if (candidate == null) { continue; } Object mode = candidate.get('mode'); Object proxyTargetClass = candidate.get('proxyTargetClass'); if (mode != null && proxyTargetClass != null && AdviceMode.class == mode.getClass() && Boolean.class == proxyTargetClass.getClass()) { candidateFound = true; if (mode == AdviceMode.PROXY) { //注冊事務AOP的入口類InfrastructureAdvisorAutoProxyCreator,實際上這個AOP入口類起不了作用 AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry); if ((Boolean) proxyTargetClass) { AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry); return; } } } } }}public class ProxyTransactionManagementConfiguration extends AbstractTransactionManagementConfiguration { /* * 明顯是創建事務切面實例 * BeanFactoryTransactionAttributeSourceAdvisor * * */ @Bean(name = TransactionManagementConfigUtils.TRANSACTION_ADVISOR_BEAN_NAME) @Role(BeanDefinition.ROLE_INFRASTRUCTURE) public BeanFactoryTransactionAttributeSourceAdvisor transactionAdvisor() { 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() { return new AnnotationTransactionAttributeSource(); } /* * 創建事務advice * TransactionInterceptor * */ @Bean @Role(BeanDefinition.ROLE_INFRASTRUCTURE) public TransactionInterceptor transactionInterceptor() { TransactionInterceptor interceptor = new TransactionInterceptor(); interceptor.setTransactionAttributeSource(transactionAttributeSource()); //事務管理器要跟數據源掛鉤,所以需要自己定義 if (this.txManager != null) { interceptor.setTransactionManager(this.txManager); } return interceptor; }}

看到這就很清楚了,前者是注冊AOP的入口類(這里注冊的入口類依然是InfrastructureAdvisorAutoProxyCreator),后者則是創建事務AOP的組件的實例到IOC中,到這里相信不僅僅是對于事務的零配置,而是整個SpringBoot的零配置實現原理都心中有數了。

總結

本篇結合之前所學分析了事務配置解析的原理,也帶出了SpringBoot零配置實現的原理,下一篇就是事務的執行調用過程。我們需要在腦海將加載、解析和調用串聯起來,從微觀到宏觀整體把握Spring,才能真正的理解Spring。

以上這篇這一次搞懂Spring事務注解的解析方式就是小編分享給大家的全部內容了,希望能給大家一個參考,也希望大家多多支持好吧啦網。

標簽: Spring
相關文章:
主站蜘蛛池模板: 艾默生变频器,艾默生ct,变频器,ct驱动器,广州艾默生变频器,供水专用变频器,风机变频器,电梯变频器,艾默生变频器代理-广州市盟雄贸易有限公司官方网站-艾默生变频器应用解决方案服务商 | 驾驶人在线_专业学车门户网站 | Akribis直线电机_直线模组_力矩电机_直线电机平台|雅科贝思Akribis-杭州摩森机电科技有限公司 | 防勒索软件_数据防泄密_Trellix(原McAfee)核心代理商_Trellix(原Fireeye)售后-广州文智信息科技有限公司 | 六自由度平台_六自由度运动平台_三自由度摇摆台—南京全控科技 | 最新范文网_实用的精品范文美文网 | 手术室净化厂家_成都实验室装修公司_无尘车间施工单位_洁净室工程建设团队-四川华锐16年行业经验 | 权威废金属|废塑料|废纸|废铜|废钢价格|再生资源回收行情报价中心-中废网 | 金属抛光机-磁悬浮抛光机-磁力研磨机-磁力清洗机 - 苏州冠古科技 | 中红外QCL激光器-其他连续-半导体连续激光器-筱晓光子 | 定量包装秤,吨袋包装称,伸缩溜管,全自动包装秤,码垛机器人,无锡市邦尧机械工程有限公司 | 皮带输送机-大倾角皮带输送机-皮带输送机厂家-河南坤威机械 | 无缝钢管-聊城无缝钢管-小口径无缝钢管-大口径无缝钢管 - 聊城宽达钢管有限公司 | 提升海外网站流量,增加国外网站访客UV,定制海外IP-访客王 | 智能交通网_智能交通系统_ITS_交通监控_卫星导航_智能交通行业 | 吸音板,隔音板,吸音材料,吸音板价格,声学材料 - 佛山诺声吸音板厂家 | 整合营销推广|营销网络推广公司|石家庄网站优化推广公司|智营销 好物生环保网、环保论坛 - 环保人的学习交流平台 | 智能终端_RTU_dcm_北斗星空自动化科技 | 低浓度恒温恒湿称量系统,强光光照培养箱-上海三腾仪器有限公司 | 国产离子色谱仪,红外分光测油仪,自动烟尘烟气测试仪-青岛埃仑通用科技有限公司 | 无缝钢管-聊城无缝钢管-小口径无缝钢管-大口径无缝钢管 - 聊城宽达钢管有限公司 | 阁楼货架_阁楼平台_仓库仓储设备_重型货架_广州金铁牛货架厂 | 膜结构车棚|上海膜结构车棚|上海车棚厂家|上海膜结构公司 | 活性氧化铝球|氧化铝干燥剂|分子筛干燥剂|氢氧化铝粉-淄博同心材料有限公司 | 齿轮减速机电机一体机_齿轮减速箱加电机一体化-德国BOSERL蜗轮蜗杆减速机电机生产厂家 | 绿萝净除甲醛|深圳除甲醛公司|测甲醛怎么收费|培训机构|电影院|办公室|车内|室内除甲醛案例|原理|方法|价格立马咨询 | 免费B2B信息推广发布平台 - 推发网| 玻璃钢板-玻璃钢防腐瓦-玻璃钢材料-广东壹诺 | 金属切削液-脱水防锈油-电火花机油-抗磨液压油-深圳市雨辰宏业科技发展有限公司 | 泉州陶瓷pc砖_园林景观砖厂家_石英砖地铺石价格 _福建暴风石英砖 | 合肥宠物店装修_合肥宠物美容院装修_合肥宠物医院设计装修公司-安徽盛世和居装饰 | PCB设计,PCB抄板,电路板打样,PCBA加工-深圳市宏力捷电子有限公司 | 沈阳庭院景观设计_私家花园_别墅庭院设计_阳台楼顶花园设计施工公司-【沈阳现代时园艺景观工程有限公司】 | 热缩管切管机-超声波切带机-织带切带机-无纺布切布机-深圳市宸兴业科技有限公司 | 郑州宣传片拍摄-TVC广告片拍摄-微电影短视频制作-河南优柿文化传媒有限公司 | 股指期货-期货开户-交易手续费佣金加1分-保证金低-期货公司排名靠前-万利信息开户 | 山西3A认证|太原AAA信用认证|投标AAA信用证书-山西AAA企业信用评级网 | 电镀整流器_微弧氧化电源_高频电解电源_微弧氧化设备厂家_深圳开瑞节能 | 活性炭-果壳木质煤质柱状粉状蜂窝活性炭厂家价格多少钱 | 火锅底料批发-串串香技术培训[川禾川调官网] | 厂房出租-厂房规划-食品技术-厂房设计-厂房装修-建筑施工-设备供应-设备求购-龙爪豆食品行业平台 |