SpringBoot SPI 机制和实现自定义 starter

本文涉及的产品
对象存储 OSS,20GB 3个月
对象存储 OSS,恶意文件检测 1000次 1年
对象存储 OSS,内容安全 1000次 1年
简介: SpringBoot SPI 机制和实现自定义 starter

本文适合于实操~,主要讲述如何自定义start,实现一些自定义类的自动装配。

面向入门、有需求和想了解的小伙伴们,以免浪费小伙伴们的时间~

实现starter,其实就是SpringBoot的自动装配原理的一个实践,以前我也写过SpringBoot的自动装配原理的文章,文章链接

细心认真对待,没有什么是很难的

补充于2022年8月24日:重新审视自定义的 spring-boot-stater | 发现并优化问题

原因还是因为当时考虑的比较不周到,落地到实际应用还是存在些许缺陷的,问题是由评论区和耳朵,也是我心目中的大佬提出来的~非常感谢😊

大家如果要自己设计stater,非常建议先去参考参考,网上现已开源的第三方stater,非常有帮助


一、SpringBoot 中的SPI机制

什么是spi呢,全称是Service Provider Interface。简单翻译的话,就是服务提供者接口,是一种寻找服务实现的机制。

其实就是一个规范定义、或者说是实现的标准。


用生活中的例子说就是,你买了一台小米的手机。

但是你用的充电器并不一定非要是小米充电器,你可以拿其他厂商的充电器来进行充电,只要满足协议、端口等要求,那么就是可以充电的。这也是一种热拔插的思想,并不是固定死的。

换成代码来说也是一样的,我定义了一个接口,但是不想固定死具体的实现类,因为那样如果要更换实现类就要改动源代码,这往往是不合适的。

那么我也可以定义一个规范,在之后需要更换实现类或增加其他实现类时,遵守这个规范,我也可以动态的去发现这些实现类。

换在SpringBoot中,就是现在的SpringBoot这个平台定义了一些规范和标准,我现在想要让SpringBoot平台接纳我。

我该如何做呢?

很简单,按照它的标准和规范做事

SpringBoot在启动的时候,会扫描所有jar包resource/META-INF/spring.factories文件,依据类的全限定名,利用反射机制将Bean装载进容器中。

看完这段话,我想你应该对今天的文章应该有个大概的理解啦。

二、自定义 starter

说一说我的小实践:

在这个 starter 中,实现

  1. 发送短线的Template
  2. 对象存储的Template

的自动装配~

大致就是四步~

  1. 用于映射配置文件中的配置的类xxxxProperties
  2. 用于操作xxxx的接口和客户端等等,如本文中的OssTemplate
  3. 自动配置类xxxxAutoConfiguration ,并且向容器中注入xxxxTemplate
  4. 在spring.factories中将xxxxAutoConfiguration添加进EnableAutoConfiguration的vaule集合中

对象存储我用的是阿里云的oss,里面的配置都是可以用的, 短信的话,就是个模拟的啦~,勿怪啦

image.png

2.1、准备一个Maven项目

删除src目录,

然后再创建两个 Maven项目(我个人习惯,习惯创建空Maven项目,实际上创建SpringBoot项目也是一样)

image.png

最外层的pom.xml

 <parent>
     <groupId>org.springframework.boot</groupId>
     <artifactId>spring-boot-starter-parent</artifactId>
     <version>2.5.2</version>
     <relativePath/>
 </parent>
 ​
 <properties>
     <maven.compiler.source>8</maven.compiler.source>
     <maven.compiler.target>8</maven.compiler.target>
 </properties>
 ​
 ​
 <dependencies>
     <dependency>
         <groupId>org.projectlombok</groupId>
         <artifactId>lombok</artifactId>
     </dependency>
     <dependency>
         <groupId>org.springframework.boot</groupId>
         <artifactId>spring-boot-starter-web</artifactId>
     </dependency>
     <dependency>
         <groupId>org.springframework.boot</groupId>
         <artifactId>spring-boot-starter</artifactId>
     </dependency>
     <dependency>
         <groupId>org.springframework.boot</groupId>
         <artifactId>spring-boot-starter-test</artifactId>
     </dependency>
     <dependency>
         <groupId>org.springframework.boot</groupId>
         <artifactId>spring-boot-configuration-processor</artifactId>
         <optional>true</optional>
     </dependency>
 </dependencies>

2.2、准备Properties类

就是用来映射配置文件的~

 /**
  * @author Ning Zaichun
  */
 @Data
 @ConfigurationProperties(prefix = "nzc.oss")
 public class OssProperties {
 ​
     private String accessKey; 
     private String secret;
     private String bucketName;
     private String url;
     private String endpoint;
 }
 @Data
 @ConfigurationProperties(prefix = "nzc.sms")
 public class SmsProperties {
 ​
     private String name;
 }
 ​

2.3、准备要注入的类

就是我们最后要通过自动装配注入进SpringBoot操作的类

我这里分别是OssTemplate 和 SmsTemplate

 /**
  * @author Ning Zaichun
  */
 public class OssTemplate {
 ​
     private OssProperties ossProperties;
 ​
     public OssTemplate(OssProperties ossProperties) {
         this.ossProperties = ossProperties;
     }
 ​
     public String test() {
         System.out.println(ossProperties.getBucketName());
         return "test";
     }
 ​
     public String upload(String filename, InputStream is) {
         // yourEndpoint填写Bucket所在地域对应的Endpoint。以华东1(杭州)为例,Endpoint填写为https://oss-cn-hangzhou.aliyuncs.com。
         String endpoint = ossProperties.getEndpoint();
         // 阿里云主账号AccessKey拥有所有API的访问权限,风险很高。强烈建议您创建并使用RAM账号进行API访问或日常运维,请登录 https://ram.console.aliyun.com 创建RAM账号。
         String accessKeyId = ossProperties.getAccessKey();
         String accessKeySecret = ossProperties.getSecret();
 ​
         // 创建OSSClient实例。
         OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
 ​
         String storePath = new SimpleDateFormat("yyyy/MM/dd").format(new Date()) + "/" + UUID.randomUUID() + filename.substring(filename.lastIndexOf("."));
 ​
         System.out.println(storePath);
         // 依次填写Bucket名称(例如examplebucket)和Object完整路径(例如exampledir/exampleobject.txt)。Object完整路径中不能包含Bucket名称。
         ossClient.putObject(ossProperties.getBucketName(), storePath, is);
 ​
         String url = ossProperties.getUrl() + storePath;
 ​
         // 关闭OSSClient。
         ossClient.shutdown();
         return url + "#" + storePath;
     }
 ​
     public void remove(String fileUrl) {
         // yourEndpoint填写Bucket所在地域对应的Endpoint。以华东1(杭州)为例,Endpoint填写为https://oss-cn-hangzhou.aliyuncs.com。
         String endpoint = ossProperties.getEndpoint();
         // 阿里云账号AccessKey拥有所有API的访问权限,风险很高。强烈建议您创建并使用RAM用户进行API访问或日常运维,请登录RAM控制台创建RAM用户。
         String accessKeyId = ossProperties.getAccessKey();
         String accessKeySecret = ossProperties.getSecret();
         // 填写Bucket名称。
         String bucketName = ossProperties.getBucketName();
         // 填写文件完整路径。文件完整路径中不能包含Bucket名称。
         //2022/01/21/f0870eb3-4714-4fae-9fc3-35e72202f193.jpg
         String objectName = fileUrl;
 ​
         // 创建OSSClient实例。
         OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
 ​
         // 删除文件或目录。如果要删除目录,目录必须为空。
         ossClient.deleteObject(bucketName, objectName);
 ​
         // 关闭OSSClient。
         ossClient.shutdown();
     }
 }
 public class SmsTemplate {
 ​
     private SmsProperties properties;
 ​
     public SmsTemplate(SmsProperties properties) {
         this.properties = properties;
     }
 ​
     public void sendSms(String mobile, String code){
         System.out.println(properties.getName()+"=="+mobile+"===="+code);
     }
 }
 ​

2.4、AutoConfiguration

 @EnableConfigurationProperties({
     SmsProperties.class,
     OssProperties.class
         })
 public class CommonAutoConfig {
 ​
     @Bean
     public SmsTemplate smsTemplate(SmsProperties smsProperties){
         return new SmsTemplate(smsProperties);
     }
 ​
     @Bean
     public OssTemplate ossTemplate(OssProperties ossProperties){
         return new OssTemplate(ossProperties);
     }
 ​
 }
 ​

2.5、编写spring.factories

在resource目录下,创建一个META-INF文件夹,

在META-INF文件夹下创建一个spring.factories文件

内容是

 org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
   com.nzc.CommonAutoConfig

如果有多个就是:

 org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
   com.nzc.CommonAutoConfig \
   com.xxx.xxx

image.png


到这一步之后,我们将这个项目,达成Jar包,然后在要使用的项目中进行引入。

image.png

2.6、应用测试

1、创建一个SpringBoot 的启动类,有启动类才能进行测试,不然没上下文环境~

2、编写配置文件

 spring:
   application:
     name: app-server
 nzc:
   sms:
     name: ningzaichun
   oss:
     accessKey: xxx
     secret: xxx
     endpoint: oss-cn-shenzhen.aliyuncs.com
     bucketName: xxx
     url: xxx

将oss的配置修改正确是可以用的~

编写测试类:

 @RunWith(SpringRunner.class)
 @SpringBootTest(classes = AppServerApplication.class)
 public class TemplateTest {
 ​
     @Autowired
     private OssTemplate ossTemplate;
 ​
     @Test
     public void testOss(){
         String s = ossTemplate.test();
         System.out.println(s);
     }
 ​
     @Test
     public void testUpload(){
         try {
             File file = new File("D:\evectionflow01.png");
             InputStream inputStream = new FileInputStream(file);
             ossTemplate.upload("123.jpg",inputStream);
         } catch (FileNotFoundException e) {
             e.printStackTrace();
         }
     }
 ​
     @Autowired
     private SmsTemplate smsTemplate;
 ​
     @Test
     public void testSendSms(){
         smsTemplate.sendSms("17670090715","123456");
     }
 }

证明是可以使用的~

image.png

后记

写得较为简单,也通俗易懂~,应该能明白吧,哈哈,

如果文中有存在错误或者是不对的地方,请留下您的评论,我会及时修正,非常感谢!

这次可能是说点废话,以前我觉得工作三四年的Java开发工作者,应该是会懂很多很多东西。

因为是后端开发吗,很多时候不可避免的要接触到一些其他东西,运维部署、测试、前端、底层、架构什么的,我说的是接触,而不是精通~,不要骂我。只是个人看法。

因为三年我感觉时间很长很长了,不敢说掌握很多,但是三四年多少应该在一个区域内,有比较大的收获了吧。 但是有些时候躺平了就真的是躺平了~

当然可能是我被卷习惯了,bb赖赖一会儿,勿怪~



相关实践学习
借助OSS搭建在线教育视频课程分享网站
本教程介绍如何基于云服务器ECS和对象存储OSS,搭建一个在线教育视频课程分享网站。
目录
相关文章
|
2月前
|
SQL 监控 druid
springboot-druid数据源的配置方式及配置后台监控-自定义和导入stater(推荐-简单方便使用)两种方式配置druid数据源
这篇文章介绍了如何在Spring Boot项目中配置和监控Druid数据源,包括自定义配置和使用Spring Boot Starter两种方法。
|
1月前
|
并行计算 Java 数据处理
SpringBoot高级并发实践:自定义线程池与@Async异步调用深度解析
SpringBoot高级并发实践:自定义线程池与@Async异步调用深度解析
155 0
|
1月前
|
人工智能 自然语言处理 前端开发
SpringBoot + 通义千问 + 自定义React组件:支持EventStream数据解析的技术实践
【10月更文挑战第7天】在现代Web开发中,集成多种技术栈以实现复杂的功能需求已成为常态。本文将详细介绍如何使用SpringBoot作为后端框架,结合阿里巴巴的通义千问(一个强大的自然语言处理服务),并通过自定义React组件来支持服务器发送事件(SSE, Server-Sent Events)的EventStream数据解析。这一组合不仅能够实现高效的实时通信,还能利用AI技术提升用户体验。
163 2
|
1月前
|
架构师 Java 开发者
得物面试:Springboot自动装配机制是什么?如何控制一个bean 是否加载,使用什么注解?
在40岁老架构师尼恩的读者交流群中,近期多位读者成功获得了知名互联网企业的面试机会,如得物、阿里、滴滴等。然而,面对“Spring Boot自动装配机制”等核心面试题,部分读者因准备不足而未能顺利通过。为此,尼恩团队将系统化梳理和总结这一主题,帮助大家全面提升技术水平,让面试官“爱到不能自已”。
得物面试:Springboot自动装配机制是什么?如何控制一个bean 是否加载,使用什么注解?
|
2月前
|
Java Spring
springboot静态资源目录访问,及自定义静态资源路径,index页面的访问
本文介绍了Spring Boot中静态资源的访问位置、如何进行静态资源访问测试、自定义静态资源路径和静态资源请求映射,以及如何处理自定义静态资源映射对index页面访问的影响。提供了两种解决方案:取消自定义静态资源映射或编写Controller来截获index.html的请求并重定向。
springboot静态资源目录访问,及自定义静态资源路径,index页面的访问
|
1月前
|
缓存 NoSQL Java
Springboot自定义注解+aop实现redis自动清除缓存功能
通过上述步骤,我们不仅实现了一个高度灵活的缓存管理机制,还保证了代码的整洁与可维护性。自定义注解与AOP的结合,让缓存清除逻辑与业务逻辑分离,便于未来的扩展和修改。这种设计模式非常适合需要频繁更新缓存的应用场景,大大提高了开发效率和系统的响应速度。
61 2
|
1月前
|
前端开发 Java 数据库
springBoot:template engine&自定义一个mvc&后端给前端传数据&增删改查 (三)
本文介绍了如何自定义一个 MVC 框架,包括后端向前端传递数据、前后端代理配置、实现增删改查功能以及分页查询。详细展示了代码示例,从配置文件到控制器、服务层和数据访问层的实现,帮助开发者快速理解和应用。
|
3月前
|
Java 数据安全/隐私保护 Spring
揭秘Spring Boot自定义注解的魔法:三个实用场景让你的代码更加优雅高效
揭秘Spring Boot自定义注解的魔法:三个实用场景让你的代码更加优雅高效
|
3月前
|
安全 Java UED
掌握SpringBoot单点登录精髓,单点登录是一种身份认证机制
【8月更文挑战第31天】单点登录(Single Sign-On,简称SSO)是一种身份认证机制,它允许用户只需在多个相互信任的应用系统中登录一次,即可访问所有系统,而无需重复输入用户名和密码。在微服务架构日益盛行的今天,SSO成为提升用户体验和系统安全性的重要手段。本文将详细介绍如何在SpringBoot中实现SSO,并附上示例代码。
75 0
|
3月前
|
监控 安全 Java
【开发者必备】Spring Boot中自定义注解与处理器的神奇魔力:一键解锁代码新高度!
【8月更文挑战第29天】本文介绍如何在Spring Boot中利用自定义注解与处理器增强应用功能。通过定义如`@CustomProcessor`注解并结合`BeanPostProcessor`实现特定逻辑处理,如业务逻辑封装、配置管理及元数据分析等,从而提升代码整洁度与可维护性。文章详细展示了从注解定义、处理器编写到实际应用的具体步骤,并提供了实战案例,帮助开发者更好地理解和运用这一强大特性,以实现代码的高效组织与优化。
181 0