Spring Retry-01

org.springframework.retry.support.RetryTemplate

Spring新建了一个类RetryTemplate来封装增强的逻辑,可以看看这个类中最里面的逻辑doExecute()方法,里面有个while循环就知道是重试的核心。这段逻辑还没有涉及到Spring框架,还只是一个独立的重试设计。

protected <T, E extends Throwable> T doExecute(RetryCallback<T, E> retryCallback,
		RecoveryCallback<T> recoveryCallback, RetryState state) throws E, ExhaustedRetryException {

	RetryPolicy retryPolicy = this.retryPolicy;
	BackOffPolicy backOffPolicy = this.backOffPolicy;

	// Allow the retry policy to initialise itself...
	RetryContext context = open(retryPolicy, state);
	if (this.logger.isTraceEnabled()) {
		this.logger.trace("RetryContext retrieved: " + context);
	}

	// Make sure the context is available globally for clients who need
	// it...
	RetrySynchronizationManager.register(context);

	Throwable lastException = null;

	boolean exhausted = false;
	try {

		// Give clients a chance to enhance the context...
		boolean running = doOpenInterceptors(retryCallback, context);

		if (!running) {
			throw new TerminatedRetryException("Retry terminated abnormally by interceptor before first attempt");
		}

		// Get or Start the backoff context...
		BackOffContext backOffContext = null;
		Object resource = context.getAttribute("backOffContext");

		if (resource instanceof BackOffContext) {
			backOffContext = (BackOffContext) resource;
		}

		if (backOffContext == null) {
			backOffContext = backOffPolicy.start(context);
			if (backOffContext != null) {
				context.setAttribute("backOffContext", backOffContext);
			}
		}

		/*
		 * We allow the whole loop to be skipped if the policy or context already
		 * forbid the first try. This is used in the case of external retry to allow a
		 * recovery in handleRetryExhausted without the callback processing (which
		 * would throw an exception).
		 */
		while (canRetry(retryPolicy, context) && !context.isExhaustedOnly()) {

			try {
				if (this.logger.isDebugEnabled()) {
					this.logger.debug("Retry: count=" + context.getRetryCount());
				}
				// Reset the last exception, so if we are successful
				// the close interceptors will not think we failed...
				lastException = null;
				T result = retryCallback.doWithRetry(context);
				doOnSuccessInterceptors(retryCallback, context, result);
				return result;
			}
			catch (Throwable e) {

				lastException = e;

				try {
					registerThrowable(retryPolicy, state, context, e);
				}
				catch (Exception ex) {
					throw new TerminatedRetryException("Could not register throwable", ex);
				}
				finally {
					doOnErrorInterceptors(retryCallback, context, e);
				}

				if (canRetry(retryPolicy, context) && !context.isExhaustedOnly()) {
					try {
						backOffPolicy.backOff(backOffContext);
					}
					catch (BackOffInterruptedException ex) {
						lastException = e;
						// back off was prevented by another thread - fail the retry
						if (this.logger.isDebugEnabled()) {
							this.logger.debug("Abort retry because interrupted: count=" + context.getRetryCount());
						}
						throw ex;
					}
				}

				if (this.logger.isDebugEnabled()) {
					this.logger.debug("Checking for rethrow: count=" + context.getRetryCount());
				}

				if (shouldRethrow(retryPolicy, context, state)) {
					if (this.logger.isDebugEnabled()) {
						this.logger.debug("Rethrow in retry for policy: count=" + context.getRetryCount());
					}
					throw RetryTemplate.<E>wrapIfNecessary(e);
				}

			}

			/*
			 * A stateful attempt that can retry may rethrow the exception before now,
			 * but if we get this far in a stateful retry there's a reason for it,
			 * like a circuit breaker or a rollback classifier.
			 */
			if (state != null && context.hasAttribute(GLOBAL_STATE)) {
				break;
			}
		}

		if (state == null && this.logger.isDebugEnabled()) {
			this.logger.debug("Retry failed last attempt: count=" + context.getRetryCount());
		}

		exhausted = true;
		return handleRetryExhausted(recoveryCallback, context, state);

	}
	catch (Throwable e) {
		throw RetryTemplate.<E>wrapIfNecessary(e);
	}
	finally {
		close(retryPolicy, context, state, lastException == null || exhausted);
		doCloseInterceptors(retryCallback, context, lastException);
		RetrySynchronizationManager.clear();
	}

}

这个具体逻辑先放下,需要继续往上找到谁在调用这个重试逻辑

org.springframework.retry.interceptor.RetryOperationsInterceptor

到了这里就涉及到Spring框架了,其中MethodInterceptor是Spring引入aop联盟的接口,用来封装方法增强的逻辑。MethodInterceptor只提供了一个方法invoke(),实现这个方法的人只需要加上自己的增强逻辑后再调用参数的Methodinvocation,执行被增强的逻辑即可。

Object invoke(@Nonnull MethodInvocation invocation) throws Throwable;
public class RetryOperationsInterceptor implements MethodInterceptor {

	private RetryOperations retryOperations = new RetryTemplate();

	private MethodInvocationRecoverer<?> recoverer;

	private String label;

	public void setLabel(String label) {
		this.label = label;
	}

	public void setRetryOperations(RetryOperations retryTemplate) {
		Assert.notNull(retryTemplate, "'retryOperations' cannot be null.");
		this.retryOperations = retryTemplate;
	}

	public void setRecoverer(MethodInvocationRecoverer<?> recoverer) {
		this.recoverer = recoverer;
	}

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

		String name;
		if (StringUtils.hasText(this.label)) {
			name = this.label;
		}
		else {
			name = invocation.getMethod().toGenericString();
		}
		final String label = name;

		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");
				}
			}

		};

		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__");
				}
			}
		}

		return this.retryOperations.execute(retryCallback);

	}

	/**
	 * @author Dave Syer
	 *
	 */
	private static final class ItemRecovererCallback implements RecoveryCallback<Object> {

		private final Object[] args;

		private final MethodInvocationRecoverer<?> recoverer;

		/**
		 * @param args the item that failed.
		 */
		private ItemRecovererCallback(Object[] args, MethodInvocationRecoverer<?> recoverer) {
			this.args = Arrays.asList(args).toArray();
			this.recoverer = recoverer;
		}

		@Override
		public Object recover(RetryContext context) {
			return this.recoverer.recover(this.args, context.getLastThrowable());
		}

	}

}

接下来需要继续往上再追一层,看看是谁调用RetryOperationsInterceptor的invoke()方法,

org.springframework.retry.annotation.AnnotationAwareRetryOperationsInterceptor

这个类将自身融入到了Spring框架中,因为他实现了org.springframework.aop.IntroductionInterceptor接口,而IntroductionInterceptor有继承了MethodInterceptor,也就是说AnnotationAwareRetryOperationsInterceptor其实是个MethodInterceptor,而它却要调用另外一个MethodInterceptor--------RetryOperationsInterceptor,这种手法很常见,就是静态代理了一层,用于扩展出2种类型。而AnnotationAwareRetryOperationsInterceptor是会在Spring启动时被发现,然后进行动态代理生成。这样就自动增强了。

猜你喜欢

转载自blog.csdn.net/tales522/article/details/131013619