序
本文主要研究一下spring cloud的consulRetryInterceptor
consulRetryInterceptor
spring-cloud-consul-core-2.1.2.RELEASE-sources.jar!/org/springframework/cloud/consul/ConsulAutoConfiguration.java
@Configuration
@EnableConfigurationProperties
@ConditionalOnConsulEnabled
public class ConsulAutoConfiguration {
//......
@ConditionalOnClass({ Retryable.class, Aspect.class, AopAutoConfiguration.class })
@Configuration
@EnableRetry(proxyTargetClass = true)
@Import(AopAutoConfiguration.class)
@EnableConfigurationProperties(RetryProperties.class)
protected static class RetryConfiguration {
@Bean(name = "consulRetryInterceptor")
@ConditionalOnMissingBean(name = "consulRetryInterceptor")
public RetryOperationsInterceptor consulRetryInterceptor(
RetryProperties properties) {
return RetryInterceptorBuilder.stateless()
.backOffOptions(properties.getInitialInterval(),
properties.getMultiplier(), properties.getMaxInterval())
.maxAttempts(properties.getMaxAttempts()).build();
}
}
//......
}
- RetryConfiguration注冊了consulRetryInterceptor伶丐,它基于RetryProperties創(chuàng)建了RetryOperationsInterceptor
RetryProperties
spring-cloud-consul-core-2.1.2.RELEASE-sources.jar!/org/springframework/cloud/consul/RetryProperties.java
@ConfigurationProperties("spring.cloud.consul.retry")
public class RetryProperties {
/** Initial retry interval in milliseconds. */
private long initialInterval = 1000;
/** Multiplier for next interval. */
private double multiplier = 1.1;
/** Maximum interval for backoff. */
private long maxInterval = 2000;
/** Maximum number of attempts. */
private int maxAttempts = 6;
public RetryProperties() {
}
public long getInitialInterval() {
return this.initialInterval;
}
public void setInitialInterval(long initialInterval) {
this.initialInterval = initialInterval;
}
public double getMultiplier() {
return this.multiplier;
}
public void setMultiplier(double multiplier) {
this.multiplier = multiplier;
}
public long getMaxInterval() {
return this.maxInterval;
}
public void setMaxInterval(long maxInterval) {
this.maxInterval = maxInterval;
}
public int getMaxAttempts() {
return this.maxAttempts;
}
public void setMaxAttempts(int maxAttempts) {
this.maxAttempts = maxAttempts;
}
@Override
public String toString() {
return new ToStringCreator(this).append("initialInterval", this.initialInterval)
.append("multiplier", this.multiplier)
.append("maxInterval", this.maxInterval)
.append("maxAttempts", this.maxAttempts).toString();
}
}
- RetryProperties定義了initialInterval回懦、multiplier、maxInterval、maxAttempts屬性
AopAutoConfiguration
spring-boot-autoconfigure-2.1.6.RELEASE-sources.jar!/org/springframework/boot/autoconfigure/aop/AopAutoConfiguration.java
@Configuration
@ConditionalOnClass({ EnableAspectJAutoProxy.class, Aspect.class, Advice.class, AnnotatedElement.class })
@ConditionalOnProperty(prefix = "spring.aop", name = "auto", havingValue = "true", matchIfMissing = true)
public class AopAutoConfiguration {
@Configuration
@EnableAspectJAutoProxy(proxyTargetClass = false)
@ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "false",
matchIfMissing = false)
public static class JdkDynamicAutoProxyConfiguration {
}
@Configuration
@EnableAspectJAutoProxy(proxyTargetClass = true)
@ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "true",
matchIfMissing = true)
public static class CglibAutoProxyConfiguration {
}
}
- AopAutoConfiguration根據(jù)
spring.aop.proxy-target-class
來注入不同的代理方式穴肘,默認(rèn)是cglib代理
RetryOperationsInterceptor
spring-retry-1.2.4.RELEASE-sources.jar!/org/springframework/retry/interceptor/RetryOperationsInterceptor.java
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;
}
public Object invoke(final MethodInvocation invocation) throws Throwable {
String name;
if (StringUtils.hasText(label)) {
name = label;
} else {
name = invocation.getMethod().toGenericString();
}
final String label = name;
RetryCallback<Object, Throwable> retryCallback = new RetryCallback<Object, Throwable>() {
public Object doWithRetry(RetryContext context) throws Exception {
context.setAttribute(RetryContext.NAME, label);
/*
* 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 (invocation instanceof ProxyMethodInvocation) {
try {
return ((ProxyMethodInvocation) invocation).invocableClone().proceed();
}
catch (Exception e) {
throw e;
}
catch (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 (recoverer != null) {
ItemRecovererCallback recoveryCallback = new ItemRecovererCallback(
invocation.getArguments(), recoverer);
return this.retryOperations.execute(retryCallback, recoveryCallback);
}
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;
}
public Object recover(RetryContext context) {
return recoverer.recover(args, context.getLastThrowable());
}
}
}
- RetryOperationsInterceptor實現(xiàn)了aopalliance的MethodInterceptor耘柱;它將invocation包裝為retryCallback腔长,然后使用RetryTemplate實現(xiàn)重試
小結(jié)
- RetryConfiguration注冊了consulRetryInterceptor葡缰,它基于RetryProperties創(chuàng)建了RetryOperationsInterceptor
- RetryProperties定義了initialInterval、multiplier缸榄、maxInterval渤弛、maxAttempts屬性
- RetryOperationsInterceptor實現(xiàn)了aopalliance的MethodInterceptor;它將invocation包裝為retryCallback甚带,然后使用RetryTemplate實現(xiàn)重試