javascript
spring aop不执行_使用Spring AOP重试方法执行
spring aop不執行
我的一位博客關注者發送了一封電子郵件,要求我顯示“ Spring AOP的RealWorld用法”示例。 他提到,在大多數示例中,都演示了Spring AOP在日志記錄方法進入/退出或事務管理或安全性檢查中的用法。
他想知道Spring AOP在“針對實際問題的真實項目”中的用法。 因此,我想展示如何在我的一個項目中使用Spring AOP來處理一個實際問題。
我們不會在開發階段遇到任何問題,只有在負載測試期間或僅在生產環境中才知道。
例如:
- 由于網絡延遲問題而導致的遠程WebService調用失敗
- 由于Lock異常等導致數據庫查詢失敗
在大多數情況下,只需重試同一操作就足以解決此類故障。
讓我們看看如果發生任何異常,如何使用Spring AOP自動重試方法執行。 我們可以使用Spring AOP @Around建議為那些需要重試其方法的對象創建代理,并在Aspect中實現重試邏輯。
在繼續執行這些Spring Advice和Aspect之前,首先讓我們編寫一個簡單的實用程序來執行“任務” ,該任務將自動重試N次,而忽略給定的異常集。
public interface Task<T> {T execute(); }import java.util.HashSet; import java.util.Set; import org.slf4j.Logger; import org.slf4j.LoggerFactory;public class TaskExecutionUtil {private static Logger logger = LoggerFactory.getLogger(TaskExecutionUtil.class);@SafeVarargspublic static <T> T execute(Task<T> task, int noOfRetryAttempts, long sleepInterval, Class<? extends Throwable>... ignoreExceptions) {if (noOfRetryAttempts < 1) {noOfRetryAttempts = 1;}Set<Class<? extends Throwable>> ignoreExceptionsSet = new HashSet<Class<? extends Throwable>>();if (ignoreExceptions != null && ignoreExceptions.length > 0) {for (Class<? extends Throwable> ignoreException : ignoreExceptions) {ignoreExceptionsSet.add(ignoreException);}}logger.debug("noOfRetryAttempts = "+noOfRetryAttempts);logger.debug("ignoreExceptionsSet = "+ignoreExceptionsSet);T result = null;for (int retryCount = 1; retryCount <= noOfRetryAttempts; retryCount++) {logger.debug("Executing the task. Attemp#"+retryCount);try {result = task.execute();break;} catch (RuntimeException t) {Throwable e = t.getCause();logger.error(" Caught Exception class"+e.getClass());for (Class<? extends Throwable> ignoreExceptionClazz : ignoreExceptionsSet) {logger.error(" Comparing with Ignorable Exception : "+ignoreExceptionClazz.getName());if (!ignoreExceptionClazz.isAssignableFrom(e.getClass())) {logger.error("Encountered exception which is not ignorable: "+e.getClass());logger.error("Throwing exception to the caller");throw t;}}logger.error("Failed at Retry attempt :" + retryCount + " of : " + noOfRetryAttempts);if (retryCount >= noOfRetryAttempts) {logger.error("Maximum retrial attempts exceeded.");logger.error("Throwing exception to the caller");throw t;}try {Thread.sleep(sleepInterval);} catch (InterruptedException e1) {//Intentionally left blank}}}return result;}}我希望這種方法可以自我解釋。 它要花費一個Task 并重試noOfRetryAttempts次,以防task.execute()方法拋出任何Exception且ignoreExceptions指示重試時要忽略的異常類型。
現在讓我們創建一個Retry注釋,如下所示:
import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target;@Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) public @interface Retry {public int retryAttempts() default 3;public long sleepInterval() default 1000L; //millisecondsClass<? extends Throwable>[] ignoreExceptions() default { RuntimeException.class };}我們將使用此@Retry批注來劃分需要重試的方法。
現在讓我們實現適用于帶有@Retry批注的方法的Aspect。
import java.lang.reflect.Method;import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.reflect.MethodSignature; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Component;@Component @Aspect public class MethodRetryHandlerAspect {private static Logger logger = LoggerFactory.getLogger(MethodRetryHandlerAspect.class);@Around("@annotation(com.sivalabs.springretrydemo.Retry)")public Object audit(ProceedingJoinPoint pjp) {Object result = null;result = retryableExecute(pjp);return result;}protected Object retryableExecute(final ProceedingJoinPoint pjp){MethodSignature signature = (MethodSignature) pjp.getSignature();Method method = signature.getMethod();logger.debug("-----Retry Aspect---------");logger.debug("Method: "+signature.toString());Retry retry = method.getDeclaredAnnotation(Retry.class);int retryAttempts = retry.retryAttempts();long sleepInterval = retry.sleepInterval();Class<? extends Throwable>[] ignoreExceptions = retry.ignoreExceptions();Task<Object> task = new Task<Object>() {@Overridepublic Object execute() {try {return pjp.proceed();} catch (Throwable e) {throw new RuntimeException(e);}}};return TaskExecutionUtil.execute(task, retryAttempts, sleepInterval, ignoreExceptions);} }而已。 我們只需要一些測試用例即可對其進行實際測試。
首先創建AppConfig.java配置類,如下所示:
import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.EnableAspectJAutoProxy;@Configuration @ComponentScan @EnableAspectJAutoProxy public class AppConfig {}和幾個虛擬Service Bean。
import org.springframework.stereotype.Service;@Service public class ServiceA {private int counter = 1;public void method1() {System.err.println("----method1----");}@Retry(retryAttempts=5, ignoreExceptions={NullPointerException.class})public void method2() {System.err.println("----method2 begin----");if(counter != 3){counter++;throw new NullPointerException();}System.err.println("----method2 end----"); } }import java.io.IOException; import org.springframework.stereotype.Service;@Service public class ServiceB {@Retry(retryAttempts = 2, ignoreExceptions={IOException.class})public void method3() {System.err.println("----method3----");if(1 == 1){throw new ArrayIndexOutOfBoundsException();}}@Retrypublic void method4() {System.err.println("----method4----");} }最后編寫一個簡單的Junit測試來調用這些方法。
import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;@RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(classes=AppConfig.class) public class RetryTest {@Autowired ServiceA svcA;@Autowired ServiceB svcB;@Testpublic void testA(){svcA.method1();}@Testpublic void testB(){svcA.method2();}@Test(expected=RuntimeException.class)public void testC(){svcB.method3();}@Testpublic void testD(){svcB.method4();} }是的,我知道我可以寫出更好的這些測試方法,但我希望您能理解。
運行JUnit測試并觀察log語句以驗證是否在發生Exception的情況下重試方法。
- 情況1:調用ServiceA.method1()時,根本不會應用MethodRetryHandlerAspect。
- 情況2:調用ServiceA.method2()時,我們將維護一個計數器并拋出NullPointerException 2次。 但是我們已經標記了該方法以忽略NullPointerExceptions。 因此它將繼續重試5次。 但是第三次??方法將正常執行并正常退出該方法。
- 情況3:調用ServiceB.method3()時,我們將拋出ArrayIndexOutOfBoundsException,但該方法被標記為僅忽略IOException。 因此,將不會重試此方法的執行,并且會立即引發Exception。
- 情況4:調用ServiceB.method4()時,一切都很好,因此通常應在第一次嘗試中退出。
我希望這個例子能說明Spring AOP在現實世界中有足夠的用處:-)
翻譯自: https://www.javacodegeeks.com/2016/02/retrying-method-execution-using-spring-aop.html
spring aop不執行
總結
以上是生活随笔為你收集整理的spring aop不执行_使用Spring AOP重试方法执行的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 科技昨夜今晨 0925:12306 回应
- 下一篇: gradle idea java ssm