【Starter 】Spring Boot 3.x 自定义封装Starter 实战

2024-09-05 13:04

本文主要是介绍【Starter 】Spring Boot 3.x 自定义封装Starter 实战,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

【Starter 】Spring Boot 3.x 自定义封装Starter 实战

Starter 背景简介及作用

什么是 Starter

Starter 是 Spring Boot 中的一项创新发明,它的主要作用是降低项目开发中的复杂性,从而简化开发操作。通过使用 Starter,开发人员可以轻松地引入常用的库和配置,避免了繁琐的手动设置。

Starter 的理念:Starter 会将项目中所需的所有依赖一起打包,开发者不需要手动逐个引入依赖。这种设计减少了手动管理依赖的麻烦,确保了所需依赖版本的一致性。不同的 Starter 是为了解决不同的场景需求,比如 JPA 和 Redis 各有对应的 Starter,这种差异是由于 Starter 本质上是对逻辑层的封装和抽象。类似于 Docker 的概念,Starter 通过封装帮助开发者快速解决复杂问题。

例如,spring-boot-starter-data-jpa 就会自动配置与 JPA 相关的依赖和配置,而开发者只需将其引入即可使用 JPA 功能,而不必手动处理配置。

自定义 Starter 的背景

虽然在开发中我们经常使用官方的 Starter,例如数据库、缓存、消息队列等中间件的 Starter,但在实际开发中仍然会遇到一些情况:

  • 某些中间件没有官方 Starter 支持,开发者需要自行引入相关依赖并手动配置。
  • Spring Boot 版本更新后,部分官方 Starter 未能及时更新,导致无法兼容新版本。

在企业中,技术负责人或架构师通常会根据项目的实际需求,封装属于自己团队的自定义 Starter。这种自定义 Starter 通过统一的规范与配置,极大地简化了项目的开发流程,提升了开发效率。例如,封装数据库访问、认证授权、消息服务等,所有项目组成员都可以统一使用,提高了代码的规范性和一致性。

自定义 Starter 封装规范

  • 官方的 Starter 包命名规范为:spring-boot-starter-xxx,如 spring-boot-starter-webspring-boot-starter-jdbc

  • 自定义 Starter 的命名规范建议为:xxx-spring-boot-starter,如 mycompany-spring-boot-starter-email,这种命名方式便于团队识别自定义的 Starter,同时遵循 Spring 的命名风格。

自定义 Starter 通常包含以下内容:

  1. 自动配置类@Configuration):定义好依赖的自动配置逻辑。
  2. 配置属性类@ConfigurationProperties):支持使用外部化配置参数来简化使用。
  3. 必要的依赖管理:将常用的第三方库一并引入,避免手动添加依赖。

通过自定义 Starter,企业能够封装复杂的业务逻辑和配置,减少重复劳动,并确保项目开发中的一致性和可维护性。

spring-boot-starter
spring-boot-starter-data-jpa
spring-boot-starter-data-redis
spring-boot-starter-data-mongodb
spring-boot-starter-jdbc
mybatis-spring-boot-starter
mybatis-plus-boot-starter

新版Spring Boot3.X和旧版Spring Boot2.7之前自定义Starter区别

SpringBoot 2.7 之前

META-INF/spring.factories 文件里添加org.springframework.boot.autoconfigure.EnableAutoConfiguration=XXAutoConfiguration

Spring Boot2.7 推出新的自动配置

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

文件里添加配置类名称,每行包含一个配置类全限定名;

兼容META-INF/spring.factories方式;

Spring Boot3.x 移除spring.factories;

移除META-INF/spring.factories方式;

只支持META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports 增加自动配置。

自定义starter的步骤

  • 创建项目 xx-spring-boot-starter
  • 添加依赖
 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-autoconfigure</artifactId><version>3.0.2</version>
</dependency>
  • 创建配置类
  • 创建XXAutoConfiguration类
  • 增加Condition条件注解
  • 配置AutoConfiguration.imports自动配置类

自定义 Starter 案例实战

需求背景

目前公司所有的短信发送功能都已集成到消息中心。为了简化各个平台的开发流程,计划自定义封装一个 codingce-sms-spring-boot-starter,供各个平台统一使用。

这个 codingce-sms-spring-boot-starter 需要能够对接多家第三方短信平台,包括阿里云、腾讯云、亚马逊云等。开发者可以通过配置灵活选择短信服务提供商,默认情况下使用腾讯云作为短信服务商。如果 Spring 容器中不存在相应的 bean,则自动创建;如果已经存在,则不再创建。

创建SpringBoot3.x项目

codingce-sms-spring-boot-starter,添加autoconfigure依赖

<dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-autoconfigure</artifactId><version>3.0.2</version></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></dependency></dependencies>

SmsAutoConfiguration

package cn.com.codingce.sms.config;import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;/*** @author Will*/
@AutoConfiguration
@ConditionalOnClass({SmsTemplate.class})
@EnableConfigurationProperties(value = SmsProperties.class)
public class SmsAutoConfiguration {@Bean@ConditionalOnMissingBeanpublic SmsTemplate smsTemplate() {return new SmsTemplate();}}

SmsProperties

package cn.com.codingce.sms.config;import cn.com.codingce.sms.constant.SmsTypeEnum;
import org.springframework.boot.context.properties.ConfigurationProperties;/*** @author Will*/
@ConfigurationProperties(prefix = "sms.server.achieve")
public class SmsProperties {/*** 发送短信类型*/private String type;public String getType() {if (type == null || "".equals(type)) {type = SmsTypeEnum.TX_CLOUD.name();}return type;}public void setType(String type) {this.type = type;}}

SmsTemplate

package cn.com.codingce.sms.config;import cn.com.codingce.sms.factory.SmsHandleFactory;
import cn.com.codingce.sms.service.SmsService;
import jakarta.annotation.Resource;
import org.springframework.beans.factory.annotation.Autowired;/*** @author Will*/
public class SmsTemplate {@Autowiredprivate SmsProperties smsProperties;@ResourceSmsHandleFactory smsHandleFactory;public String send(String fromPhone, String toPhone, String content) {//获取云厂商的业务实现类String type = smsProperties.getType();SmsService smsService = smsHandleFactory.createSmsService(type);return smsService.send(fromPhone, toPhone, content);}}

SmsTypeEnum

package cn.com.codingce.sms.constant;/*** @author Will*/
public enum SmsTypeEnum {//阿里云ALI_CLOUD("ali"),//腾讯云TX_CLOUD("tx"),//亚马逊云YMX_CLOUD("ymx");private String type;SmsTypeEnum(String ymx) {}}

SmsHandleFactory

package cn.com.codingce.sms.factory;import cn.com.codingce.sms.service.SmsService;
import org.springframework.stereotype.Component;import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;/*** @author Will*/
@Component
public class SmsHandleFactory {public Map<String, SmsService> handlerMap = new ConcurrentHashMap<>();/*** 创建处理类对象** @param code code* @return ISmsService*/public SmsService createSmsService(String code) {return handlerMap.get(code);}}

SmsService

package cn.com.codingce.sms.service;/*** @author Will*/
public interface SmsService {/*** 发送短信** @param fromPhone fromPhone* @param toPhone   toPhone* @param content   content* @return String*/String send(String fromPhone, String toPhone, String content);}

AliCloudSmsServiceImpl

package cn.com.codingce.sms.service.impl;import cn.com.codingce.sms.factory.SmsHandleFactory;
import cn.com.codingce.sms.service.SmsService;
import jakarta.annotation.PostConstruct;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Service;/*** 阿里云SMS实现** @author Will*/
@Service("ali")
public class AliCloudSmsServiceImpl implements SmsService {@ResourceSmsHandleFactory smsHandleFactory;static final String ALI = "ali";@PostConstructpublic void init() {smsHandleFactory.handlerMap.put(ALI, this);}@Overridepublic String send(String fromPhone, String toPhone, String content) {System.out.println("------------------当前SMS厂商为阿里云------------------");System.out.println("----" + fromPhone + " 向 " + toPhone + " 发送了一条短信。" + "----");System.out.println("短信内容为:" + content);System.out.println("----------------------------------------------------");return "success";}
}

TxCloudSmsServiceImpl

package cn.com.codingce.sms.service.impl;import cn.com.codingce.sms.factory.SmsHandleFactory;
import cn.com.codingce.sms.service.SmsService;
import jakarta.annotation.PostConstruct;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Service;/*** 腾讯云SMS实现** @author ma*/
@Service("tx")
public class TxCloudSmsServiceImpl implements SmsService {@ResourceSmsHandleFactory smsHandleFactory;static final String ALI = "tx";@PostConstructpublic void init() {smsHandleFactory.handlerMap.put(ALI, this);}@Overridepublic String send(String fromPhone, String toPhone, String content) {System.out.println("------------------当前SMS厂商为腾讯云------------------");System.out.println("----" + fromPhone + " 向 " + toPhone + " 发送了一条短信。" + "----");System.out.println("短信内容为:" + content);System.out.println("----------------------------------------------------");return "success";}}

YmxCloudSmsServiceImpl

package cn.com.codingce.sms.service.impl;import cn.com.codingce.sms.factory.SmsHandleFactory;
import cn.com.codingce.sms.service.SmsService;
import jakarta.annotation.PostConstruct;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Service;/*** 亚马逊云SMS实现** @author Will*/
@Service("ymx")
public class YmxCloudSmsServiceImpl implements SmsService {@ResourceSmsHandleFactory smsHandleFactory;static final String ALI = "ymx";@PostConstructpublic void init() {smsHandleFactory.handlerMap.put(ALI, this);}@Overridepublic String send(String fromPhone, String toPhone, String content) {System.out.println("------------------当前SMS厂商为亚马逊云------------------");System.out.println("----" + fromPhone + " 向 " + toPhone + " 发送了一条短信。" + "----");System.out.println("短信内容为:" + content);System.out.println("----------------------------------------------------");return "success";}}

mvn clean install 打入到本地仓库

使用方

新建项目

注意一定要是spring boot3.x版本以上的。

<dependency><groupId>cn.com.codingce</groupId><artifactId>codingce-sms-spring-boot-starter</artifactId><version>0.0.1-SNAPSHOT</version>
</dependency>

创建测试代码

package com.example.usersdkdemo.controller;import cn.com.codingce.sms.config.SmsTemplate;
import jakarta.annotation.Resource;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;/*** @author Will*/
@RestController
@RequestMapping("/codingce")
public class SmsController {@Resourceprivate SmsTemplate smsTemplate;@RequestMapping("/sms")public String sms() {String fromPhone = "19922579993";String toPhone = "17694917213";String content = "志国,志国,今晚英雄联盟 十点 五缺一,收到请回复,over!";return smsTemplate.send(fromPhone, toPhone, content);}}

当配置文件不进行配置时,默认走的是腾讯云的厂商

http://localhost:8080/codingce/sms

当配置好云厂商时,就会走配置的云厂商

http://localhost:8080/codingce/sms
sms:server:achieve:type: ali

这篇关于【Starter 】Spring Boot 3.x 自定义封装Starter 实战的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1139037

相关文章

Java实现字节字符转bcd编码

《Java实现字节字符转bcd编码》BCD是一种将十进制数字编码为二进制的表示方式,常用于数字显示和存储,本文将介绍如何在Java中实现字节字符转BCD码的过程,需要的小伙伴可以了解下... 目录前言BCD码是什么Java实现字节转bcd编码方法补充总结前言BCD码(Binary-Coded Decima

SpringBoot全局域名替换的实现

《SpringBoot全局域名替换的实现》本文主要介绍了SpringBoot全局域名替换的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一... 目录 项目结构⚙️ 配置文件application.yml️ 配置类AppProperties.Ja

Java使用Javassist动态生成HelloWorld类

《Java使用Javassist动态生成HelloWorld类》Javassist是一个非常强大的字节码操作和定义库,它允许开发者在运行时创建新的类或者修改现有的类,本文将简单介绍如何使用Javass... 目录1. Javassist简介2. 环境准备3. 动态生成HelloWorld类3.1 创建CtC

JavaScript中的高级调试方法全攻略指南

《JavaScript中的高级调试方法全攻略指南》什么是高级JavaScript调试技巧,它比console.log有何优势,如何使用断点调试定位问题,通过本文,我们将深入解答这些问题,带您从理论到实... 目录观点与案例结合观点1观点2观点3观点4观点5高级调试技巧详解实战案例断点调试:定位变量错误性能分

使用Python批量将.ncm格式的音频文件转换为.mp3格式的实战详解

《使用Python批量将.ncm格式的音频文件转换为.mp3格式的实战详解》本文详细介绍了如何使用Python通过ncmdump工具批量将.ncm音频转换为.mp3的步骤,包括安装、配置ffmpeg环... 目录1. 前言2. 安装 ncmdump3. 实现 .ncm 转 .mp34. 执行过程5. 执行结

Java实现将HTML文件与字符串转换为图片

《Java实现将HTML文件与字符串转换为图片》在Java开发中,我们经常会遇到将HTML内容转换为图片的需求,本文小编就来和大家详细讲讲如何使用FreeSpire.DocforJava库来实现这一功... 目录前言核心实现:html 转图片完整代码场景 1:转换本地 HTML 文件为图片场景 2:转换 H

Java使用jar命令配置服务器端口的完整指南

《Java使用jar命令配置服务器端口的完整指南》本文将详细介绍如何使用java-jar命令启动应用,并重点讲解如何配置服务器端口,同时提供一个实用的Web工具来简化这一过程,希望对大家有所帮助... 目录1. Java Jar文件简介1.1 什么是Jar文件1.2 创建可执行Jar文件2. 使用java

SpringBoot实现不同接口指定上传文件大小的具体步骤

《SpringBoot实现不同接口指定上传文件大小的具体步骤》:本文主要介绍在SpringBoot中通过自定义注解、AOP拦截和配置文件实现不同接口上传文件大小限制的方法,强调需设置全局阈值远大于... 目录一  springboot实现不同接口指定文件大小1.1 思路说明1.2 工程启动说明二 具体实施2

Java实现在Word文档中添加文本水印和图片水印的操作指南

《Java实现在Word文档中添加文本水印和图片水印的操作指南》在当今数字时代,文档的自动化处理与安全防护变得尤为重要,无论是为了保护版权、推广品牌,还是为了在文档中加入特定的标识,为Word文档添加... 目录引言Spire.Doc for Java:高效Word文档处理的利器代码实战:使用Java为Wo

SpringBoot日志级别与日志分组详解

《SpringBoot日志级别与日志分组详解》文章介绍了日志级别(ALL至OFF)及其作用,说明SpringBoot默认日志级别为INFO,可通过application.properties调整全局或... 目录日志级别1、级别内容2、调整日志级别调整默认日志级别调整指定类的日志级别项目开发过程中,利用日志