最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

這一次搞懂Spring事務(wù)注解的解析方式

 更新時(shí)間:2020年08月27日 09:34:05   作者:夜勿語  
這篇文章主要介紹了這一次搞懂Spring事務(wù)注解的解析方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧

前言

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

正文

XML標(biāo)簽的解析

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

配置過事務(wù)的應(yīng)該都不陌生,上面這個(gè)配置就是Spring開啟事務(wù)注解(@Transactional)支持的配置,而看過我之前文章的應(yīng)該知道,這個(gè)帶前綴的標(biāo)簽叫自定義標(biāo)簽,我在之前的文章也分析過自定義標(biāo)簽的解析過程,所以這里我直接找到對(duì)應(yīng)的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());
 }

}

可以看到對(duì)應(yīng)的注解解析器就是AnnotationDrivenBeanDefinitionParser類,在該類中一定會(huì)有一個(gè)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模式,進(jìn)入configureAutoProxyCreator方法:

 public static void configureAutoProxyCreator(Element element, ParserContext parserContext) {
 // 注冊(cè)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執(zhí)行鏈
 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);
 }
 }

這里的流程比較長(zhǎng),但邏輯很簡(jiǎn)單。首先來看注冊(cè)事務(wù)AOP入口類是哪個(gè):

 public static void registerAutoProxyCreatorIfNecessary(
 ParserContext parserContext, Element sourceElement) {

 // 將優(yōu)先級(jí)更高的AOP入口類放入到IOC容器中
 BeanDefinition beanDefinition = AopConfigUtils.registerAutoProxyCreatorIfNecessary(
 parserContext.getRegistry(), parserContext.extractSource(sourceElement));
 // 設(shè)置代理生成的方式以及是否緩存代理類到當(dāng)前線程
 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");

 // 判斷傳進(jìn)來的類和ICO中當(dāng)前存在的類哪個(gè)優(yōu)先級(jí)更高,將更高的放入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對(duì)象,要實(shí)例化
 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;
 }

首先判斷容器中是否已經(jīng)存在AOP入口類,如果不存在則直接創(chuàng)建InfrastructureAdvisorAutoProxyCreator的BeanDefinition對(duì)象注冊(cè)到容器中,這個(gè)類也是我上一篇文章分析的AOP入口類AbstractAutoProxyCreator的子類,再來看看其繼承關(guān)系:

你會(huì)不會(huì)疑惑,這么多子類,到底會(huì)使用哪一個(gè)呢?回到剛剛的代碼中,可以看到如果已經(jīng)存在一個(gè)入口類了,就會(huì)通過findPriorityForClass獲取兩個(gè)類的優(yōu)先級(jí),最終就會(huì)使用優(yōu)先級(jí)更大的那個(gè),那么它們的優(yōu)先級(jí)順序是怎樣的呢?

 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) {
 // 索引即是優(yōu)先級(jí),越大優(yōu)先級(jí)越高,IOC中只會(huì)存在一個(gè)事務(wù)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是優(yōu)先級(jí)最低的,基本上不會(huì)起作用;AspectJAwareAdvisorAutoProxyCreator是當(dāng)我們配置了<aop:config>標(biāo)簽時(shí)會(huì)注冊(cè),也就是xml配置的AOP的入口類;而AnnotationAwareAspectJAutoProxyCreator是當(dāng)我們配置了<aop:aspectj-autoproxy>或使用@EnableAspectJAutoProxy注解時(shí)注冊(cè),因此大部分情況下都是使用的AnnotationAwareAspectJAutoProxyCreator。

注冊(cè)完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類的作用就是封裝事務(wù)注解@Transactional的屬性,這里需要記住其繼承體系以及熟悉該類和其父類的屬性和方法,對(duì)后面分析事物切面執(zhí)行原理有幫助:

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

AOP零配置原理

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

@Import(TransactionManagementConfigurationSelector.class)
public @interface EnableTransactionManagement {

 boolean proxyTargetClass() default false;
 AdviceMode mode() default AdviceMode.PROXY;
 int order() default Ordered.LOWEST_PRECEDENCE;
}

在該注解下使用@Import導(dǎo)入了一個(gè)類TransactionManagementConfigurationSelector,首先該注解的作用就是導(dǎo)入一個(gè)類的實(shí)例到IOC容器中,你可能會(huì)說不是在類上加@Component注解就行了么,但是有些類它并不在你掃描的路徑下,而該注解依然可以將其導(dǎo)入進(jìn)來,所以我么主要看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類,返回后會(huì)被封裝為BeanDefinition對(duì)象,那這個(gè)方法是在哪里調(diào)用的呢?這個(gè)在之前的文章中也分析過,ConfigurationClassPostProcessor類中會(huì)調(diào)用ConfigurationClassParser類的parse方法解析@Configuration、@Import、@ImportSource等注解,具體過程這里就不再贅述了。我們繼續(xù)來分別看看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) {
  //注冊(cè)事務(wù)AOP的入口類InfrastructureAdvisorAutoProxyCreator,實(shí)際上這個(gè)AOP入口類起不了作用
  AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry);
  if ((Boolean) proxyTargetClass) {
  AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
  return;
  }
 }
 }
 }
 }
}

public class ProxyTransactionManagementConfiguration extends AbstractTransactionManagementConfiguration {

 /*
 * 明顯是創(chuàng)建事務(wù)切面實(shí)例
 * BeanFactoryTransactionAttributeSourceAdvisor
 *
 * */
 @Bean(name = TransactionManagementConfigUtils.TRANSACTION_ADVISOR_BEAN_NAME)
 @Role(BeanDefinition.ROLE_INFRASTRUCTURE)
 public BeanFactoryTransactionAttributeSourceAdvisor transactionAdvisor() {
 BeanFactoryTransactionAttributeSourceAdvisor advisor = new BeanFactoryTransactionAttributeSourceAdvisor();
 advisor.setTransactionAttributeSource(transactionAttributeSource());
 //設(shè)置通知類
 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();
 }

 /*
 * 創(chuàng)建事務(wù)advice
 * TransactionInterceptor
 * */
 @Bean
 @Role(BeanDefinition.ROLE_INFRASTRUCTURE)
 public TransactionInterceptor transactionInterceptor() {
 TransactionInterceptor interceptor = new TransactionInterceptor();
 interceptor.setTransactionAttributeSource(transactionAttributeSource());
 //事務(wù)管理器要跟數(shù)據(jù)源掛鉤,所以需要自己定義
 if (this.txManager != null) {
 interceptor.setTransactionManager(this.txManager);
 }
 return interceptor;
 }

}

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

總結(jié)

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

以上這篇這一次搞懂Spring事務(wù)注解的解析方式就是小編分享給大家的全部?jī)?nèi)容了,希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • Java實(shí)現(xiàn)一個(gè)簡(jiǎn)單的定時(shí)器代碼解析

    Java實(shí)現(xiàn)一個(gè)簡(jiǎn)單的定時(shí)器代碼解析

    這篇文章主要介紹了Java實(shí)現(xiàn)一個(gè)簡(jiǎn)單的定時(shí)器代碼解析,具有一定借鑒價(jià)值,需要的朋友可以參考下。
    2017-12-12
  • 如何利用SpringBoot搭建WebService服務(wù)接口

    如何利用SpringBoot搭建WebService服務(wù)接口

    之前項(xiàng)目經(jīng)理想要開發(fā)一個(gè)webservice的協(xié)議,給我一個(gè)星期的時(shí)間,后面用springboot開發(fā)了webservice,這篇文章主要給大家介紹了關(guān)于如何利用SpringBoot搭建WebService服務(wù)接口的相關(guān)資料,需要的朋友可以參考下
    2023-11-11
  • Java判斷主機(jī)是否能ping通代碼實(shí)例

    Java判斷主機(jī)是否能ping通代碼實(shí)例

    這篇文章主要介紹了Java判斷主機(jī)是否能ping通代碼實(shí)例,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-01-01
  • java中URLencode、URLdecode及Base64加解密轉(zhuǎn)換

    java中URLencode、URLdecode及Base64加解密轉(zhuǎn)換

    本文主要介紹了java中URLencode、URLdecode及Base64加解密轉(zhuǎn)換,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2024-01-01
  • 一文徹底搞懂Java和JDK的版本命名問題

    一文徹底搞懂Java和JDK的版本命名問題

    今天通過本文給大家分享我對(duì)Java的版本號(hào)以及JDK的命名的了解,通過實(shí)例圖文展示給大家介紹的非常詳細(xì),需要的朋友跟隨小編一起看看吧
    2021-06-06
  • Java后端配置允許跨域方式

    Java后端配置允許跨域方式

    本文介紹了在不同技術(shù)和框架中配置跨域資源共享(CORS)的方法,包括使用SpringMVC的@CrossOrigin注解、SpringBoot的全局CORS配置、SpringSecurity中的CORS集成以及手動(dòng)設(shè)置響應(yīng)頭,根據(jù)具體需求和技術(shù)棧,選擇合適的方法來確??缬蛘?qǐng)求的安全性和有效性
    2025-02-02
  • 關(guān)于Http持久連接和HttpClient連接池的深入理解

    關(guān)于Http持久連接和HttpClient連接池的深入理解

    眾所周知,httpclient是java開發(fā)中非常常見的一種訪問網(wǎng)絡(luò)資源的方式了,下面這篇文章主要給大家介紹了關(guān)于Http持久連接和HttpClient連接池的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),需要的朋友可以參考借鑒,下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2018-05-05
  • MyBatis多數(shù)據(jù)源的兩種配置方式

    MyBatis多數(shù)據(jù)源的兩種配置方式

    這篇文章主要給大家介紹了關(guān)于MyBatis多數(shù)據(jù)源的兩種配置方式,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2018-12-12
  • Spring攔截器HandlerInterceptor接口代碼解析

    Spring攔截器HandlerInterceptor接口代碼解析

    這篇文章主要介紹了Spring攔截器HandlerInterceptor接口代碼解析,具有一定借鑒價(jià)值,需要的朋友可以參考下
    2017-12-12
  • Redis工具類封裝RedisUtils的使用示例

    Redis工具類封裝RedisUtils的使用示例

    本文主要介紹了Redis工具類封裝RedisUtils的使用示例,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-03-03

最新評(píng)論

汾西县| 大新县| 屯昌县| 洪湖市| 正宁县| 应城市| 璧山县| 仙游县| 连江县| 牟定县| 郧西县| 伊通| 宝兴县| 莲花县| 理塘县| 黄石市| 宜兴市| 双桥区| 保定市| 武穴市| 永登县| 肥乡县| 德江县| 即墨市| 岳池县| 临西县| 定兴县| 巢湖市| 遂平县| 收藏| 鹿泉市| 鹤峰县| 化隆| 连山| 灵台县| 花莲市| 桐庐县| 东海县| 汤原县| 辽阳县| 邮箱|