Весенняя повторная попытка-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 предоставляет только один метод, ignore(). Тем, кто реализует этот метод, нужно только добавить свою собственную расширенную логику, а затем вызвать метод вызова параметра для выполнения расширенной логики.

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.

org.springframework.retry.annotation.AnnotationAwareRetryOperationsInterceptor

Этот класс интегрируется в среду Spring, поскольку он реализует интерфейс org.springframework.aop.IntroductionInterceptor, а IntroductionInterceptor наследует MethodInterceptor, что означает, что AnnotationAwareRetryOperationsInterceptor на самом деле является MethodInterceptor, но он вызывает другой MethodInterceptor ---- ----RetryOperationsInterceptor, этот метод очень распространен, то есть для расширения двух типов используется слой статического прокси. AnnotationAwareRetryOperationsInterceptor будет обнаружен при запуске Spring, а затем будет создан динамический прокси. Это автоматически улучшается.

おすすめ

転載: blog.csdn.net/tales522/article/details/131013619
01-