序
本文主要研究一下 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 创建了 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 根据
spring.aop.proxy-target-class
来注入不同的代理方式,默认是 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 实现了 aopalliance 的 MethodInterceptor;它将 invocation 包装为 retryCallback,然后使用 RetryTemplate 实现重试
小结
- RetryConfiguration 注册了 consulRetryInterceptor,它基于 RetryProperties 创建了 RetryOperationsInterceptor
- RetryProperties 定义了 initialInterval、multiplier、maxInterval、maxAttempts 属性
- RetryOperationsInterceptor 实现了 aopalliance 的 MethodInterceptor;它将 invocation 包装为 retryCallback,然后使用 RetryTemplate 实现重试
doc
- RetryProperties