Add Retryable interface for proxies advising @Retryable beans
This is purely a marker interface, but might be useful for other tools looking to apply retry advice (they should usually not bother if the bean already implements Retryable)
This commit is contained in:
@@ -260,6 +260,8 @@ for a random backoff between 100 and 500 milliseconds and up to 12 attempts. The
|
||||
|
||||
The `@EnableRetry` annotation also looks for beans of type `Sleeper` and other strategies used in the `RetryTemplate` and interceptors to control the beviour of the retry at runtime.
|
||||
|
||||
The `@EnableRetry` annotation creates proxies for `@Retryable` beans, and the proxies (so the bean instances in the application) have the `Retryable` interface added to them. This is purely a marker interface, but might be useful for other tools looking to apply retry advice (they should usually not bother if the bean already implements `Retryable`).
|
||||
|
||||
### XML Configuration
|
||||
|
||||
Here is an example of declarative iteration using Spring AOP to repeat a service call to a method called `remoteCall` (for more detail on how to configure AOP interceptors see the Spring User Guide):
|
||||
|
||||
@@ -115,7 +115,6 @@ public class AnnotationAwareRetryOperationsInterceptor implements MethodIntercep
|
||||
} else {
|
||||
delegate = getStatelessInterceptor(target, method, retryable);
|
||||
}
|
||||
// TODO: allow declaring class to specify @Recover methods
|
||||
delegates.put(method, delegate);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,6 +23,8 @@ import java.util.Set;
|
||||
import javax.annotation.PostConstruct;
|
||||
|
||||
import org.aopalliance.aop.Advice;
|
||||
import org.springframework.aop.ClassFilter;
|
||||
import org.springframework.aop.IntroductionAdvisor;
|
||||
import org.springframework.aop.Pointcut;
|
||||
import org.springframework.aop.support.AbstractPointcutAdvisor;
|
||||
import org.springframework.aop.support.ComposablePointcut;
|
||||
@@ -49,7 +51,7 @@ import org.springframework.retry.policy.RetryContextCache;
|
||||
@SuppressWarnings("serial")
|
||||
@Configuration
|
||||
public class RetryConfiguration extends AbstractPointcutAdvisor implements
|
||||
BeanFactoryAware {
|
||||
IntroductionAdvisor, BeanFactoryAware {
|
||||
|
||||
private Advice advice;
|
||||
|
||||
@@ -86,6 +88,20 @@ public class RetryConfiguration extends AbstractPointcutAdvisor implements
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClassFilter getClassFilter() {
|
||||
return pointcut.getClassFilter();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<?>[] getInterfaces() {
|
||||
return new Class[] { org.springframework.retry.interceptor.Retryable.class };
|
||||
}
|
||||
|
||||
@Override
|
||||
public void validateInterfaces() throws IllegalArgumentException {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Advice getAdvice() {
|
||||
return this.advice;
|
||||
|
||||
@@ -17,6 +17,7 @@ import java.util.Arrays;
|
||||
|
||||
import org.aopalliance.intercept.MethodInterceptor;
|
||||
import org.aopalliance.intercept.MethodInvocation;
|
||||
import org.springframework.aop.IntroductionInterceptor;
|
||||
import org.springframework.aop.ProxyMethodInvocation;
|
||||
import org.springframework.retry.RecoveryCallback;
|
||||
import org.springframework.retry.RetryCallback;
|
||||
@@ -41,7 +42,7 @@ import org.springframework.util.Assert;
|
||||
* @author Rob Harrop
|
||||
* @author Dave Syer
|
||||
*/
|
||||
public class RetryOperationsInterceptor implements MethodInterceptor {
|
||||
public class RetryOperationsInterceptor implements IntroductionInterceptor {
|
||||
|
||||
private RetryOperations retryOperations = new RetryTemplate();
|
||||
private MethodInvocationRecoverer<?> recoverer;
|
||||
@@ -54,6 +55,11 @@ public class RetryOperationsInterceptor implements MethodInterceptor {
|
||||
public void setRecoverer(MethodInvocationRecoverer<?> recoverer) {
|
||||
this.recoverer = recoverer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean implementsInterface(Class<?> intf) {
|
||||
return Retryable.class.isAssignableFrom(intf);
|
||||
}
|
||||
|
||||
public Object invoke(final MethodInvocation invocation) throws Throwable {
|
||||
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* Copyright 2013-2014 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
|
||||
*
|
||||
* http://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;
|
||||
|
||||
/**
|
||||
* Marker interface for proxies that are providing retryable behaviour. Can be added by
|
||||
* proxy creators that use the {@link RetryOperationsInterceptor} and
|
||||
* {@link StatefulRetryOperationsInterceptor}.
|
||||
* @author Dave Syer
|
||||
*
|
||||
*/
|
||||
public interface Retryable {
|
||||
|
||||
}
|
||||
@@ -22,6 +22,7 @@ import org.aopalliance.intercept.MethodInterceptor;
|
||||
import org.aopalliance.intercept.MethodInvocation;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.aop.IntroductionInterceptor;
|
||||
import org.springframework.retry.RecoveryCallback;
|
||||
import org.springframework.retry.RetryCallback;
|
||||
import org.springframework.retry.RetryContext;
|
||||
@@ -51,7 +52,7 @@ import org.springframework.util.ObjectUtils;
|
||||
*
|
||||
* @author Dave Syer
|
||||
*/
|
||||
public class StatefulRetryOperationsInterceptor implements MethodInterceptor {
|
||||
public class StatefulRetryOperationsInterceptor implements IntroductionInterceptor {
|
||||
|
||||
private transient Log logger = LogFactory.getLog(getClass());
|
||||
|
||||
@@ -105,6 +106,11 @@ public class StatefulRetryOperationsInterceptor implements MethodInterceptor {
|
||||
this.newMethodArgumentsIdentifier = newMethodArgumentsIdentifier;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean implementsInterface(Class<?> intf) {
|
||||
return Retryable.class.isAssignableFrom(intf);
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrap the method invocation in a stateful retry with the policy and other helpers
|
||||
* provided. If there is a failure the exception will generally be re-thrown. The only
|
||||
|
||||
@@ -18,16 +18,15 @@ package org.springframework.retry.annotation;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.springframework.aop.support.AopUtils;
|
||||
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.EnableAspectJAutoProxy;
|
||||
import org.springframework.retry.annotation.EnableRetry;
|
||||
import org.springframework.retry.annotation.Recover;
|
||||
import org.springframework.retry.annotation.Retryable;
|
||||
import org.springframework.retry.backoff.Sleeper;
|
||||
|
||||
/**
|
||||
@@ -46,6 +45,16 @@ public class EnableRetryTests {
|
||||
context.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void marker() {
|
||||
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(
|
||||
TestConfiguration.class);
|
||||
Service service = context.getBean(Service.class);
|
||||
assertTrue(AopUtils.isCglibProxy(service));
|
||||
assertTrue(service instanceof org.springframework.retry.interceptor.Retryable);
|
||||
context.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void recovery() {
|
||||
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(
|
||||
|
||||
Reference in New Issue
Block a user