实现自定义SpringBoot的Starter组件
一、前言
想要自定义starter组件,首先要了解springboot是如何加载starter的,也就是springboot的自动装配机制原理。
1.1、starter加载原理
springboot通过一个@SpringBootApplication注解启动项目,springboot在项目启动的时候,会将项目中所有声明为Bean对象(注解、xml)的实例信息全部加载到ioc容器当中。 除此之外也会将所有依赖到的starter里的bean信息加载到ioc容器中,从而做到所谓的零配置,开箱即用。
1.1.1、加载starter
首先通过通过注解@SpringBootApplication找到@EnableAutoConfiguration注解进行加载starter。
再通过注解@EnableAutoConfiguration下注解@import找到AutoConfigurationImportSelector类加载器实现。
这个AutoConfigurationImportSelector类会去其引用的依赖jar包下,找到一个”spring.factories”文件,一般spring.factories文件里都会声明该依赖所提供的核心功能bean配置信息。文件一般在依赖jar包的META-INF文件夹下面。
以spring-boot版本2.7.7为例,加载spring.factories的代码在:
AutoConfigurationImportSelector.java->selectImports(AnnotationMetadata annotationMetadata)->getAutoConfigurationEntry(annotationMetadata)->getCandidateConfigurations(annotationMetadata, attributes)->SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(), getBeanClassLoader())->loadSpringFactories(classLoaderToUse):
-
private static Map<String, List<String>> loadSpringFactories(ClassLoader classLoader) {
-
Map<String, List<String>> result = (Map)cache.get(classLoader);
-
if (result != null) {
-
return result;
-
} else {
-
HashMap result = new HashMap();
-
-
try {
-
Enumeration urls = classLoader.getResources("META-INF/spring.factories");
-
-
while(urls.hasMoreElements()) {
-
URL url = (URL)urls.nextElement();
-
UrlResource resource = new UrlResource(url);
-
Properties properties = PropertiesLoaderUtils.loadProperties(resource);
-
Iterator var6 = properties.entrySet().iterator();
-
-
while(var6.hasNext()) {
-
Entry<?, ?> entry = (Entry)var6.next();
-
String factoryTypeName = ((String)entry.getKey()).trim();
-
String[] factoryImplementationNames = StringUtils.commaDelimitedListToStringArray((String)entry.getValue());
-
String[] var10 = factoryImplementationNames;
-
int var11 = factoryImplementationNames.length;
-
-
for(int var12 = 0; var12 < var11; var12) {
-
String factoryImplementationName = var10[var12];
-
((List)result.computeIfAbsent(factoryTypeName, (key) -> {
-
return new ArrayList();
-
})).add(factoryImplementationName.trim());
-
}
-
}
-
}
-
-
result.replaceAll((factoryType, implementations) -> {
-
return (List)implementations.stream().distinct().collect(Collectors.collectingAndThen(Collectors.toList(), Collections::unmodifiableList));
-
});
-
cache.put(classLoader, result);
-
return result;
-
} catch (IOException var14) {
-
throw new IllegalArgumentException("Unable to load factories from location [META-INF/spring.factories]", var14);
-
}
-
}
-
}
举例如:spring-boot-autoconfig的spring.factories.
二、自定义starter
上面了解了springboot加载starter原理,其实就是加载依赖jar包下的spring.factories文件。所以我们要自定义starter,就需要在项目中建立一个META-INF的文件夹,然后在该文件夹下面建一个spring.factories文件,文件里将你需要提供出去的bean实例信息配置好就行。
2.1、代码
2.1.1、新建springboot项目。简单演示所以需求配置任务依赖。如springboot构建很慢,或者打包的时候下载依赖很慢,可在pom文件中添加如下仓库配置,可以加快构建速度。
-
<repositories>
-
<repository>
-
<id>alimaven</id>
-
<url>https://maven.aliyun.com/repository/public</url>
-
</repository>
-
</repositories>
-
-
<pluginRepositories>
-
<pluginRepository>
-
<id>alimaven</id>
-
<url>https://maven.aliyun.com/repository/public</url>
-
</pluginRepository>
-
</pluginRepositories>
注意:spring官方规定自定义组件的命名:
SpringBoot官方命名方式
格式:spring-boot-starter-{模块名}
举例:spring-boot-starter-web
自定义命名方式
格式:{模块名}-spring-boot-starter
举例:mystarter-spring-boot-starter
2.1.2、项目构建完成后,在resources文件夹下面新建META-INF文件夹,并新建spring.factories文件。
2.1.3、因为我们是作为插件来使用,所以我们不需要启动类,删除启动类。并新建几个类:
一个接口AnimalService:
-
package com.example.demospringbootstarter.service;
-
-
/**
-
* @Project: demo-spring-boot-starter
-
* @Description:
-
* @Author: chengjiangbo
-
* @Date: 2023/2/7 15:12
-
*/
-
public interface AnimalService {
-
-
String say();
-
}
两个接口实现类CatService和DogService:
-
package com.example.demospringbootstarter.service;
-
-
import lombok.AllArgsConstructor;
-
import lombok.Data;
-
import lombok.NoArgsConstructor;
-
import org.springframework.stereotype.Service;
-
-
/**
-
* @Project: demo-spring-boot-starter
-
* @Description:
-
* @Author: chengjiangbo
-
* @Date: 2023/2/7 14:49
-
*/
-
-
public class CatService implements AnimalService{
-
-
public static String name = "cat";
-
-
-
public String say() {
-
return "喵喵";
-
}
-
}
-
package com.example.demospringbootstarter.service;
-
-
import org.springframework.stereotype.Service;
-
-
/**
-
* @Project: demo-spring-boot-starter
-
* @Description:
-
* @Author: chengjiangbo
-
* @Date: 2023/2/7 14:49
-
*/
-
-
public class DogService implements AnimalService{
-
-
public static String name = "dog";
-
-
-
public String say() {
-
return "汪汪";
-
}
-
}
再建一个配置AnimalProperties类,方便注入属性值:
-
package com.example.demospringbootstarter.config;
-
-
import lombok.Data;
-
import org.springframework.boot.context.properties.ConfigurationProperties;
-
-
/**
-
* @Project: demo-spring-boot-starter
-
* @Description:
-
* @Author: chengjiangbo
-
* @Date: 2023/2/7 15:37
-
*/
-
-
-
public class AnimalProperties {
-
-
private String name;
-
}
最后新建一个核心自动装备配置类:
-
package com.example.demospringbootstarter.config;
-
-
import com.example.demospringbootstarter.service.AnimalService;
-
import com.example.demospringbootstarter.service.CatService;
-
import com.example.demospringbootstarter.service.DogService;
-
import org.springframework.beans.factory.annotation.Autowired;
-
import org.springframework.boot.context.properties.EnableConfigurationProperties;
-
import org.springframework.context.annotation.Bean;
-
import org.springframework.context.annotation.Configuration;
-
-
/**
-
* @Project: demo-spring-boot-starter
-
* @Description:
-
* @Author: chengjiangbo
-
* @Date: 2023/2/7 14:48
-
*/
-
-
-
public class AnimalAutoConfig {
-
-
-
private AnimalProperties animalProperties;
-
-
-
public AnimalService demoService(){
-
switch (animalProperties.getName()){
-
case "cat":
-
return new CatService();
-
case "dog":
-
return new DogService();
-
default:
-
return null;
-
}
-
}
-
}
META-INF/spring.factories的内容为:
-
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
-
com.example.demospringbootstarter.config.AnimalAutoConfig
以上步骤都好后,使用maven命令打包:
mvn clean install -Dmaven.test.skip=true
或者使用idea的LIfecycle点击对应操作(注意不是plugin下的命令操作)。
pom.xml内容为:
-
-
<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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
-
<modelVersion>4.0.0</modelVersion>
-
<parent>
-
<groupId>org.springframework.boot</groupId>
-
<artifactId>spring-boot-starter-parent</artifactId>
-
<version>2.3.4.RELEASE</version>
-
<relativePath/> <!-- lookup parent from repository -->
-
</parent>
-
<groupId>com.example</groupId>
-
<artifactId>demo-spring-boot-starter</artifactId>
-
<version>0.0.4-SNAPSHOT</version>
-
<name>demo-spring-boot-starter</name>
-
<description>Demo project for Spring Boot</description>
-
<properties>
-
<java.version>8</java.version>
-
</properties>
-
<dependencies>
-
<dependency>
-
<groupId>org.springframework.boot</groupId>
-
<artifactId>spring-boot-starter-web</artifactId>
-
</dependency>
-
-
<dependency>
-
<groupId>org.projectlombok</groupId>
-
<artifactId>lombok</artifactId>
-
<optional>true</optional>
-
</dependency>
-
-
</dependencies>
-
-
<repositories>
-
<repository>
-
<id>alimaven</id>
-
<url>https://maven.aliyun.com/repository/public</url>
-
</repository>
-
</repositories>
-
-
<pluginRepositories>
-
<pluginRepository>
-
<id>alimaven</id>
-
<url>https://maven.aliyun.com/repository/public</url>
-
</pluginRepository>
-
</pluginRepositories>
-
-
</project>
三、组件集成依赖测试
3.1、新启另一个项目中,引入刚刚打包的pom依赖
-
<dependency>
-
<groupId>com.example</groupId>
-
<artifactId>demo-spring-boot-starter</artifactId>
-
<version>0.0.4-SNAPSHOT</version>
-
</dependency>
3.2、新建一个controller,里面注入上面提供的AnimalService类并调用其方法
-
package com.cjb.mavendemo.controllers;
-
-
import com.example.demospringbootstarter.service.AnimalService;
-
import com.example.inputoutputlogspringbootstarter.config.PrintResponseTime;
-
import org.springframework.beans.factory.annotation.Autowired;
-
import org.springframework.web.bind.annotation.GetMapping;
-
import org.springframework.web.bind.annotation.RequestMapping;
-
import org.springframework.web.bind.annotation.RestController;
-
-
/**
-
* @Project: maven-demo
-
* @Description:
-
* @Author: chengjiangbo
-
* @Date: 2023/2/7 10:26
-
*/
-
-
-
public class TestController {
-
-
-
private AnimalService animalService;
-
-
-
-
public String call(){
-
return animalService.say();
-
}
-
}
3.3、application.properties内容配置参数"animal.name"值
3.4、最后通过项目启动类启动项目(项目启动类就一个@SpringBootApplicaiton注解)
-
package com.cjb.mavendemo;
-
-
import org.springframework.boot.SpringApplication;
-
import org.springframework.boot.autoconfigure.SpringBootApplication;
-
-
-
public class MavenDemoApplication {
-
-
public static void main(String[] args) {
-
SpringApplication.run(MavenDemoApplication.class, args);
-
}
-
-
}
3.5、接口测试
调用http接口测试:
修改"animal.name"值为"cat",再次调用http接口访问:
四、源码地址
这篇好文章是转载于:学新通技术网
- 版权申明: 本站部分内容来自互联网,仅供学习及演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,请提供相关证据及您的身份证明,我们将在收到邮件后48小时内删除。
- 本站站名: 学新通技术网
- 本文地址: /boutique/detail/tanhgiijab
-
报错org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name...
-
解决Java 8 date/time type `java.time.LocalDateTime` not supported by default
-
Maven项目混淆、瘦身、打包exe
-
IntelliJ IDEA导入本地SpringBoot项目教程
-
Spring Boot整合Spring Security二自定义登录界面——formLogin()的配置
-
java+springboot 做日志链路追踪
-
photoshop保存的图片太大微信发不了怎么办
PHP中文网 06-15 -
《学习通》视频自动暂停处理方法
HelloWorld317 07-05 -
word里面弄一个表格后上面的标题会跑到下面怎么办
PHP中文网 06-20 -
Android 11 保存文件到外部存储,并分享文件
Luke 10-12 -
photoshop扩展功能面板显示灰色怎么办
PHP中文网 06-14 -
微信公众号没有声音提示怎么办
PHP中文网 03-31 -
excel下划线不显示怎么办
PHP中文网 06-23 -
excel打印预览压线压字怎么办
PHP中文网 06-22 -
TikTok加速器哪个好免费的TK加速器推荐
TK小达人 10-01 -
怎样阻止微信小程序自动打开
PHP中文网 06-13