我们知道SpringBoot Starter也就是启动器。是SpringBoot组件化的一大优点。基于这个思想,基于这个思想SpringBoot 才变得非常强大,官方给我们提供很多开箱即用的启动器。

Spring Boot Starter 是 Spring Boot 的一个重要特性,它有以下优点:

  1. 依赖管理:Starter 自动处理项目的依赖关系,使得开发者无需手动添加和管理每个依赖。

  2. 自动配置:Starter 提供了一种自动配置的方式,可以根据你的 classpath 和你定义的属性自动配置 Spring 应用。

  3. 简化开发:通过提供各种服务的 Starter(如数据库、安全、缓存等),极大地简化了开发过程。

  4. 减少样板代码:由于 Starter 的自动配置和依赖管理,开发者可以专注于业务逻辑,而不是配置和基础设施代码。

  5. 快速原型开发:使用 Starter 可以快速创建可运行的原型。

  6. 易于理解和使用:Spring Boot Starter 的设计目标之一就是让非专业的开发者也能快速上手。

  7. 社区支持:除了官方提供的 Starter,还有大量的社区提供的 Starter,可以满足各种特定需求。

我现在手把手教大家如何封装自己的starter 做自己的springboot组件,当然你也可以发布自己的starter 到maven中央仓库供大家使用

剖析SpringBoot自带Starter

我们以WebMvcAutoConfiguration这个自动加载为例

自动配置类要能加载,有一个要求,源码分析结果是,需要在\META-INF\spring.factories中做如下配置

# Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration,\
org.springframework.boot.autoconfigure.aop.AopAutoConfiguration,\

这样SpringBoot在启动完成时候,会找到我们引入,的starter 找到\META-INF\spring.factories 属性文件,找到需要自动加载配置的类路径,然后帮我们自动注入到Spring IOC 容器,我们在项目中就可以直接使用了。

这里实现自动加载还要依赖一些注解如:

@Configuration // 指定这个类是个配置类
@ConditionalOnXXX // 在指定条件成立的情况下自动配置类生效
@AutoConfigureOrder //配置类顺序
@AutoConfigureAfter // 在哪个配置类之后
@Bean //给容器中添加组件 @ConfigurationProperties //结合相关的XXXProperties类 来绑定相关的配置
@EnableConfigurationProperties // 让XXXProperties加入到容器中,别人就可以自动装配

自定义自己的starter

剖析了SpringBoot 官方的starter 我们自定义自己的starter,(我们仿照着写)

命名规范

配置提示

如果自定义属性文件中,需要IDEA智能提示需要引入

       <dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>

定义starter

这里我以自己封装总结我工作以来总结项目封装的一个SpringBoot starter为例

 <dependency>
<groupId>cn.soboys</groupId>
<artifactId>rest-api-spring-boot-starter</artifactId>
<version>1.2.0</version>
</dependency>

就是我自己封装的start。已经发布中央仓库。

目前更新版本1.3.0 功能如下

  1. 支持一键配置自定义RestFull API 统一格式返回
  2. 支持RestFull API 错误国际化
  3. 支持全局异常处理,全局参数验证处理
  4. 业务错误断言工具封装,遵循错误优先返回原则
  5. redis工作封装。支持所有key操作工具
  6. RestTemplate 封装 POST,GET 请求工具
  7. 日志集成。自定义日志路径,按照日志等级分类,支持压缩和文件大小分割。按时间显示
  8. 工具库集成 集成了lombok,hutool,commons-lang3,guava。不需要自己单个引入
  9. 集成mybatisPlus一键代码生成

rest-api-spring-boot-starter

仓库地址

github

  1. 自定义配置属性文件
rest-api:
enabled: false
logging:
path: ./logs
i18n:
# 若前端无header传参则返回中文信息
i18n-header: Lang
default-lang: cn
message:
# admin
internal_server_error:
en: Internal Server Error
cn: 系统错误
not_found:
en: Not Found
cn: 请求资源不存在
  1. 定义属性配置类
package cn.soboys.restapispringbootstarter.i18n;

import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Configuration; import java.util.Map;
import java.util.Optional; /**
* @author 公众号 程序员三时
* @version 1.0
* @date 2023/6/26 11:55
* @webSite https://github.com/coder-amiao
*/
//@PropertySource(value = "classpath:i18n.yaml", factory = YamlPropertySourceFactory.class)
@Configuration
@ConfigurationProperties(prefix = "rest-api.i18n")
@Data
public class I18NMessage {
/**
* message-key:<lang:message>
*/
private Map<String, Map<String, String>> message;
/**
* Default language setting (Default "cn").
*/
private String defaultLang = "cn"; private String i18nHeader = "Lang"; /**
* get i18n message
*
* @param key
* @param language
* @return
*/
public String message(I18NKey key, String language) {
return Optional.ofNullable(message.get(key.key()))
.map(map -> map.get(language == null ? defaultLang : language))
.orElse(key.key());
} /**
* get i18n message
*
* @param key
* @param language
* @return
*/
public String message(String key, String language) {
return Optional.ofNullable(message.get(key))
.map(map -> map.get(language == null ? defaultLang : language))
.orElse(key);
} }
  1. 定义BeanAutoConfiguration自动加载配置类
package cn.soboys.restapispringbootstarter.config;

import cn.soboys.restapispringbootstarter.ApplicationRunner;
import cn.soboys.restapispringbootstarter.ExceptionHandler;
import cn.soboys.restapispringbootstarter.ResultHandler;
import cn.soboys.restapispringbootstarter.aop.LimitAspect;
import cn.soboys.restapispringbootstarter.i18n.I18NMessage;
import cn.soboys.restapispringbootstarter.utils.RedisTempUtil;
import cn.soboys.restapispringbootstarter.utils.RestFulTemp;
import org.springframework.boot.autoconfigure.ImportAutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.client.ClientHttpRequestFactory;
import org.springframework.http.client.SimpleClientHttpRequestFactory;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.StringHttpMessageConverter;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.http.converter.support.AllEncompassingFormHttpMessageConverter;
import org.springframework.web.client.RestTemplate; import java.nio.charset.Charset;
import java.util.List; /**
* @author 公众号 程序员三时
* @version 1.0
* @date 2023/6/27 11:36
* @webSite https://github.com/coder-amiao
*/
@Configuration
@ConditionalOnProperty(name = "rest-api.enabled", havingValue = "true")
public class BeanAutoConfiguration { @Bean
public I18NMessage i18NMessage() {
return new I18NMessage();
} @Bean
public ResultHandler resultHandler() {
return new ResultHandler();
} @Bean
public ExceptionHandler exceptionHandler() {
return new ExceptionHandler();
} @Bean
public StartupApplicationListener startupApplicationListener() {
return new StartupApplicationListener();
} @Bean
public RestApiProperties restApiProperties() {
return new RestApiProperties();
} @Bean
public RestApiProperties.LoggingProperties loggingProperties(RestApiProperties restApiProperties) {
return restApiProperties.new LoggingProperties();
} @Bean
public ApplicationRunner applicationRunner() {
return new ApplicationRunner();
} /**
* restTemplate 自动注入
*/
@Configuration
@ConditionalOnProperty(name = "rest-api.enabled", havingValue = "true")
class RestTemplateConfig {
/**
* 第三方请求要求的默认编码
*/
private final Charset thirdRequest = Charset.forName("utf-8"); @Bean
public RestTemplate restTemplate(ClientHttpRequestFactory factory) {
RestTemplate restTemplate = new RestTemplate(factory);
// 处理请求中文乱码问题
List<HttpMessageConverter<?>> messageConverters = restTemplate.getMessageConverters();
for (HttpMessageConverter<?> messageConverter : messageConverters) {
if (messageConverter instanceof StringHttpMessageConverter) {
((StringHttpMessageConverter) messageConverter).setDefaultCharset(thirdRequest);
}
if (messageConverter instanceof MappingJackson2HttpMessageConverter) {
((MappingJackson2HttpMessageConverter) messageConverter).setDefaultCharset(thirdRequest);
}
if (messageConverter instanceof AllEncompassingFormHttpMessageConverter) {
((AllEncompassingFormHttpMessageConverter) messageConverter).setCharset(thirdRequest);
}
}
return restTemplate;
} @Bean
public ClientHttpRequestFactory simpleClientHttpRequestFactory() {
SimpleClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory();
factory.setConnectTimeout(15000);
factory.setReadTimeout(5000);
return factory;
} @Bean
public RestFulTemp restFulTemp() {
return new RestFulTemp();
} } }
  1. 自动装配

    在项目

spring.factories 配置自己加载配置类

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
cn.soboys.restapispringbootstarter.config.BeanAutoConfiguration,\
cn.soboys.restapispringbootstarter.config.BeanAutoConfiguration.RestTemplateConfig,\
cn.soboys.restapispringbootstarter.utils.RedisTempUtil\

扩展思考,我们可以看到SpringBoot官方stater 很多启用都类似@Enablexxx注解

这个怎么实现。我的rest-api-spring-boot-starter 1.3.0已经实现不需要在application.properties配置一行 直接在启动类或者配置类使用EnableRestFullApi就可以使用全部功能

完善文档使用可以看我

SpringBoot定义优雅全局统一Restful API 响应框架完结撒花篇封装starter组件

这篇文章

到此自己定义starter就写完了 接下来就是打包,发布到maven中央仓库

我会在 下一篇文章继续分享

留下你的思考,关注公众 程序员三时

持续输出优质内容 希望给你带来一点启发和帮助

手把手教你自定义自己SpringBoot Starter组件源码剖析的更多相关文章

  1. Rest_Framework之认证、权限、频率组件源码剖析

    一:使用RestFramwork,定义一个视图 from rest_framework.viewsets import ModelViewSet class BookView(ModelViewSet ...

  2. forms组件源码剖析

    一:forms组件源码剖析 1.forms组件源码切入点: 1.0 form_obj.is_valid() 2.0 def is_valid(self): """ Ret ...

  3. Element 2 组件源码剖析之布局容器

    0x00 简介 前文分析过组件的 布局栅格化(Grid Layout) ,通过基础的 24 分栏,迅速简便地创建布局. 本文将介绍用于布局的容器组件,使用 Flexbox 功能将其所控制区域设定为特定 ...

  4. 手把手教你搭建自己的Angular组件库 - DevUI

    摘要:DevUI 是一款面向企业中后台产品的开源前端解决方案,它倡导沉浸.灵活.至简的设计价值观,提倡设计者为真实的需求服务,为多数人的设计,拒绝哗众取宠.取悦眼球的设计.如果你正在开发 ToB 的工 ...

  5. Springboot自动装配源码及启动原理理解

    Springboot自动装配源码及启动原理理解 springboot版本:2.2.2 传统的Spring框架实现一个Web服务,需要导入各种依赖JAR包,然后编写对应的XML配置文件 等,相较而言,S ...

  6. springboot整合mybatis源码分析

    springboot整合mybatis源码分析 本文主要讲述mybatis在springboot中是如何被加载执行的,由于涉及的内容会比较多,所以这次只会对调用关系及关键代码点进行讲解,为了避免文章太 ...

  7. SpringBoot源码学习1——SpringBoot自动装配源码解析+Spring如何处理配置类的

    系列文章目录和关于我 一丶什么是SpringBoot自动装配 SpringBoot通过SPI的机制,在我们程序员引入一些starter之后,扫描外部引用 jar 包中的META-INF/spring. ...

  8. .NET开发邮件发送功能的全面教程(含邮件组件源码)

    今天,给大家分享的是如何在.NET平台中开发“邮件发送”功能.在网上搜的到的各种资料一般都介绍的比较简单,那今天我想比较细的整理介绍下: 1)         邮件基础理论知识 2)         ...

  9. Node 进阶:express 默认日志组件 morgan 从入门使用到源码剖析

    本文摘录自个人总结<Nodejs学习笔记>,更多章节及更新,请访问 github主页地址.欢迎加群交流,群号 197339705. 章节概览 morgan是express默认的日志中间件, ...

  10. 浅探element-ui2组件源码之upload

    最近不小心更新了element-ui的版本,已经到了2.1.0,以前修改的源码都失效了. 于是重新尝试下面的指令重新修改: git clone https://github.com/ElemeFE/e ...

随机推荐

  1. Moebius数据库多活集群

    背景 数据库是信息化的基石,支撑着整个业务系统,发挥着非常重要的作用,被喻为"IT的心脏".因此,让数据库安全.稳定.高效地运行已经成为IT管理者必须要面对的问题.数据库在底层架构 ...

  2. 基于Switching的 恒虚警率检测算法

    转发和使用请注明来源,以下为本人精心整理,还请尊重本人劳动成果与产权!由于本人现有知识和能力有限,如存在错误之处请指正!下面为正文内容: 1.S-CFAR检测算法(Switching,开关CFAR) ...

  3. Python代码相似度计算(基于AST和SW算法)

    代码相似度计算将基于AST和Smith-Waterman算法 AST (抽象语法树) AST即Abstract Syntax Trees,是源代码的抽象语法结构的树状表示,树上的每个节点都表示源代码中 ...

  4. HTML5中的document.visibilityState

    在 HTML5 中,文档对象(即 document 对象)具有一个 visibilityState 属性,该属性表示当前文档对象的可见性状态. visibilityState 可能的取值有以下三种: ...

  5. 2步打通ModelArts和Astro,实现AI应用快速落地

    摘要:本文以 ModelArts 的"找云宝"自动学习 AI 应用为例,结合低代码平台 Astro 轻应用快速实现一个"找云宝"小应用. 本文分享自华为云社区& ...

  6. 2020-10-02:golang如何写一个插件?

    福哥答案2020-10-02:#福大大架构师每日一题#简单回答:buildmode=plugin plugin.Openp.Lookup [中级回答:](https://www.zhihu.com/q ...

  7. uni-app 背景图片

    背景图片 uni-app 支持使用在 css 里设置背景图片,使用方式与普通 web 项目大体相同,但需要注意以下几点: 支持 base64 格式图片. 支持网络路径图片. 小程序不支持在 css 中 ...

  8. phpstudy-sqlilabs-less-14

    题目:POST - Double Injection - Single quotes- String - with twist 和上关一模一样 uname=1"or 1=1 #&pa ...

  9. 【重学C++】01| C++ 如何进行内存资源管理?

    文章首发 [重学C++]01| C++ 如何进行内存资源管理? 前言 大家好,我是只讲技术干货的会玩code,今天是[重学C++]的第一讲,我们来学习下C++的内存管理. 与java.golang等自 ...

  10. ENVI手动地理配准栅格图像的方法

      本文介绍在ENVI软件中,手动划定地面控制点从而实现栅格图像相互间地理配准的方法:其中,所用软件版本为ENVI Classic 5.3 (64-bit).   首先,在软件中同时打开两景需要进行地 ...