定制你的【Spring Boot Starter】,加速开发效率

news2025/3/12 19:51:40

摘要: 本文将介绍如何创建一个自定义的 Spring Boot Starter,让您可以封装常用功能和配置,并在多个 Spring Boot 项目中共享和重用。

1. 简介

Spring Boot Starter 是 Spring Boot 框架中的一种特殊的依赖项,它用于快速启动和配置特定功能的应用程序。Starter 实际上是一个 Maven 或 Gradle 项目,它包含了一组预配置的依赖项、默认的配置信息和自动配置类,以帮助开发者快速集成和使用某项功能。

Spring Boot Starter 通常命名为 spring-boot-starter-*,例如 spring-boot-starter-web 用于启动基本的Web应用程序,spring-boot-starter-data-jpa 用于启动使用JPA的数据访问应用程序。

2.背景

在企业微服务开发中,每个微服务模块可能会有不同的异常处理和错误信息输出方式,这样会导致系统的一致性和可维护性下降。为了解决这个问题,您希望创建一个自定义的 Spring Boot Starter,用于统一处理异常和错误信息,并提供一致的错误响应格式。

3.需求

  1. 统一的异常处理:对于常见的异常类型(如 404、500),提供统一的异常处理方式,并返回一致的错误响应。

  2. 统一的错误响应格式:定义一致的错误响应格式,包括错误代码、错误消息、错误详情等信息。

  3. 可定制化:允许开发人员根据实际情况定制异常处理和错误响应的方式,以满足不同的业务需求。

4.实现

4.1.创建SpringBoot项目

创建完成后项目结构

4.2.添加相关依赖

这里需要注意的是,在build.gradle文件中,我们在这里引入了  id 'java-library'

plugins {
    id 'java'
    // 添加 maven-publish 插件 主要是为了发布项目到 Maven 仓库
    id 'maven-publish'
    // 应用 Java Library 插件,提供 Java 项目的基本构建功能
    id 'java-library'

}

group = 'org.sys_my_start'
version = '1.0-SNAPSHOT'
ext {
    springfoxVersion = '3.2.2'
}

// 配置发布任务
publishing {
    // 定义发布内容
    publications {
        // 定义一个 MavenPublication 类型的发布
        mavenJava(MavenPublication) {
            // 发布内容来源于 Java 组件
            from components.java
            // 定义 Maven 坐标信息
            groupId 'org.sys_my_start' // Maven 项目的组织或公司标识
            artifactId 'com_sys_my_start' // 项目在 Maven 仓库中的唯一标识
            version '1.0-SNAPSHOT' // 项目的版本号,表示开发中的版本
        }
    }
}

repositories {
    mavenCentral()
}

/*  api: 这个依赖声明范围表示该依赖项不仅仅对当前项目的编译和运行时可见,而且对于其他依赖于当前项目的项目也是可见的。
    换句话说,当一个项目依赖于当前项目时,它也将自动获得该依赖项。(也就是最外层的可以访问最内层所引入的依赖)
    上面引入这个 也是为了使用api 因为 gradle 7.0 以后默认不支持 compile语法了废弃了,所以我们这里需要使用api
    id 'java-library'
*/
dependencies {
    api "org.springframework.boot:spring-boot-starter-web:$springfoxVersion"
}

test {
    useJUnitPlatform()
}

4.3.编写Starter 主要逻辑

4.3.1.编写异常处理类

package com.sys.my.start.exception;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.context.request.WebRequest;

@ControllerAdvice
public class GlobalExceptionHandler {

    private final ExceptionHandlerProperties properties;

    @Autowired
    public GlobalExceptionHandler(ExceptionHandlerProperties properties) {
        this.properties = properties;
    }

    /**
     * 处理自定义异常
     * @param ex 自定义异常
     * @param request 请求
     * @return ResponseEntity 返回异常信息
     */
    @ExceptionHandler(Exception.class)
    public ResponseEntity<ErrorResponse> handleAnyException(Exception ex, WebRequest request) {
        if (properties.isEnabled()) {
            // 处理自定义异常, 返回异常信息
            ErrorResponse errorResponse = new ErrorResponse("500", ex.getMessage(), request.getDescription(false));
            return new ResponseEntity<>(errorResponse, HttpStatus.INTERNAL_SERVER_ERROR);
        } else {
            // 未启用全局异常处理 返回500
            return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
        }
    }
}

4.3.2.编写错误响应类

package com.sys.my.start.exception;

/**
 * 定义统一错误相应格式
 */
public class ErrorResponse {
    /**
     * 错误码
     */
    private String errorCode;

    /**
     * 错误信息
     */
    private String errorMessage;

    /**
     * 错误详情
     */
    private String errorDetails;

    public ErrorResponse(String number, String message, String description) {
        this.errorCode = number;
        this.errorMessage = message;
        this.errorDetails = description;
    }

    public String getErrorCode() {
        return errorCode;
    }

    public String getErrorMessage() {
        return errorMessage;
    }

    public String getErrorDetails() {
        return errorDetails;
    }

    public void setErrorCode(String errorCode) {
        this.errorCode = errorCode;
    }

    public void setErrorMessage(String errorMessage) {
        this.errorMessage = errorMessage;
    }

    public void setErrorDetails(String errorDetails) {
        this.errorDetails = errorDetails;
    }
}

4.3.3.编写扫描配置文件类

package com.sys.my.start.exception;

import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;

/**
 * 扫描 exception-handler:
 *      enabled: true
 * 为true时,启用全局异常处理
 */
@Component
@ConfigurationProperties(prefix = "exception-handler")
public class ExceptionHandlerProperties {
    private boolean enabled;

    public boolean isEnabled() {
        return enabled;
    }

    public void setEnabled(boolean enabled) {
        this.enabled = enabled;
    }
}

4.3.4.编写自动配置类

package com.sys.my.start.exception;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import org.springframework.context.annotation.Import;

import java.lang.invoke.MethodHandles;

/**
 * 自动配置类
 * 通过@Import导入相关文件
 * EnableAspectJAutoProxy开启AOP代理自动配置
 * @author 13723
 * @version 1.0
 * 2024/2/16 19:16
 */
@Configuration
@EnableAspectJAutoProxy(
		exposeProxy = true
)
@Import({ExceptionHandlerProperties.class})
public class ErrorHandlerAutoProxy {
	private static final Logger logger = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
}

4.3.5.编写spring.factories

# 通过SpringBoot的自动注入功能,扫描spring.factories,实现自动注入。
org.springframework.boot.autoconfigure.EnableAutoConfiguration= com.sys.my.start.exception.ErrorHandlerAutoProxy

4.3.6.发布到本地gradle

5.测试

5.1.测试模块引入starter

注意 这里为了保证测试的service模块能够使用到 starter引入springboot依赖,也需要使用api进行调用

// sys_my_service 子项目中的 build.gradle
plugins {
    id 'java-library'
}
dependencies {
    // https://mvnrepository.com/artifact/com.alibaba.fastjson2/fastjson2
    /* json转换 */
    implementation 'com.alibaba.fastjson2:fastjson2:2.0.46'
    /* lombok */
    compileOnly 'org.projectlombok:lombok'
    annotationProcessor 'org.projectlombok:lombok'
    /* 日志类 */
    api 'ch.qos.logback:logback-classic:1.4.14'
    /* 引入自定义jar包 */
    api  group: 'org.sys_my_start', name: 'com_sys_my_start', version: '1.0-SNAPSHOT'
}
sourceSets.main.resources {
    srcDirs = ['src/main/java']
    include '**/*.xml'
}

5.2.编写测试代码

/**
 * @author 13723
 * @version 1.0
 * 2024/2/16 13:32
 */
@RestController
@RequestMapping("/test")
public class TestController {
	private static final Logger logger = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());

	@Resource
	private TestService testService;
	@RequestMapping("/hello")
	public String hello(){
		return testService.hello();
	}
}
/**
 * @author 13723
 * @version 1.0
 * 2024/2/16 13:33
 */

@Service
public class TestService {
	private static final Logger logger = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());

	public String hello(){
		throw new RuntimeException("测试统一返回异常!");
	}
}

5.3.测试结果

6.总结

6.1.好处

自定义 Starter 是在 Spring Boot 中实现代码模块化和功能封装的强大工具。它的优势和用途包括:

  • 模块化开发: 自定义 Starter 允许将应用程序的不同功能模块化,使得代码结构更清晰,易于维护和管理。
  • 功能封装: Starter 可以封装特定功能的代码和配置,使得其他开发人员可以轻松地集成和使用这些功能。
  • 提高开发效率: 使用自定义 Starter 可以加速新项目的开发过程,避免重复编写相似的代码,提高开发效率。
  • 标准化配置: Starter 可以定义标准化的配置方式,使得不同项目之间的配置更一致,降低了配置错误的可能性。

通过自定义 Starter,开发团队可以实现代码的复用和标准化,从而提高了代码的复用性和可维护性,降低了开发和维护成本。

6.2.结语

本文介绍了如何创建自定义的 Spring Boot Starter,并详细解释了其优势、用途以及如何提高代码复用性和可维护性。通过自定义 Starter,开发人员可以更轻松地构建模块化的应用程序,并在团队内部实现功能的共享和复用。

鼓励读者在实际项目中尝试创建自己的自定义 Starter,将通用的功能模块化,并通过开源社区与他人分享,促进技术的共享和交流。这将有助于提高团队的开发效率,加速项目的上线和迭代过程,推动软件开发行业的发展。

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

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

相关文章

51_蓝桥杯_led流水灯

一 原理图分析 二 三八译码器工作原理 三八译码器&#xff1a;3个输入控制8路互斥的低电平有效输出。 C B A 输出 0 0 0 Y0 0 0 1 Y1 0 1 0 Y2 0 1 1 Y3 1 0 0 Y4 1 0 1 Y5 1 1 0 Y6 1 1 1 Y7 三 锁存器工作原理 锁存器&#xff1a;当使…

租房招聘|在线租房和招聘平台|基于Springboot的在线租房和招聘平台设计与实现(源码+数据库+文档)

在线租房和招聘平台目录 目录 基于Springboot的在线租房和招聘平台设计与实现 一、前言 二、系统功能设计 三、系统实现 1、房屋管理 2、招聘管理 3、平台资讯管理 4、平台资讯类型管理 四、数据库设计 1、实体ER图 六、论文参考 七、最新计算机毕设选题推荐 八、源…

Oracle19c PDB的简介与创建

多租用户环境&#xff08;Multitenant Environment&#xff09;&#xff0c;允许一个数据库容器&#xff08;CDB&#xff09;承载多个可插拔数据库&#xff08;PDB&#xff09;。 首先&#xff0c;毋庸置疑的是pdb只能在cdb root下创建&#xff0c;每个cdb里面都有一个pdb$seed…

自定义配置IDEA中的Java注释模板

文章目录 1.背景2.模板配置2.1.配置类模板2.2.配置方法模板2.2.1. 创建自定义模板分组2.2.2. 配置缩写、模板、触发键2.2.3. 变量配置 3.总结 1.背景 由于在公司的编码规约中关于注释的规约&#xff0c;在IDEA中的默认模板无法适配&#xff0c;所以在每次新建接口、类、方法的…

信息安全研究方向

信息安全研究方向 目前信息安全的研究包含密码学、网络安全、信息系统安全、信息内容安全、信息对抗等方向。 网络空间是所有信息系统的集合,网络安全的核心是信息安全。网络空间安全学科是研究信息的获取、存储、传输、处理等领域中信息安全保障问题的一门学科。 信息安全理…

数据分析 — Pandas 数据加载、存储和清洗

目录 一、文件读取1、常见文件读取函数2、read_csv()3、read_table()4、read_excel()5、read_json()6、read_html()7、大文件读取 二、数据保存1、csv2、excel3、json4、html5、MySQL1、连接数据库2、MySQL 存储到本地3、本地存储到 MySQL 三、数据清洗1、处理缺失值1、判断数据…

【C++初阶】第三站:类和对象(中) -- 日期计算器

目录 前言 日期类的声明.h 日期类的实现.cpp 获取某年某月的天数 全缺省的构造函数 拷贝构造函数 打印函数 日期 天数 日期 天数 日期 - 天数 日期 - 天数 前置 后置 前置 -- 后置-- 日期类中比较运算符的重载 <运算符重载 运算符重载 ! 运算符重载 …

【教3妹学编程-算法题】N 叉树的前序遍历

2哥 : 叮铃铃&#xff0c;3妹&#xff0c;准备复工了啊&#xff0c;过年干嘛呢&#xff0c;是不是逛吃逛吃&#xff0c;有没有长胖呢。 3妹&#xff1a;切&#xff0c;不想上班&#xff0c;假期能不能重来一遍啊&#xff0c;虽然在家我妈张罗着要给我相亲呢。可是在家还是很好的…

压敏电阻:浪涌保护的理想解决方案?

有关电涌保护的新法规迫使工程师寻找解决方案&#xff0c;以最小的成本损失集成此类保护&#xff0c;特别是在成本敏感的消费产品中。在汽车领域&#xff0c;电涌保护也越来越重要&#xff0c;这要归功于即使是最基本的量产车中电子含量的快速增长&#xff0c;以及公认的电源电…

MySQL简单配置GTID

前期规划 IP地址 角色 系统版本 内核 软件包名称 192.168.2.3 Mysql主服务器 CentOS Stream 9 5.14.0- 381.el9.x86_64 mysql-8.2.0-linux-glibc2.17-x86_64.tar.xz 192.168.2.4 Mysql从服务器 CentOS Stream 9 5.14.0- 381.el9.x86_64 mysql-8.2.0-linux-glibc…

C++ //练习 7.27 给你自己的Screen类添加move、set和display函数,通过执行下面的代码检验你的类是否正确。

C Primer&#xff08;第5版&#xff09; 练习 7.27 练习 7.27 给你自己的Screen类添加move、set和display函数&#xff0c;通过执行下面的代码检验你的类是否正确。 Screen myScreen(5, 5, X); myScreen.move(4, 0).set(#).display(cout); cout<<"\n"; myScr…

计算机网络——18无连接传输UDP

无连接传输UDP UDP “尽力而为的”服务&#xff0c;报文段可能 丢失送到应用进程的报文段乱序 无连接 UDP发送端和接收端之间没有握手每个UDP报文段都被独立的处理 UDP被用于 流媒体DNSSNMP 在UDP上实现可靠传输 在应用层增加可靠性应用特定的差错格式 UDP&#xff1a;用户…

综合交易模型教程---qmt实盘链接,提供源代码

综合交易模型教程---qmt实盘链接&#xff0c;提供源代码 Original L1511732 数据分析与运用 2024-02-17 00:13 贵州 目前框架实盘全部完成了&#xff0c;后面写教程&#xff0c;每一个函数怎么样使用&#xff0c;怎么样开发自己的策略 模拟盘现在登录不了我直接实盘展示 后面…

阿里云轻量应用服务器怎么样?有哪些好处?

阿里云轻量应用服务器有哪些优势&#xff1f;轻量服务器具有价格优惠、使用门槛低快速上手、灵活变配、可视化运维等优势&#xff0c;阿里云百科aliyunbaike.com整理轻量应用服务器详细优势&#xff1a; 1、价格优惠 阿里云轻量应用服务器性价比高&#xff0c;价格优惠&#x…

ubuntu制作windows的u盘启动盘

概要&#xff1a; 本篇演示在ubuntu22.04中制作windows10的u盘启动盘 一、下载woeusb 1、下载woeusb 在浏览器中输入https://github.com/woeusb/woeusb/releases访问woeusb 点击红色矩形圈出来的部分&#xff0c;下载woeusb 2、安装wimtools wimtools是woeusb的一个必须的…

EasyRecovery软件免费版与付费版有哪些功能区别?

免费版的EasyRecovery软件在功能和恢复能力上确实存在一些限制。 首先&#xff0c;在数据恢复方面&#xff0c;免费版通常只能恢复最多1GB的数据。这意味着&#xff0c;如果你需要恢复的数据量超过1GB&#xff0c;你将需要升级到付费版才能完全恢复。 其次&#xff0c;免费版…

第4讲引入JWT前后端交互

引入JWT前后端交互 Json web token (JWT), 是为了在网络应用环境间传递声明而执行的一种基于JSON的开放标准&#xff08;(RFC 7519)&#xff1b; JWT就是一段字符串&#xff0c;用来进行用户身份认证的凭证&#xff0c;该字符串分成三段【头部、载荷、签证】 后端接口测试&…

c++ 可调用对象的绑定器和包装器

文章目录 可调用对象普通函数类的静态成员函数仿函数lambda函数类的非静态成员函数 最重要的可被转换为函数指针的类对象 包装器 function适配器bind可变函数和参数实现回调函数实现替代虚函数 可调用对象 在C中&#xff0c;可以像函数一样调用的有: 普通函数、类的静态成员函…

解决IDEA的Project无法正常显示的问题

一、问题描述 打开IDEA&#xff0c;结果发现项目结构显示有问题&#xff1a; 二、解决办法 File -> Project Structure… -> Project Settings (选Modules)&#xff0c;然后导入Module 结果&#xff1a; 补充&#xff1a; IDEA提示“The imported module settings a…

深度学习系列58:大模型训练和压缩

1. 大模型训练 1.1数据并行 1.2 模型并行 1.3 ZeRO 1.4 流水线并行 1.5 混合精度训练 1.6 offloading 把梯度放在cpu上保存和计算 1.7 overlapping 提前传输数据 1.8 checkpointing 中间线性层不保存&#xff0c;反向传播时再次重新计算 1.9 使用BMtrain 2. 大模型压…