spring-retry RetryOperationsInterceptor 源码
spring-retry RetryOperationsInterceptor 代码
文件路径:/src/main/java/org/springframework/retry/interceptor/RetryOperationsInterceptor.java
/*
* Copyright 2006-2022 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.retry.interceptor;
import java.util.Arrays;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.springframework.aop.ProxyMethodInvocation;
import org.springframework.retry.RecoveryCallback;
import org.springframework.retry.RetryCallback;
import org.springframework.retry.RetryContext;
import org.springframework.retry.RetryOperations;
import org.springframework.retry.support.Args;
import org.springframework.retry.support.RetrySynchronizationManager;
import org.springframework.retry.support.RetryTemplate;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
/**
* A {@link MethodInterceptor} that can be used to automatically retry calls to a method
* on a service if it fails. The injected {@link RetryOperations} is used to control the
* number of retries. By default it will retry a fixed number of times, according to the
* defaults in {@link RetryTemplate}.
*
* Hint about transaction boundaries. If you want to retry a failed transaction you need
* to make sure that the transaction boundary is inside the retry, otherwise the
* successful attempt will roll back with the whole transaction. If the method being
* intercepted is also transactional, then use the ordering hints in the advice
* declarations to ensure that this one is before the transaction interceptor in the
* advice chain.
*
* @author Rob Harrop
* @author Dave Syer
*/
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());
}
}
}
相关信息
相关文章
spring-retry FixedKeyGenerator 源码
spring-retry MethodArgumentsKeyGenerator 源码
spring-retry MethodInvocationRecoverer 源码
spring-retry MethodInvocationRetryCallback 源码
spring-retry NewMethodArgumentsIdentifier 源码
0
赞
热门推荐
-
2、 - 优质文章
-
3、 gate.io
-
8、 golang
-
9、 openharmony
-
10、 Vue中input框自动聚焦