Spring Boot(二)— 自定义Spring Boot Starter

 在Spring Boot中,自定义Spring Boot Starter是一个常见且强大的功能,它允许开发者为特定的功能或库创建自己的自动配置,从而简化集成过程。

1 前置知识

Spring Boot的事件为应用的启动和关闭提供了详细的上下文信息,使得开发者能够根据不同阶段执行特定的逻辑。

Spring Boot的外部化配置是一种允许开发者将应用程序的配置信息从代码中分离出来,存储在外部文件或系统中的机制。支持包括Java属性文件、YAML文件、环境变量和命令行参数等多种外部配置源。

1.1 事件与监听器

ApplicationStartingEvent

程序刚启动,但没进行任何实际工作,除了监听器和初始化器的注册。

ApplicationEnvironmentPreparedEvent

应用程序的环境(例如配置属性、命令行参数等)已准备好,但上下文还没创建。

ApplicationPreparedEvent

属性之前,bean定义加载之后。(刷新指上下文的初始化过程,包括加载bean定义等)

ContextRefreshedEvent

刷新之后,ApplicationStartedEvent之前。

WebServerInitializedEvent

当基于Servlet的Web服务器(如tomcat)初始化完成后。(ApplicationStartedEvent之前

ApplicationStartedEvent

刷新之后,任何启动任务或命令行指令被调用之前。

ApplicationReadyEvent

任何应用程序和命令行运行器调用之后执行。

ApplicationFailedEvent

启动时发生异常。

表 Spring Boot 定义的事件

上面大多数事件都是在bean之前创建的,因此如果将监听器设置为bean,可能没法正常的监听,可以通过application.addListeners方法来添加监听器。

1.2 外部化配置

属性值可以通过多种方式注入到应用程序中,常见的方式有:1)使用@Value注解将属性值直接注入到Bean中。2)使用@ConfigurationProperties可以将配置属性绑定到结构化对象上。

属性值类型可以是数组、Map、Java对象等复杂的类型。还可以对属性值进行校验,需要添加依赖:

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
@ConfigurationProperties("student")
@Data
@Validated
public class Student {@NotBlank(message = "姓名不能为空")private String name;private Integer age;private List<Address> addressList;private List<String> role;private Map<String,Object> map;@DurationUnit(ChronoUnit.HOURS)private Duration duration1;private Duration duration2;private Period period1;private Period period2;private Date date;private String username;@Dataprivate static class Address {private String province;private String city;}
}
student:name: 黄先生age: 27role:- 爸爸- 丈夫- 员工map:info: hellousername: hmfaddressList:- province: 广东省city: 深圳市duration1: 900duration2: 15mperiod1: p3Dperiod2: p20Mdate: 2023/03/02 12:00username: hmf

2 自动配置

Spring Boot的自动配置是其核心特性之一,大大简化了Spring应用的初始搭建以及开发过程。基于“约定优于配置”的思想,通过默认配置来减少开发者需要手动进行的配置工作。

2.1 Bean 创建的条件约束

在自动配置过程中,可以使用一个或多个约束来控制bean的创建。

@ConditionalOnClass

指定类在运行时才会创建bean,(注意引用类在编译时可能存在,但是运行时不一定会存在。)

@ConditionalOnBean

当指定的bean存在时才会创建bean。注意指定的bean 一般为业务代码中的bean,而非依赖包中的bean。这个会受到bean创建顺序的影响,依赖包中的bean一般后于业务代码中的bean创建。

@ConditionalOnMissingBean

当这个bean不存在时才会被创建。

@ConditionalOnProperty

当对于的属性名存在特定值时bean才会被创建。

表 常用的Bean条件约束

2.2 自定义Starter

创建自定义的Starter,步骤如下:

  1. 创建一个Maven项目,该项目包含了核心功能。
  2. 创建一个自动配置Maven模块,命名规则一般为:项目名-spring-boot-autoconfigure。该模块的作用为:创建用于封装配置项的配置类,可以使用@ConfigurationProperties注解来指定配置项的前缀;创建自动配置类xxxGenerateAutoConfiguration,该类包含了根据条件自动创建Bean的逻辑;配置META- INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports 文件,该文件包含了自定配置类的全限定名,Spring Boot在启动时能自动加载。
  3. 创建一个空Maven模块,命名规则一般为:项目名-spring-boot-starter,该模块的作用为在pom文件中,引入核心模块、自动配置模块等需要的依赖。
  4. 打包部署。

2.2.1 自动配置模块中的pom.xml

在自动配置模块中,引入依赖时,一般会加上<optional>true</optional>,这意味着依赖不会被传递性地引入到使用这个库到其他项目中,有以下的好处:

  1. 避免依赖冲突。如果两个不同的Starter都依赖了不同版本的同一库,而且没有将其声明为可选依赖,那么构建过程中就可能会遇到依赖版本冲突的问题。
  2. 控制依赖范围。有时只想让Starter负责自动配置功能,而不希望它强制引入一些可能不需要的运行时依赖。通过将依赖声明为可选,允许最终用户根据自己的需求选择是否引入这些额外的依赖。
  3. 模块化和解耦。让项目不会因为引入Starter而间接引入不必要的依赖、减少最终构建的应用程序的大小,有助于优化应用程序的启动时间和性能。

2.2.2 自动配置模块中外部化配置的元数据描述

Spring Boot启动时,它会扫描类路径下的META-INF目录来查找spring-autoconfigure-metadata.properties 文件,该文件会被加载并用于生成关于自动配置类的元数据信息(属性的描述、类型、默认值、是否必须等信息)。

这个文件,一般可以通过添加spring-autoconfigure-metadata.properties依赖来自动生成,或者可以创建additional-spring-configuration-metadata.json 文件来自定义(这种方式不建议,还是推荐自动生成的形式)。

@Configuration
@EnableConfigurationProperties({CustomProperties.class,CustomSellerProperties.class})
public class CustomAutoConfiguration {private final CustomProperties customProperties;private final CustomSellerProperties customSellerProperties;public CustomAutoConfiguration(CustomProperties customProperties, CustomSellerProperties customSellerProperties) {this.customProperties = customProperties;this.customSellerProperties = customSellerProperties;}@Bean@ConditionalOnMissingBeanpublic Shop shop() {Shop shop = new Shop();shop.setManagerName(customProperties.getManagerName());shop.setName(customProperties.getName());shop.setCreateDate(customProperties.getCreateDate());shop.setGoodsList(customProperties.getGoodsList());shop.setStateOwned(customProperties.getStateOwned());return shop;}@Bean@ConditionalOnMissingBeanpublic Seller seller() {Seller seller = new Seller();seller.setName(customSellerProperties.getName());seller.setAge(customSellerProperties.getAge());return seller;}@Bean@ConditionalOnBean(name = "myBean")public DataSource1 dataSource1() {return new DataSource1();}@Bean@ConditionalOnProperty(name = "custom-seller.age", havingValue = "30")public DataSource2 dataSource2() {return new DataSource2();}
}@Configuration
@ConditionalOnClass(CustomDataSource.class)
public class CustomDataAutoConfiguration {public CustomDataAutoConfiguration() {System.out.println("CustomDataAutoConfiguration 被创建");}@Bean@ConditionalOnMissingBeanpublic CustomDataSource customDataSource() {return new CustomDataSource();}}@ConfigurationProperties(prefix = "custom")
public class CustomProperties {private String managerName;private String name;private Date createDate;private List<String> goodsList;private Boolean stateOwned;public String getManagerName() {return managerName;}public void setManagerName(String managerName) {this.managerName = managerName;}public String getName() {return name;}public void setName(String name) {this.name = name;}public Date getCreateDate() {return createDate;}public void setCreateDate(Date createDate) {this.createDate = createDate;}public List<String> getGoodsList() {return goodsList;}public void setGoodsList(List<String> goodsList) {this.goodsList = goodsList;}public Boolean getStateOwned() {return stateOwned;}public void setStateOwned(Boolean stateOwned) {this.stateOwned = stateOwned;}
}@ConfigurationProperties(prefix = "custom-seller")
public class CustomSellerProperties {/*** 商家姓名哦*/private String name = "黄sire";private Integer age = 18;public String getName() {return name;}public void setName(String name) {this.name = name;}public Integer getAge() {return age;}public void setAge(Integer age) {this.age = age;}
}

META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports

com.huangmingfu.autoconfigure.CustomAutoConfiguration
com.huangmingfu.autoconfigure.CustomDataAutoConfiguration

自动配置模块中的pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><parent><artifactId>spring-boot-starter-parent</artifactId><groupId>org.springframework.boot</groupId><version>3.1.2</version></parent><groupId>com.huangmingfu</groupId><artifactId>custom-spring-boot-autoconfigure</artifactId><version>1.0-SNAPSHOT</version><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-autoconfigure</artifactId><optional>true</optional></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-configuration-processor</artifactId><optional>true</optional></dependency><dependency><groupId>com.huangmingfu</groupId><artifactId>custom-core</artifactId><optional>true</optional><version>1.0-SNAPSHOT</version></dependency><dependency><groupId>com.huangmingfu</groupId><artifactId>custom-data</artifactId><version>1.0-SNAPSHOT</version><optional>true</optional></dependency></dependencies></project>

图 自动配置模块依赖中自动生成的元数据描述文件 

图 使用这个starter依赖的主服务的yml 配置文件

注意:对于配置属性的默认值,在元数据描述文件中定义的默认值并不会生效,可以在这个配置类中定义默认值(自动生成元数据描述文件时,默认值也取自这)。

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

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

相关文章

基于表面势的增强型p-GaN HEMT器件模型

来源&#xff1a;电子学报 22年 摘要 为了满足功率电路及系统设计对p-GaN HEMT&#xff08;High Electron Mobility Transistor&#xff09;器件模型的需求&#xff0c;本文建立了一套基于表面势计算方法的增强型p-GaN HEMT器件SPICE&#xff08;Simulation Program with Int…

Golang | Leetcode Golang题解之第27题移除元素

题目&#xff1a; 题解&#xff1a; func removeElement(nums []int, val int) int {left, right : 0, len(nums)for left < right {if nums[left] val {nums[left] nums[right-1]right--} else {left}}return left }

软件杯 深度学习卷积神经网络垃圾分类系统 - 深度学习 神经网络 图像识别 垃圾分类 算法 小程序

文章目录 0 简介1 背景意义2 数据集3 数据探索4 数据增广(数据集补充)5 垃圾图像分类5.1 迁移学习5.1.1 什么是迁移学习&#xff1f;5.1.2 为什么要迁移学习&#xff1f; 5.2 模型选择5.3 训练环境5.3.1 硬件配置5.3.2 软件配置 5.4 训练过程5.5 模型分类效果(PC端) 6 构建垃圾…

Eland上传bge-large-zh-v1.5向量化模型到ElasticSearch中

最近需要做一些向量检索&#xff0c;试试ES 一、准备 系统&#xff1a;MacOS 14.3.1 ElasticSearch&#xff1a;8.13.2 Kibana&#xff1a;8.13.2 本地单机环境&#xff0c;无集群&#xff0c;也不基于Docker BGE是一个常见的文本转向量的模型&#xff0c;在很多大模型RAG应…

数据仓库—维度建模—维度表设计

维度表 维度表(Dimension Table)是数据仓库中描述业务过程中各种维度信息的表,用于提供上下文和描述性信息,以丰富事实数据的分析 维度表是维度建模的灵魂所在,在维度表设计中碰到的问题(比如维度变化、维度层次、维度一致性、维度整合和拆分等)都会直接关系到维度建模…

docker和kubernetes(k8s)

docker是什么 运行程序需要环境&#xff0c;不同的环境&#xff0c;程序运行的结果就不一样。将程序打包给其它客户端使用时&#xff0c;客户端需要自己配置相应的环境。我们将程序和环境一起打包给其它客户端&#xff0c;客户端可直接运行程序。docker容器作为程序和操作系统…

防汛物资仓库管理系统|实现应急物资仓库三维可视化

系统概述 智慧应急物资仓库可视化系统&#xff08;智物资DW-S300&#xff09;采用了 B/S 架构的设计&#xff0c;通过浏览器即可快速登录操作。实现对库房内的应急物资从申购入库、出库、调拨、库内环境监测、维修保养、检测试验、处置报废等全周期、科学、规范的管理。系统以…

SpringBoot实用开发(十六)-- SpringBoot整合ActiveMQ

目录 1.导入springboot整合ActiveMQ的starter 2.进行yml文件的基础配置 3.使用JmsMessagingTemplate操作ActiveMQ

ssh爆破服务器的ip-疑似肉鸡

最近发现自己的ssh一直有一些人企图使用ssh暴力破解的方式进行密码破解.就查看了一下,真是网络安全太可怕了. 大家自己的服务器密码还是要设置好,管好,做好最基本的安全措施,不然最后只能沦为肉鸡. ssh登陆日志可以在/var/log下看到,ubuntu的话为auth.log,centos为secure文件 查…

45.HarmonyOS鸿蒙系统 App(ArkUI)创建列表(List)

列表是一种复杂的容器&#xff0c;当列表项达到一定数量&#xff0c;内容超过屏幕大小时&#xff0c;可以自动提供滚动功能。它适合用于呈现同类数据类型或数据类型集&#xff0c;例如图片和文本。在列表中显示数据集合是许多应用程序中的常见要求&#xff08;如通讯录、音乐列…

Android Activity 启动涉及几个进程

Zygote进程: Zygote进程在Android系统启动时被初始创建&#xff0c;并且初始化了虚拟机&#xff08;Dalvik或ART&#xff09;&#xff0c;预加载了Android系统的核心类库。所有的Android应用进程都是通过fork()从Zygote进程派生出来的&#xff0c;这允许应用快速启动&#xff0…

ChatGPT 和 Elasticsearch:使用 Elastic 数据创建自定义 GPT

作者&#xff1a;Sandra Gonzales ChatGPT Plus 订阅者现在有机会创建他们自己的定制版 ChatGPT&#xff0c;称为 GPT&#xff0c;这替代了之前博客文章中讨论的插件。基于本系列的第一部分的基础 —— 我们深入探讨了在 Elastic Cloud 中设置 Elasticsearch 数据和创建向量嵌…

软件无线电安全之HackRF One初探

HackRF介绍 HackRF是一款开源软件无线电&#xff08;SDR&#xff09;平台&#xff0c;由Great Scott Gadgets公司推出。它具有广泛的频率覆盖范围&#xff0c;从1 MHz到6 GHz&#xff0c;支持大部分常见的无线通信频段。采用软件定义无线电技术&#xff0c;HackRF提供了自定义…

C语言 函数——断言与防御式编程

目录 如何确定假设的真假&#xff1f; 断言 防御式编程&#xff08;Defensive programming&#xff09; 如何确定假设的真假&#xff1f; 程序中的假设 *某个特定点的某个表达式的值一定为真 *某个特定点的某个表达式的值一定位于某个区间等 问题&#xff1a;如何确定这些…

嵌入式单片机 TTL电平、232电平、485电平的区别和联系

一、简介 TTL、232和485是常见的串口通信标准&#xff0c;它们在电平和通信方式上有所不同&#xff0c; ①一般情况下TTL电平应用于单片机外设&#xff0c;属于MCU/CPU等片外外设&#xff1b; ②232/485电平应用于产品整体对外的接口&#xff0c;一般是片外TTL串口转232/485…

五、Jenkins、Docker、SpringClound持续集成

Jenkins、Docker、SpringClound持续集成 一、部署介绍1.部署图2.微服务项目结构3.项目启动顺序 二、微服务项目在Windows运行1.配置java、maven环境2.初始化数据库表/数据2.1 tensquare_gathering服务表2.2 tensquare_gathering服务表 3.启动微服务4.微服务接口测试4.1 获取用户…

黑马苍穹外卖--再来一单(stream流转换、赋值与收集映射)

1.首先明确一下业务规则: 业务规则&#xff1a; 再来一单就是将原订单中的商品重新加入到购物车中 2.产品页面原型和开发接口文档 3.业务层逻辑代码开发 3.1 查询方向 我们要明确的是: 再来一单就是将原订单中的商品重新加入到购物车中------直接把商品加入到购物车&#…

JMeter 连接数据库报错信息整理

目录 1.SSL连接问题 2.驱动版本报错 3.缺少 mysql-connector 驱动问题 4.时区问题 5.‘com.mysql.jdbc.Driver’被弃用问题 1.SSL连接问题 这是以前遇到的问题&#xff0c;mysql 版本是 5.7.42&#xff0c;jmeter 下载的mysql-connector 驱动是 8.0.11&#xff0c;连接数据…

深入理解SOAP协议:基于XML的分布式通信协议

文章目录 目录 文章目录 前言 一、SOAP协议的基本概念 1. 基本概念 2. SOAP消息结构 3. SOAP的通信模式 4. SOAP协议的扩展性 5. SOAP的传输协议独立性 6. SOAP的安全性 7. SOAP协议的应用场景 二、具体格式和应用 1. SOAP消息结构示例 2. SOAP的通信模式示例 请求…

容斥原理系列

容斥原理 假设班里有 10 个学生喜欢数学,15 个学生喜欢语文,21 个学生喜欢编程,班里至少喜欢一门学科的有多少个学生呢? 容斥原理:指把包含于某内容中的所有对象的数目先计算出来,然后再把计数时重复计算的数目排斥出去,使得计算的结果既无遗漏又无重复,这种计数的方法…