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不执行

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/336037.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

LeetCode 09. 回文数

原题链接 class Solution { public:bool isPalindrome(int x) {if(x<0)return false;if(x>0 && x<10)return true;long long temp 0;int xx x;while(x!0){int n x % 10;temp temp * 10 n;x /10;}if(temp xx)return true;else{return false;}} };

python 获取文件名_真实需求 | Python+os+openpyxl 批量获取Excel的文件名和最大行数...

1. 提出需求 这已经不知道是粉丝问我的第几个办公自动化的问题了&#xff0c;并且这些问题都是大家在学习和工作中碰到过的真实问题场景。其实从下图中已经可以很明确的看出别人的需求了&#xff0c;我这里就不用在赘述了&#xff0c;下面直接上思路吧&#xff01;2. 解题思路为…

LeetCode 03. 无重复字符的最长子串

原题链接 解题思路: (双指针扫描) O(n)&#xff0c;双指针主要作用是维护一段区间 定义两个指针 i,j(i<j)&#xff0c;表示当前扫描到的子串是 [i,j] (闭区间)。扫描过程中维护一个哈希表unordered_map<char,int> hash&#xff0c;表示 [i,j]中每个字符出现的次数。…

python元组取值_Python基础之元组

元组初识元组的认识首先&#xff0c;我们来认识一下元组&#xff1a;# 定义一个元组uesr_tuple ("zhangsan", "lisi", "wangwu")# 定义一个空元组empty_tuple ()元组的作用和定义通过前面的学习&#xff0c;我们知道&#xff0c;列表通常用来存…

junit5和junit4_JUnit 5 –下一代JUnit的初步了解

junit5和junit42月初&#xff0c; JUnit 5&#xff08;又名JUnit Lambda&#xff09;团队发布了一个alpha版本。 由于JUnit 4是我工具箱中使用最多的项目之一&#xff0c;因此我认为值得一看下一个主要版本。 我试用了最新版本&#xff0c;并记下了我在这里发现值得注意的更改…

python进阶装饰器_老生常谈Python进阶之装饰器

函数也是对象要理解Python装饰器&#xff0c;首先要明白在Python中&#xff0c;函数也是一种对象&#xff0c;因此可以把定义函数时的函数名看作是函数对象的一个引用。既然是引用&#xff0c;因此可以将函数赋值给一个变量&#xff0c;也可以把函数作为一个参数传递或返回。同…

LeetCode 02.两数相加

原题链接 解题思路&#xff1a; 本题可以使用模拟法&#xff0c;从链表的结点中提取出val逐个相加&#xff0c;没有值取0。并且记录进位&#xff0c;每个节点只保留个位数&#xff0c;所以需要使用sum与10取模&#xff0c;如果最高位存在进位则需要在最后添加一个val为1的节点…

apache ignite_从In Memory Data Grid,Apache Ignite快速入门

apache igniteIMDG或内存数据网格不是内存中关系数据库&#xff0c;NOSQL数据库或关系数据库。 它是另一种软件数据存储库。 数据模型分布在单个位置或多个位置的许多服务器上。 这种分布称为数据结构。 这种分布式模型被称为“无共享”架构。 IMDG具有以下特征&#xff1a; 所…

bvp解算器是什么_那些学习了编程的中学生,为什么会更可能成功?

来源 | 异步当你看到这个题目&#xff0c;或许会想&#xff0c;这不是搞笑吗&#xff1f;众所周知&#xff0c;高等数学是编程的基础和前提&#xff0c;而说起程序编写员&#xff0c;在普通人眼里就是数学学霸的代名词&#xff0c;人们往往会把它和那些数学天才的名字联系在一起…

Leetcode 08. 字符串转换整数 (atoi)

原题链接 1.字符 0~~~~~9 分别对应整数 48~~~~~57 2.先过滤空白 3.确定前面所带的符号 4. long long res 0; res res * 10 str[k] - 0; 可以通过此方法从左到右高位逐个累加。 class Solution { public:int myAtoi(string str) {long long res 0;int k 0;while…

maven与spring_与Spring和Maven签约首个SOAP服务

maven与spring1.简介 在本教程中&#xff0c;我们将学习使用JAX-WS&#xff0c;Spring和Maven实施合同优先的SOAP服务应用程序。 这是使用合同优先还是代码优先方法的更多设计决定。 在开发基于SOAP的Web服务应用程序时使用应用合同优先的方法最显着的好处是&#xff0c;可以在…

如何维持手机电池寿命_充电小知识:你知道如何正确充电吗?这几种充电方式最损害电池...

目前基本上大部分人都至少有一部智能手机&#xff0c;智能手机基本上都需要每日一充&#xff0c;你的充电方式会不会损伤电池呢&#xff1f;有部分消费者认为要等到手机电量耗尽后再充电&#xff0c;还有人认为手机充电要充至100%才能拔下来&#xff0c;有人觉得充电宝等产品给…

【开放集检测】OpenGAN: Open-Set Recognition via Open Data Generation 论文阅读

文章目录 英语积累为什么使用GAN系列网络进行开放集检测摘要1. 前言2. 相关工作开集检测基于GAN网络的开集检测基于暴露异常数据的开集检测 3. OpenGAN3.1 公式建模3.1.1 二分类方法存在问题如何解决 3.1.2 使用合成数据存在问题如何解决 3.1.3 OpenGAN3.1.4 模型验证 3.2 先前…

LeetCode 27.移除元素

原题链接 /** lc appleetcode.cn id27 langcpp** [27] 移除元素标签&#xff1a;拷贝覆盖主要思路是遍历数组nums&#xff0c;每次取出的数字变量为num&#xff0c;同时设置一个下标ans在遍历过程中如果出现数字与需要移除的值不相同时&#xff0c;则进行拷贝覆盖nums[ans] n…

hotspot 默认 gc_默认HotSpot最大直接内存大小

hotspot 默认 gc在我以前的博客文章热点选项中的Java 8改进的文档 &#xff0c;我写的误解围绕热点JVM非标准的默认设置选项 -XX:MaxDirectMemorySize 。 在本文中&#xff0c;我介绍了一种确定HotSpot JVM中“默认”最大直接内存大小的简单方法。 Java启动器的Java 8文档对-X…

python控制电脑休眠唤醒键_每当计算机从休眠状态唤醒时,都运行python脚本

我在python上编写了一个小脚本,该脚本从控制台调用命令行以使linux机器休眠(或在更改一个单词的情况下将其自身关闭),然后在一段时间后唤醒.通过watch命令一次又一次地调用该命令.import osimport timeos.system("watch -n 20 sudo rtcwake -u -s 10 -m mem")因此,在…

sso集成shiro_Keycloak SSO集成到jBPM和Drools Workbench中

sso集成shiro介绍 单一登录&#xff08;SSO&#xff09;和相关令牌交换机制正在成为Web上不同环境中身份验证和授权的最常见方案&#xff0c;尤其是在迁移到云中时。 本文讨论了Keycloak与jBPM或Drools应用程序的集成&#xff0c;以便使用Keycloak上提供的所有功能。 Keycloak…

LeetCode 01. 两数之和

原题 分析&#xff1a; 1.根据题意&#xff0c;首先需要将要数据选择一个合适的 数据结构模型。 因为是对应相关联&#xff0c;所以我们选择unordered_map 2.因为是一组数&#xff0c;所以用数组 &#xff0c;将数值与数组下标对应起来 3.已知两数之和&#xff0c;从数组第…

python中自带的模块_python中的模块详解

概念python中的模块是什么&#xff1f;简而言之&#xff0c;在python中&#xff0c;一个文件(以“.py”为后缀名的文件)就叫做一个模块&#xff0c;每一个模块在python里都被看做是一个独立的文件。模块可以被项目中的其他模块、一些脚本甚至是交互式的解析器所使用&#xff0c…

剑指 Offer 51-----59

剑指 Offer 55 - I. 二叉树的深度 解题思路&#xff1a; class Solution { public:int maxDepth(TreeNode* root) {if(rootNULL)return 0;int lmaxDepth(root->left);int rmaxDepth(root->right);return (l>r?l:r)1;} };