企业网站cms源码,孝昌县专注网站建设代理,WordPress多站點支付插件,wordpress 首页 静态页面我的一位博客关注者发送了一封电子邮件#xff0c;要求我显示“ Spring AOP的RealWorld用法”示例。 他提到#xff0c;在大多数示例中#xff0c;都演示了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 TaskT {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(TaskT task, int noOfRetryAttempts, long sleepInterval, Class? extends Throwable... ignoreExceptions) {if (noOfRetryAttempts 1) {noOfRetryAttempts 1;}SetClass? extends Throwable ignoreExceptionsSet new HashSetClass? 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 classe.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();TaskObject task new TaskObject() {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(retryAttempts5, 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(classesAppConfig.class)
public class RetryTest
{Autowired ServiceA svcA;Autowired ServiceB svcB;Testpublic void testA(){svcA.method1();}Testpublic void testB(){svcA.method2();}Test(expectedRuntimeException.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