- ExponentialBackOffPolicy
例如:默认初始 0.1 秒 , 系数是 2 , 那么下次延迟 0.2 秒 , 再下次就是延迟 0.4 秒 , 如此类推 , 最大 30 秒 。
- ExponentialRandomBackOffPolicy
- UniformRandomBackOffPolicy
原理切入点@EnableRetry
@Target(ElementType.TYPE)@Retention(RetentionPolicy.RUNTIME)@EnableAspectJAutoProxy(proxyTargetClass = false)@Import(RetryConfiguration.class)@Documentedpublic @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*/boolean proxyTargetClass() default false;}
@EnablRetry 中使用了两个特殊的注解- @EnableAspectJAutoProxy
- @Import
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)@Componentpublic class RetryConfiguration extends AbstractPointcutAdvisorimplements IntroductionAdvisor, BeanFactoryAware, InitializingBean {private Advice advice;private Pointcut pointcut;
我们可以看到 RetryConfiguration 继承了 AbstractPointcutAdvisor , 所以 RetryConfiguration 需要实现 getAdvice() 和 getPointcut() 接口 , 所以这个 bean 的作用就是为 @Retryable 注解注册 pointcut 切点和 advice 增强 。我们再来看他的 初始化方法@Overridepublic void afterPropertiesSet() throws Exception {this.retryContextCache = findBean(RetryContextCache.class);this.methodArgumentsKeyGenerator = findBean(MethodArgumentsKeyGenerator.class);this.newMethodArgumentsIdentifier = findBean(NewMethodArgumentsIdentifier.class);this.retryListeners = findBeans(RetryListener.class);this.sleeper = findBean(Sleeper.class);Set<Class<? extends Annotation>> retryableAnnotationTypes = new LinkedHashSet<Class<? extends Annotation>>(1);retryableAnnotationTypes.add(Retryable.class);this.pointcut = buildPointcut(retryableAnnotationTypes); //创建 pointcutthis.advice = buildAdvice(); //创建 adviceif (this.advice instanceof BeanFactoryAware) {((BeanFactoryAware) this.advice).setBeanFactory(this.beanFactory);}}
protected Advice buildAdvice() {AnnotationAwareRetryOperationsInterceptor interceptor = new AnnotationAwareRetryOperationsInterceptor();if (this.retryContextCache != null) {interceptor.setRetryContextCache(this.retryContextCache);}if (this.retryListeners != null) {interceptor.setListeners(this.retryListeners);}if (this.methodArgumentsKeyGenerator != null) {interceptor.setKeyGenerator(this.methodArgumentsKeyGenerator);}if (this.newMethodArgumentsIdentifier != null) {interceptor.setNewItemIdentifier(this.newMethodArgumentsIdentifier);}if (this.sleeper != null) {interceptor.setSleeper(this.sleeper);}return interceptor; }
上面代码用到了 AnnotationClassOrMethodPointcut , 其实它最终还是用到了 AnnotationMethodMatcher 来根据注解进行切入点的过滤 。这里就是 @Retryable 注解了下面来看 AnnotationAwareRetryOperationsInterceptor 的 invoke() 方法
@Overridepublic Object invoke(MethodInvocation invocation) throws Throwable {//获取真正的代理类MethodInterceptor delegate = getDelegate(invocation.getThis(), invocation.getMethod());if (delegate != null) {//代理类存在 , 则执行代理类的 invoke()方法return delegate.invoke(invocation);}else {//否则 , 直接执行目标方法return invocation.proceed();}}
这里 getDelegate() 会处理 @Retryable 的相关参数以及决定使用哪种重试策略和退避策略 。private MethodInterceptor getDelegate(Object target, Method method) {ConcurrentMap<Method, MethodInterceptor> cachedMethods = this.delegates.get(target);if (cachedMethods == null) {cachedMethods = new ConcurrentHashMap<Method, MethodInterceptor>();}MethodInterceptor delegate = cachedMethods.get(method);if (delegate == null) {//获取方法上的 Retryable 注解MethodInterceptor interceptor = NULL_INTERCEPTOR;Retryable retryable = AnnotatedElementUtils.findMergedAnnotation(method, Retryable.class);if (retryable == null) {//获取类上的 Retryable 注解retryable = AnnotatedElementUtils.findMergedAnnotation(method.getDeclaringClass(), Retryable.class);}if (retryable == null) {//获取目标类或者方法上的 Retryable 注解retryable = findAnnotationOnTarget(target, method, Retryable.class);}if (retryable != null) {if (StringUtils.hasText(retryable.interceptor())) {//是否实现了自定义拦截 , 优先级最高interceptor = this.beanFactory.getBean(retryable.interceptor(), MethodInterceptor.class);}else if (retryable.stateful()) {//有状态的拦截interceptor = getStatefulInterceptor(target, method, retryable);}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;}
推荐阅读
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 何静|何静公开力挺汪小菲!怒斥大S太欺负人,称其算什么东西必遭报应
- 为什么交警查车会摸一下车尾?听交警一说,网友:太机智了
- 发动机故障灯亮一会就灭了,这是什么情况?
- 杨乐乐|杨乐乐毁灭史:从“湖南一姐”到“万人唾”,她都做了什么事?
- 大头菜有什么功效作用 大头菜可以生吃吗
- 带子什么人不能吃 带子可以生吃吗
- 七境堂绿茶是什么茶 七境堂绿茶价格及批发价查询
- 翡翠|很多人知道翡翠不戴要水养,但用什么水?
- 大闸蟹的选购技巧 大闸蟹988型是什么意思
- |为什么很多员工会谎报离职原因?