定制你的【Spring Boot Starter】,加速开发效率
摘要: 本文将介绍如何创建一个自定义的 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.需求
-
统一的异常处理:对于常见的异常类型(如 404、500),提供统一的异常处理方式,并返回一致的错误响应。
-
统一的错误响应格式:定义一致的错误响应格式,包括错误代码、错误消息、错误详情等信息。
-
可定制化:允许开发人员根据实际情况定制异常处理和错误响应的方式,以满足不同的业务需求。
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语法了废弃了,所以我们这里需要使用apiid '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;@Autowiredpublic 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 {// 未启用全局异常处理 返回500return 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());@Resourceprivate 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,将通用的功能模块化,并通过开源社区与他人分享,促进技术的共享和交流。这将有助于提高团队的开发效率,加速项目的上线和迭代过程,推动软件开发行业的发展。
相关文章:
定制你的【Spring Boot Starter】,加速开发效率
摘要: 本文将介绍如何创建一个自定义的 Spring Boot Starter,让您可以封装常用功能和配置,并在多个 Spring Boot 项目中共享和重用。 1. 简介 Spring Boot Starter 是 Spring Boot 框架中的一种特殊的依赖项,它用于快速启动和配置…...
Vue源码系列讲解——生命周期篇【二】(new Vue)
目录 1. 前言 2. new Vue()都干了什么 3 . 合并属性 4. callHook函数如何触发钩子函数 5. 总结 1. 前言 上篇文章中介绍了Vue实例的生命周期大致分为4个阶段,那么首先我们先从第一个阶段——初始化阶段开始入手分析。从生命周期流程图中我们可以看到ÿ…...
JavaScript 设计模式之观察者模式
观察者模式 观察者模式又被称为发布-订阅模式,使用一个对象来收集订阅者,在发布时遍历所有订阅者,然后将信息传递给订阅者,可以这样来实现一个简单的模式 const Observable (function () {let __messages {}return {register:…...
数据结构D4作业
1.实现单向循环链表的功能 loop.c #include "loop.h" loop_p create_loop() { loop_p H(loop_p)malloc(sizeof(loop)); if(HNULL) { printf("创建失败\n"); return NULL; } H->len0; H->nextH; ret…...
springboot750人职匹配推荐系统
springboot750人职匹配推荐系统 获取源码——》公主号:计算机专业毕设大全...
【笔记】【开发方案】APN 配置参数 bitmask 数据转换(Android KaiOS)
一、参数说明 (一)APN配置结构对比 平台AndroidKaiOS文件类型xmljson结构每个<apn>标签是一条APN,包含完成的信息层级数组结构,使用JSON格式的数据。最外层是mcc,其次mnc,最后APN用数组形式配置&am…...
Redis篇之缓存雪崩、击穿、穿透详解
学习材料:https://xiaolincoding.com/redis/cluster/cache_problem.html 缓存雪崩 什么是缓存雪崩 在面对业务量较大的查询场景时,会把数据库中的数据缓存至redis中,避免大量的读写请求同时访问mysql客户端导致系统崩溃。这种情况下&#x…...
【深度学习笔记】3_2线性回归的从零实现
注:本文为《动手学深度学习》开源内容,仅为个人学习记录,无抄袭搬运意图 3.2 线性回归的从零开始实现 在了解了线性回归的背景知识之后,现在我们可以动手实现它了。尽管强大的深度学习框架可以减少大量重复性工作,但若…...
Apache Maven简介
Maven 简介 Apache Maven 是一个用于项目构建、依赖管理和项目信息管理的强大工具。它基于项目对象模型(Project Object Model,POM)进行构建,通过描述项目的结构和依赖关系来管理项目的构建过程。 以下是 Apache Maven 的一些关键原理和工作流程: 项目对象模型(POM)…...
#12解决request中getReader()和getInputStream()只能调用一次的问题
目录 1、背景 2、解决方案 2.1、自定义HttpServletRequestWrapper 2.2、JsonRequestHeaderParamsHelper 2.3、HttpServletRequestReplacedFilter 2.4、使用 1、背景 当前系统Content-Type为application/json,参数接收方式采用RequestBody和RequestParam&#…...
直接插入排序+希尔排序+冒泡排序+快速排序+选择排序+堆排序+归并排序+基于统计的排序
插入排序:直接插入排序、希尔排序 交换排序:冒泡排序、快速排序 选择排序:简单选择排序、堆排序 其他:归并排序、基于统计的排序 一、直接插入排序 #include<stdio.h> #include<stdlib.h> /* 直接插入排序&#…...
Java高级 / 架构师 场景方案 面试题(二)
1.双十一亿级用户日活统计如何用 Redis快速计算 在双十一这种亿级用户日活统计的场景中,使用Redis进行快速计算的关键在于利用Redis的数据结构和原子操作来高效地统计和计算数据。以下是一个基于Redis的日活统计方案: 选择合适的数据结构: …...
C/C++内存管理学习【new】
文章目录 一、C/C内存分布二、C语言中动态内存管理方式:malloc/calloc/realloc/free三、C内存管理方式3.1 new/delete操作内置类型3.2 new和delete操作自定义类型四、operator new与operator delete函数五、new和delete的实现原理5.1 内置类型 六、定位new表达式(pl…...
选择适合你的编程语言
引言 在当今瞬息万变的技术领域中,选择一门合适的编程语言对于个人职业发展和技术成长至关重要。每种语言都拥有独特的设计哲学、应用场景和市场需求,因此,在决定投入时间和精力去学习哪种编程语言时,我们需要综合分析多个因素&a…...
【力扣每日一题】力扣106从中序和后序遍历序列构造二叉树
题目来源 力扣106从中序和后序遍历序列构造二叉树 题目概述 给定两个整数数组 inorder 和 postorder ,其中 inorder 是二叉树的中序遍历, postorder 是同一棵树的后序遍历,请你构造并返回这颗 二叉树 。 思路分析 后序遍历序列的最末尾数…...
logback日志回滚原理
日志输出主要依赖RollingFileAppender、TimeBasedRollingPolicy、SizeAndTimeBasedFNATP。 RollingFileAppender 主要用于生成日志文件,格式化内容再输出到日志文件TimeBasedRollingPolicy 设置回滚策略,如果发现日志输出的时间超过单位时间,…...
[C#]winform基于opencvsharp结合pairlie算法实现低光图像增强黑暗图片变亮变清晰
【低光图像增强介绍】 在图像处理领域,低光图像增强是一个具有挑战性的任务。由于光线不足,这些图像往往呈现出低对比度、高噪声和细节丢失等问题,严重影响了图像的视觉效果和后续分析的准确性。因此,开发有效的低光图像增强方法…...
React18源码: reconcliler启动过程
Reconcliler启动过程 Reconcliler启动过程实际就是React的启动过程位于react-dom包,衔接reconciler运作流程中的输入步骤.在调用入口函数之前,reactElement(<App/>) 和 DOM对象 div#root 之间没有关联,用图片表示如下: 在启…...
【RN】为项目使用React Navigation中的navigator
简言 移动应用基本不会只由一个页面组成。管理多个页面的呈现、跳转的组件就是我们通常所说的导航器(navigator)。 React Navigation 提供了简单易用的跨平台导航方案,在 iOS 和 Android 上都可以进行翻页式、tab 选项卡式和抽屉式的导航布局…...
CS50x 2024 - Lecture 8 - HTML, CSS, JavaScript
00:00:00 - Introduction 关于互联网是怎么工作的,如何在他的基础上构建软件 HTML和CSS是描述性语言 javascript一种编程语言,在浏览器上下文中很有用,使得界面更具交互性,也用于服务器 00:01:01 - Bingo Board 00:01:51 - T…...
SCAU期末笔记 - 数据分析与数据挖掘题库解析
这门怎么题库答案不全啊日 来简单学一下子来 一、选择题(可多选) 将原始数据进行集成、变换、维度规约、数值规约是在以下哪个步骤的任务?(C) A. 频繁模式挖掘 B.分类和预测 C.数据预处理 D.数据流挖掘 A. 频繁模式挖掘:专注于发现数据中…...
Unit 1 深度强化学习简介
Deep RL Course ——Unit 1 Introduction 从理论和实践层面深入学习深度强化学习。学会使用知名的深度强化学习库,例如 Stable Baselines3、RL Baselines3 Zoo、Sample Factory 和 CleanRL。在独特的环境中训练智能体,比如 SnowballFight、Huggy the Do…...
Caliper 配置文件解析:config.yaml
Caliper 是一个区块链性能基准测试工具,用于评估不同区块链平台的性能。下面我将详细解释你提供的 fisco-bcos.json 文件结构,并说明它与 config.yaml 文件的关系。 fisco-bcos.json 文件解析 这个文件是针对 FISCO-BCOS 区块链网络的 Caliper 配置文件,主要包含以下几个部…...
Mac下Android Studio扫描根目录卡死问题记录
环境信息 操作系统: macOS 15.5 (Apple M2芯片)Android Studio版本: Meerkat Feature Drop | 2024.3.2 Patch 1 (Build #AI-243.26053.27.2432.13536105, 2025年5月22日构建) 问题现象 在项目开发过程中,提示一个依赖外部头文件的cpp源文件需要同步,点…...
技术栈RabbitMq的介绍和使用
目录 1. 什么是消息队列?2. 消息队列的优点3. RabbitMQ 消息队列概述4. RabbitMQ 安装5. Exchange 四种类型5.1 direct 精准匹配5.2 fanout 广播5.3 topic 正则匹配 6. RabbitMQ 队列模式6.1 简单队列模式6.2 工作队列模式6.3 发布/订阅模式6.4 路由模式6.5 主题模式…...
C++ 设计模式 《小明的奶茶加料风波》
👨🎓 模式名称:装饰器模式(Decorator Pattern) 👦 小明最近上线了校园奶茶配送功能,业务火爆,大家都在加料: 有的同学要加波霸 🟤,有的要加椰果…...
基于PHP的连锁酒店管理系统
有需要请加文章底部Q哦 可远程调试 基于PHP的连锁酒店管理系统 一 介绍 连锁酒店管理系统基于原生PHP开发,数据库mysql,前端bootstrap。系统角色分为用户和管理员。 技术栈 phpmysqlbootstrapphpstudyvscode 二 功能 用户 1 注册/登录/注销 2 个人中…...
Kafka主题运维全指南:从基础配置到故障处理
#作者:张桐瑞 文章目录 主题日常管理1. 修改主题分区。2. 修改主题级别参数。3. 变更副本数。4. 修改主题限速。5.主题分区迁移。6. 常见主题错误处理常见错误1:主题删除失败。常见错误2:__consumer_offsets占用太多的磁盘。 主题日常管理 …...
AI语音助手的Python实现
引言 语音助手(如小爱同学、Siri)通过语音识别、自然语言处理(NLP)和语音合成技术,为用户提供直观、高效的交互体验。随着人工智能的普及,Python开发者可以利用开源库和AI模型,快速构建自定义语音助手。本文由浅入深,详细介绍如何使用Python开发AI语音助手,涵盖基础功…...
协议转换利器,profinet转ethercat网关的两大派系,各有千秋
随着工业以太网的发展,其高效、便捷、协议开放、易于冗余等诸多优点,被越来越多的工业现场所采用。西门子SIMATIC S7-1200/1500系列PLC集成有Profinet接口,具有实时性、开放性,使用TCP/IP和IT标准,符合基于工业以太网的…...
