当前位置: 首页 > article >正文

如何在 Spring Boot 中创建自定义注解简化重复编码

你是否曾陷入重复编写相同代码的困境,渴望有一种方法能简化这一过程?如果你正在使用Spring Boot,想必你对注解的强大功能深有体会,它们能使你的代码更加简洁高效。然而,当现有的注解无法完全满足你的需求时,你又该如何应对呢?

这就是自定义注解发挥作用的地方。想象一下,能够创建自己的注解来封装重复的代码,使你的代码不仅更清洁,而且更易于维护。在本文中,我们将探讨如何在Spring Boot中制作自定义注解,以简化你的开发过程,并帮助你避免冗余代码带来的头痛。

f8b94b22f04d038b7cf883328570a49f.png

分享一个例子:假设你遇到了一个需要将应用程序中的所有错误记录到错误日志表中的场景。很快,你厌倦了在每个需要记录的方法中重复添加相同的日志代码。下面,就可以通过使用自定义注解来解决这个问题。

这个自定义注解的核心理念在于消除方法中重复的错误处理代码。与其手动在每个方法中嵌套try-catch块并逐一记录异常,不如简单地添加你的自定义注解。这个注解将充当一个标志,指示方法内发生的任何错误都应自动记录。在幕后,注解将利用Spring的面向方面编程(AOP)能力,拦截方法调用,捕获任何异常,并按照你预定义的格式进行记录。

这种方法不仅减少了样板代码,还确保了在整个应用程序中错误处理和记录的一致性。通过将错误处理逻辑集中到注解中,你可以轻松管理和更新你的日志策略,而无需触及各个方法本身。这是一种保持代码库清洁、可维护且免于冗余错误处理代码的强大方法。

下面一起来尝试一下吧!

第一步:在项目中添加 Spring AOP 依赖项

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-aop</artifactId>
    <version>6.1.12</version>
</dependency>

第 2 步:创建自定义注解

定义一个自定义注解,用于标记错误处理方法。

以下是创建 ErrorHandler 注解的方法:

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface ErrorHandler {

}

创建自定义注解的第一步是使用@interface关键字进行声明。在这个例子中,我们创建的为ErrorHandler。接下来,需要提供关于代码的元数据,@Retention和@Target是两个重要的元素,它们定义了这些注解可以在何处可用以及如何使用。

在我们的 ErrorHandler 注解中,使用了 @Retention(RetentionPolicy.RUNTIME)。这意味着注解将在运行时可用,这对于需要在应用程序执行期间检查注解的框架或自定义逻辑来说是必要的。@Target(ElementType.METHOD) 指定该注解只能应用于方法。这意味着您可以使用 @ErrorHandler 来标记您希望应用自定义错误处理逻辑的方法,但它不能应用于类、字段或其他元素。

现在我们来定义 ErrorHandler 的切面:

@Aspect
@Component
public class ErrorHandlerAspect {
    private final ErrorLogRepository errorLogRepository;
    public ErrorHandlerAspect(ErrorLogRepository errorLogRepository) {
        this.errorLogRepository = errorLogRepository;
    }
    @Pointcut("@annotation(com.maheshbabu11.spring_custom_annotations.annotations.ErrorHandler)")
    public void handleException() {
    }
    @AfterThrowing(pointcut = "handleException()", throwing = "ex")
    public void afterThrowing(Exception ex) {
        System.out.println("Exception occurred: " + ex.getMessage());
        ErrorLog errorLog = new ErrorLog();
        errorLog.setErrorLogId(UUID.randomUUID().getMostSignificantBits() & Long.MAX_VALUE); // Generate a unique ID
        errorLog.setExceptionMessage(ex.getMessage());
        errorLog.setExceptionStackTrace(getStackTraceAsString(ex));
        errorLogRepository.save(errorLog);
    }
    private String getStackTraceAsString(Exception ex) {
        StringWriter sw = new StringWriter();
        PrintWriter pw = new PrintWriter(sw);
        ex.printStackTrace(pw);
        return sw.toString();
    }
}
  • @Aspect注解将类标记为切面,这使得它能够包含将被应用于由切入点定义的连接点的通知。

  • @Pointcut注解定义了一个名为handleException的切入点,它匹配任何带有@ErrorHandler注解的方法。这是通知的目标。

  • @AfterThrowing注解指定在匹配handleException切入点的方法抛出异常后,应调用afterThrowing方法。throwing参数将抛出的异常绑定到通知方法的ex参数。

  • afterThrowing方法将异常消息记录到控制台,并创建一个ErrorLog对象,用异常的详细信息填充它,包括一个唯一的ID和堆栈跟踪,并使用errorLogRepository保存ErrorLog对象。

  • getStackTraceAsString方法将异常的堆栈跟踪转换为字符串格式,这对于日志记录和调试非常有用。

第 3 步:使用自定义注解

让我们将自定义注解添加到方法中,看看该方法出现异常时会发生什么。

@ErrorHandler
public void testExceptionLogging() {
    //simulate an exception
    if (true) {
        throw new RuntimeException("Exception occurred");
    }
}

一旦方法被调用,一个新的运行时异常被抛出,这会触发ErrorHandlerAspect中的@AfterThrowing通知。这反过来会将异常消息打印到控制台,并将错误记录在错误日志表中。

小结

在 Spring Boot中的自定义注解,如@ErrorHandler注解,提供了一种强大的机制来自动化重复任务并增强代码的可维护性。通过利用Spring AOP,你可以简化错误处理和日志记录,确保异常被一致地记录和管理,而不会在业务逻辑中充斥着重复的try-catch块。这种方法不仅简化了代码,还集中了错误处理,使其更容易更新和维护。通过自定义注解,你可以更专注于应用程序的核心功能,同时依赖于强大的自动化机制来处理像错误日志记录这样的横切关注点。

那么你有自定义过那些注解,用来解决什么问题呢?留言区一起分享一下吧~

来源:https://spring4all.com/forum-post/7659.html

我们创建了一个高质量的技术交流群,与优秀的人在一起,自己也会优秀起来,赶紧点击加群,享受一起成长的快乐。


你还在购买国内的各种昂贵又低质的技术教程吗?这里给大家推荐下我们自研的Youtube视频语音转换插件(https://youtube-dubbing.com/),一键外语转中文,英语不好的小伙伴也可以轻松的学习油管上的优质教程了,下面是演示视频,可以直观的感受一下:

如果您觉得这款插件不错,也可以推荐给您身边的朋友,目前我们开通了分享赚钱功能,只要安装本插件登录注册之后,获取邀请链接,放到你的博客侧边栏、友情链接或者发到朋友圈、微博、X等社交平台,就能获得积分,积分现在是可以i直接提现的哦~

推荐阅读

  • Redis 鸟枪换炮了

  • Spring AI 更新:支持OpenAI的结构化输出,增强对JSON响应的支持

  • IntelliJ IDEA 2024.2 发布:Spring Data JPA即时查询、自动补全cron表达式

  • Spring Boot 中使用 JSON Schema 来校验复杂JSON数据


http://www.kler.cn/a/287909.html

相关文章:

  • 重置docker版本的octoprint管理员账号密码
  • 超好用shell脚本NuShell mac安装
  • Zero、Zero-Offload、Zero-Infinity是什么
  • Docker占用空间太大磁盘空间不足清理妙招
  • Spring Boot 启动时自动配置 RabbitMQ 交换机、队列和绑定关系
  • Python读写Excel的全面教程
  • 栈和队列
  • 一 lua学习笔记:概述
  • 第L2周:机器学习-线性回归
  • Ubuntu系统本地搭建WordPress网站并一键发布内网站点至公网实战
  • 20-22 - 打造专业的编译环境
  • Language Models are Few-Shot Learners
  • 【计算机网络复习资料】
  • hello树先生——红黑树
  • go中的并发处理
  • 书生大模型实战营(1)——InterStudio基础知识+Vscode SSH连接远程服务器+Linux基础指令
  • 深度解析MFT损坏:原因、恢复策略与预防措施
  • 知道哪些键值型存储数据结构?这些数据结构的时间、空间复杂度分别是什么?什么时候选⽤?
  • 【C++】C++ 多态的底层实现
  • Python进阶04-网络编程
  • 和字符串有关的经典OJ题——字符串的逆置和字符串的翻转
  • 【TPAMI 2024】Occlusion-Aware Self-Supervised Monocular 6D Object Pose Estimation
  • 音视频解码 AVIO内存输入模式
  • nexus 清理 docker 镜像
  • rv1126-rv1109-mkcramfs-mkfs.cramfs-打包文件系统
  • 干货含源码!如何用Java后端操作Docker(命令行篇)