国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

Spring retry(二)- 源碼解析-啟動裝配篇 @EnableRetry

這篇具有很好參考價(jià)值的文章主要介紹了Spring retry(二)- 源碼解析-啟動裝配篇 @EnableRetry。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問。

上一篇文章,我們快速介紹了下spring-retry的使用技巧,本篇我們將會剖析源碼去學(xué)習(xí)

一、 EnableRetry注解

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@EnableAspectJAutoProxy(proxyTargetClass = false)
@Import(RetryConfiguration.class)
@Documented
public @interface EnableRetry {

   /**
    * Indicate whether subclass-based (CGLIB) proxies are to be created as opposed to
    * standard Java interface-based proxies. The default is {@code false}.
    * @return whether to proxy or not to proxy the class
    */
   @AliasFor(annotation = EnableAspectJAutoProxy.class)
   boolean proxyTargetClass() default false;

   /**
    * Indicate the order in which the {@link RetryConfiguration} AOP <b>advice</b> should
    * be applied.
    * <p>
    * The default is {@code Ordered.LOWEST_PRECEDENCE - 1} in order to make sure the
    * advice is applied before other advices with {@link Ordered#LOWEST_PRECEDENCE} order
    * (e.g. an advice responsible for {@code @Transactional} behavior).
    */
   int order() default Ordered.LOWEST_PRECEDENCE - 1;

}

英文翻譯我就不再解釋了,上面說的很清楚;這里重點(diǎn)提一下@Import(RetryConfiguration.class)這個(gè)注解,表明了@EnableRetry注解的啟動配置類是RetryConfiguration, 通過@Import注解來注入對應(yīng)的配置類,這樣的做法同樣可見于@EnableAsync/@EnableScheduling等注解上; 看到這里,如何定義一個(gè)Enable配置注解是不是會了呢~

二、 RetryConfiguration如何構(gòu)建 ponintCut和advisor

@SuppressWarnings("serial")
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
@Component
public class RetryConfiguration extends AbstractPointcutAdvisor
      implements IntroductionAdvisor, BeanFactoryAware, InitializingBean, SmartInitializingSingleton, ImportAware {

    //在這里構(gòu)建了ponintCut和advice
    @Override
    public void afterPropertiesSet() throws Exception {
       this.retryContextCache = findBean(RetryContextCache.class);
       this.methodArgumentsKeyGenerator = findBean(MethodArgumentsKeyGenerator.class);
       this.newMethodArgumentsIdentifier = findBean(NewMethodArgumentsIdentifier.class);
       this.sleeper = findBean(Sleeper.class);
       Set<Class<? extends Annotation>> retryableAnnotationTypes = new LinkedHashSet<>(1);
       retryableAnnotationTypes.add(Retryable.class);
       
       //這里構(gòu)建基于@Retryable注解的切點(diǎn)
       this.pointcut = buildPointcut(retryableAnnotationTypes);
       //這里構(gòu)建了aop的通知
       this.advice = buildAdvice();
       
       this.advice.setBeanFactory(this.beanFactory);
       if (this.enableRetry != null) {
          setOrder(enableRetry.getNumber("order"));
       }
    }

}

RetryConfiguration繼承AbstractPointcutAdvisor實(shí)現(xiàn)了一個(gè)環(huán)繞切面,通知的邏輯見AnnotationAwareRetryOperationsInterceptor的實(shí)現(xiàn); 這里需要補(bǔ)一下spring AOP的基礎(chǔ)知識,詳情見文檔 https://cloud.tencent.com/developer/article/1808649 ,我覺的這篇文章已經(jīng)寫的非常好了,就不再細(xì)述;

接下來我們重點(diǎn)關(guān)注 AnnotationAwareRetryOperationsInterceptor 的實(shí)現(xiàn)邏輯,這里才是retgry啟動業(yè)務(wù)的實(shí)現(xiàn)邏輯;

三、AnotationAwareRetryOperationsInterceptor 重試retry邏輯的裝配

我們看下它的核心實(shí)現(xiàn)

public class AnnotationAwareRetryOperationsInterceptor implements IntroductionInterceptor, BeanFactoryAware {
    //...省略其它代碼
   
    @Override
    public Object invoke(MethodInvocation invocation) throws Throwable {
       //這里獲取代理MethodInterceptor
       MethodInterceptor delegate = getDelegate(invocation.getThis(), invocation.getMethod());
       if (delegate != null) {
          return delegate.invoke(invocation);
       }
       else {
          return invocation.proceed();
       }
    }
    
    /**
     * 拿到代理類的實(shí)現(xiàn)
     **
    private MethodInterceptor getDelegate(Object target, Method method) {
                //緩存解析結(jié)果,主要用于class級別的retry配置
		ConcurrentMap<Method, MethodInterceptor> cachedMethods = this.delegates.get(target);
		if (cachedMethods == null) {
			cachedMethods = new ConcurrentHashMap<>();
		}
		MethodInterceptor delegate = cachedMethods.get(method);
		if (delegate == null) {
			MethodInterceptor interceptor = NULL_INTERCEPTOR;
			Retryable retryable = AnnotatedElementUtils.findMergedAnnotation(method, Retryable.class);
			if (retryable == null) {
				retryable = classLevelAnnotation(method, Retryable.class);
			}
			if (retryable == null) {
				retryable = findAnnotationOnTarget(target, method, Retryable.class);
			}
			if (retryable != null) {
                        
                                //假如你需要實(shí)現(xiàn)自定義的攔截器,那就走的是這里的邏輯,例如你要實(shí)現(xiàn)retry的上下文放置到數(shù)據(jù)庫里記錄,不放在內(nèi)存里,那你就要考慮這里作文章了
				if (StringUtils.hasText(retryable.interceptor())) {
					interceptor = this.beanFactory.getBean(retryable.interceptor(), MethodInterceptor.class);
				}
                                
                                //有狀態(tài)的retry, 走的是這里,我沒有深入研究stateful的應(yīng)用場景,總感覺即便是有狀態(tài)的重試,必然跟業(yè)務(wù)邏輯本身也強(qiáng)關(guān)聯(lián)的,那狀態(tài)保護(hù)的邏輯,肯定也會抽出來,所以我不考慮放到框架本身去做,畢竟不同業(yè)務(wù),狀態(tài)保護(hù)方法不同;
				else if (retryable.stateful()) {
					interceptor = getStatefulInterceptor(target, method, retryable);
				}
                                
                                //這里應(yīng)該是通用邏輯鏈路了
				else {
					interceptor = getStatelessInterceptor(target, method, retryable);
				}
			}
			cachedMethods.putIfAbsent(method, interceptor);
			delegate = cachedMethods.get(method);
		}
		this.delegates.putIfAbsent(target, cachedMethods);
		return delegate == NULL_INTERCEPTOR ? null : delegate;
	}
        
        
        //無狀態(tài)的重試攔截器
        private MethodInterceptor getStatelessInterceptor(Object target, Method method, Retryable retryable) {
           //這里基于注解生產(chǎn)重試策略 和 延遲策略
           RetryTemplate template = createTemplate(retryable.listeners());
           template.setRetryPolicy(getRetryPolicy(retryable, true));
           template.setBackOffPolicy(getBackoffPolicy(retryable.backoff(), true));
           
           return RetryInterceptorBuilder.stateless()
              .retryOperations(template)
              .label(retryable.label())
              
              //這里關(guān)注下怎么構(gòu)建recover的
              .recoverer(getRecoverer(target, method))
              .build();
        }

        
        
    //...省略其它代碼
}


最終,無狀態(tài)的重試攔截器見,所以RetryOperationsInterceptor是常用鏈路的實(shí)現(xiàn)邏輯

public static class StatelessRetryInterceptorBuilder extends RetryInterceptorBuilder<RetryOperationsInterceptor> {

   private final RetryOperationsInterceptor interceptor = new RetryOperationsInterceptor();

   @Override
   public RetryOperationsInterceptor build() {
      if (this.recoverer != null) {
         this.interceptor.setRecoverer(this.recoverer);
      }
      if (this.retryOperations != null) {
         this.interceptor.setRetryOperations(this.retryOperations);
      }
      else {
         this.interceptor.setRetryOperations(this.retryTemplate);
      }
      if (this.label != null) {
         this.interceptor.setLabel(this.label);
      }
      return this.interceptor;
   }

   private StatelessRetryInterceptorBuilder() {
   }

}

四、RetryOperationsInterceptor 常用retry operation的實(shí)現(xiàn)邏輯

RetryOperationsInterceptor是直接重試攔截器的實(shí)現(xiàn)邏輯,它的邏輯比較簡單,封裝了retryTemplate的執(zhí)行邏輯;核心代碼見RetryOperationsInterceptor#invoke()

@Override
public Object invoke(final MethodInvocation invocation) throws Throwable {

   //這個(gè)名字主要用于構(gòu)建上下文的時(shí)候用,正常有么有意義不大
   String name;
   if (StringUtils.hasText(this.label)) {
      name = this.label;
   }
   else {
      name = invocation.getMethod().toGenericString();
   }
   final String label = name;

   //重試回調(diào),這里不作贅述
   RetryCallback<Object, Throwable> retryCallback = new MethodInvocationRetryCallback<Object, Throwable>(
         invocation, label) {

      @Override
      public Object doWithRetry(RetryContext context) throws Exception {

         context.setAttribute(RetryContext.NAME, this.label);
         context.setAttribute("ARGS", new Args(invocation.getArguments()));

         /*
          * If we don't copy the invocation carefully it won't keep a reference to
          * the other interceptors in the chain. We don't have a choice here but to
          * specialise to ReflectiveMethodInvocation (but how often would another
          * implementation come along?).
          */
         if (this.invocation instanceof ProxyMethodInvocation) {
            context.setAttribute("___proxy___", ((ProxyMethodInvocation) this.invocation).getProxy());
            try {
               return ((ProxyMethodInvocation) this.invocation).invocableClone().proceed();
            }
            catch (Exception | Error e) {
               throw e;
            }
            catch (Throwable e) {
               throw new IllegalStateException(e);
            }
         }
         else {
            throw new IllegalStateException(
                  "MethodInvocation of the wrong type detected - this should not happen with Spring AOP, "
                        + "so please raise an issue if you see this exception");
         }
      }

   };
   
   
   //有recover的時(shí)候,走這里就好
   if (this.recoverer != null) {
      ItemRecovererCallback recoveryCallback = new ItemRecovererCallback(invocation.getArguments(),
            this.recoverer);
      try {
         Object recovered = this.retryOperations.execute(retryCallback, recoveryCallback);
         return recovered;
      }
      finally {
         RetryContext context = RetrySynchronizationManager.getContext();
         if (context != null) {
            context.removeAttribute("__proxy__");
         }
      }
   }
   
   //沒有recover走這里,都是調(diào)用RetryTemplate#execute的邏輯
   return this.retryOperations.execute(retryCallback);

}

至此,全部的裝配邏輯就講結(jié)束,流程看下來并不復(fù)雜,對于未來自己想要定義一個(gè)類似的注解具有很大的參考意義!下一篇,我們講解一下retry的真正的執(zhí)行邏輯,并對整體的設(shè)計(jì)做一個(gè)介紹和思考總結(jié)文章來源地址http://www.zghlxwxcb.cn/news/detail-685176.html

到了這里,關(guān)于Spring retry(二)- 源碼解析-啟動裝配篇 @EnableRetry的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請點(diǎn)擊違法舉報(bào)進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

  • 拆解Spring boot:Springboot為什么如此絲滑而簡單?源碼剖析解讀自動裝配

    拆解Spring boot:Springboot為什么如此絲滑而簡單?源碼剖析解讀自動裝配

    ????歡迎光臨,終于等到你啦???? ??我是蘇澤,一位對技術(shù)充滿熱情的探索者和分享者。???? ??持續(xù)更新的專欄 《Spring 狂野之旅:從入門到入魔》 ?? 本專欄帶你從Spring入門到入魔 ? 這是蘇澤的個(gè)人主頁可以看到我其他的內(nèi)容哦???? 努力的蘇澤 http://suzee.blog.csdn

    2024年03月23日
    瀏覽(25)
  • Spring Boot 啟動擴(kuò)展點(diǎn)深入解析

    Spring Boot以其“約定優(yōu)于配置”的理念和簡潔的自動配置機(jī)制,極大地簡化了Spring應(yīng)用的初始化和開發(fā)過程。然而,在某些特定場景下,我們可能需要對Spring Boot的啟動過程進(jìn)行定制或擴(kuò)展。這時(shí),了解Spring Boot的啟動擴(kuò)展點(diǎn)就顯得尤為重要。 來自:gwzkb.com 來自:dlanye.com Spring

    2024年04月08日
    瀏覽(27)
  • Android系統(tǒng)啟動流程 源碼解析

    本文鏈接:https://blog.csdn.net/feather_wch/article/details/132518105 有道云腦圖:https://note.youdao.com/s/GZ9d8vzO 1、整體流程 Boot Room BootLoader idle kthread init init ServiceManager zygote zygote SystemServer app 1、kernel/common/init/main.c 2、andorid.mk-android.bp編譯 3、init是用戶空間鼻祖 屬于C、C++ Framework 1.1 啟動源

    2024年02月11日
    瀏覽(30)
  • 【SpringBoot3.0源碼】啟動流程源碼解析 ? 上

    SpringBoot啟動類:

    2024年02月02日
    瀏覽(31)
  • 重試框架入門:Spring-Retry&Guava-Retry

    重試框架入門:Spring-Retry&Guava-Retry

    在日常工作中,隨著業(yè)務(wù)日漸龐大,不可避免的涉及到調(diào)用遠(yuǎn)程服務(wù),但是遠(yuǎn)程服務(wù)的健壯性和網(wǎng)絡(luò)穩(wěn)定性都是不可控因素,因此,我們需要考慮合適的重試機(jī)制去處理這些問題,最基礎(chǔ)的方式就是手動重試,侵入業(yè)務(wù)代碼去處理,再高端一點(diǎn)的通過切面去處理,較為優(yōu)雅的

    2024年02月13日
    瀏覽(57)
  • Spring Retry

    Spring Retry

    工作中,經(jīng)常遇到需要重試的場景,最簡單的方式可以用try...catch...加while循環(huán)來實(shí)現(xiàn)。那么,有沒有統(tǒng)一的、優(yōu)雅一點(diǎn)兒的處理方式呢?有的,Spring Retry就可以幫我們搞定重試問題。 關(guān)于重試,我們可以關(guān)注以下以下幾個(gè)方面: 什么情況下去觸發(fā)重試機(jī)制 重試多少次,重試

    2024年02月05日
    瀏覽(17)
  • [RocketMQ] Broker啟動流程源碼解析 (二)

    [RocketMQ] Broker啟動流程源碼解析 (二)

    1.Brocker介紹 Broker主要負(fù)責(zé)消息的存儲、投遞和查詢以及服務(wù)高可用保證, Broker包含了以下幾個(gè)重要子模塊。 Remoting Module: 整個(gè)Broker的實(shí)體, 負(fù)責(zé)處理來自Client端的請求 Client Manager: 負(fù)責(zé)管理客戶端 Producer和Consumer, 維護(hù)Consumer的Topic訂閱信息 Store Service: 提供方便簡單的API接口處理

    2024年02月09日
    瀏覽(22)
  • spring retry 配置及使用

    依賴 開始使用 代碼示例 業(yè)務(wù)注解 代碼示例 注意 兩個(gè)方法的返回值要一樣,否則是不起作用的 NullPointerException 必須要將異常類型當(dāng)作參數(shù)傳入 如果不這樣的話無法進(jìn)行回調(diào),當(dāng)然不配置 @Recever 也可以,那就不會有回調(diào)處理了 寫一個(gè)action 調(diào)用一下方法 輸出結(jié)果 以上最簡單

    2024年01月19日
    瀏覽(58)
  • Spring Boot啟動源碼分析

    Spring Boot啟動源碼分析

    版本:spring-boot-starter-parent版本為2.3.0 Spring Boot項(xiàng)目的啟動入口是一個(gè)main方法,因此我們從該方法入手即可 跟蹤run方法 這里分兩步debug: new SpringApplication( primarySources ) 執(zhí)行run()方法 deduceFromClasspath推斷應(yīng)用程序類型 該方法根據(jù)是否存在指定路徑的類來推斷應(yīng)用程序類型。有

    2024年02月07日
    瀏覽(20)
  • springboot啟動流程 (3) 自動裝配

    springboot啟動流程 (3) 自動裝配

    在SpringBoot中,EnableAutoConfiguration注解用于開啟自動裝配功能。 本文將詳細(xì)分析該注解的工作流程。 啟用SpringBoot自動裝配功能,嘗試猜測和配置可能需要的組件Bean。 自動裝配類通常是根據(jù)類路徑和定義的Bean來應(yīng)用的。例如,如果類路徑上有tomcat-embedded.jar,那么可能需要一個(gè)

    2024年02月09日
    瀏覽(15)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包