如何實(shí)現(xiàn)自定義SpringBoot的Starter組件
一、前言
想要自定義starter組件,首先要了解springboot是如何加載starter的,也就是springboot的自動(dòng)裝配機(jī)制原理。
1.1、starter加載原理
springboot通過(guò)一個(gè)@SpringBootApplication注解啟動(dòng)項(xiàng)目,springboot在項(xiàng)目啟動(dòng)的時(shí)候,會(huì)將項(xiàng)目中所有聲明為Bean對(duì)象(注解、xml)的實(shí)例信息全部加載到ioc容器當(dāng)中。 除此之外也會(huì)將所有依賴到的starter里的bean信息加載到ioc容器中,從而做到所謂的零配置,開(kāi)箱即用。
1.1.1、加載starter
首先通過(guò)通過(guò)注解@SpringBootApplication找到@EnableAutoConfiguration注解進(jìn)行加載starter。

再通過(guò)注解@EnableAutoConfiguration下注解@import找到AutoConfigurationImportSelector類加載器實(shí)現(xiàn)。

這個(gè)AutoConfigurationImportSelector類會(huì)去其引用的依賴jar包下,找到一個(gè)”spring.factories”文件,一般spring.factories文件里都會(huì)聲明該依賴所提供的核心功能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原理,其實(shí)就是加載依賴jar包下的spring.factories文件。所以我們要自定義starter,就需要在項(xiàng)目中建立一個(gè)META-INF的文件夾,然后在該文件夾下面建一個(gè)spring.factories文件,文件里將你需要提供出去的bean實(shí)例信息配置好就行。
2.1、代碼
2.1.1、新建springboot項(xiàng)目。
簡(jiǎn)單演示所以需求配置任務(wù)依賴。如springboot構(gòu)建很慢,或者打包的時(shí)候下載依賴很慢,可在pom文件中添加如下倉(cāng)庫(kù)配置,可以加快構(gòu)建速度。
<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官方規(guī)定自定義組件的命名:
SpringBoot官方命名方式
格式:spring-boot-starter-{模塊名}
舉例:spring-boot-starter-web
自定義命名方式
格式:{模塊名}-spring-boot-starter
舉例:mystarter-spring-boot-starter
2.1.2、項(xiàng)目構(gòu)建完成后,在resources文件夾下面新建META-INF文件夾,并新建spring.factories文件。

2.1.3、因?yàn)槲覀兪亲鳛椴寮?lái)使用,所以我們不需要啟動(dòng)類,刪除啟動(dòng)類。并新建幾個(gè)類:
一個(gè)接口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();
}兩個(gè)接口實(shí)現(xiàn)類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
*/
@Service
public class CatService implements AnimalService{
public static String name = "cat";
@Override
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
*/
@Service
public class DogService implements AnimalService{
public static String name = "dog";
@Override
public String say() {
return "汪汪";
}
}再建一個(gè)配置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
*/
@Data
@ConfigurationProperties(prefix = "animal")
public class AnimalProperties {
private String name;
}最后新建一個(gè)核心自動(dòng)裝備配置類:
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
*/
@Configuration
@EnableConfigurationProperties(AnimalProperties.class)
public class AnimalAutoConfig {
@Autowired
private AnimalProperties animalProperties;
@Bean
public AnimalService demoService(){
switch (animalProperties.getName()){
case "cat":
return new CatService();
case "dog":
return new DogService();
default:
return null;
}
}
}
META-INF/spring.factories的內(nèi)容為:
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ com.example.demospringbootstarter.config.AnimalAutoConfig
以上步驟都好后,使用maven命令打包:
mvn clean install -Dmaven.test.skip=true
或者使用idea的LIfecycle點(diǎn)擊對(duì)應(yīng)操作(注意不是plugin下的命令操作)。

pom.xml內(nèi)容為:
<?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 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>
三、組件集成依賴測(cè)試
3.1、新啟另一個(gè)項(xiàng)目中,引入剛剛打包的pom依賴
<dependency>
<groupId>com.example</groupId>
<artifactId>demo-spring-boot-starter</artifactId>
<version>0.0.4-SNAPSHOT</version>
</dependency>3.2、新建一個(gè)controller,里面注入上面提供的AnimalService類并調(diào)用其方法
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
*/
@RestController
@RequestMapping(value = "/test")
public class TestController {
@Autowired
private AnimalService animalService;
@PrintResponseTime
@GetMapping("/call")
public String call(){
return animalService.say();
}
}3.3、application.properties內(nèi)容配置參數(shù)"animal.name"值

3.4、最后通過(guò)項(xiàng)目啟動(dòng)類啟動(dòng)項(xiàng)目(項(xiàng)目啟動(dòng)類就一個(gè)@SpringBootApplicaiton注解)
package com.cjb.mavendemo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class MavenDemoApplication {
public static void main(String[] args) {
SpringApplication.run(MavenDemoApplication.class, args);
}
}3.5、接口測(cè)試
調(diào)用http接口測(cè)試:

修改"animal.name"值為"cat",再次調(diào)用http接口訪問(wèn):

四、源碼地址,參考資料
組件代碼:https://download.csdn.net/download/u010132847/87426046
集成自定義組件代碼:https://download.csdn.net/download/u010132847/87426048
到此這篇關(guān)于實(shí)現(xiàn)自定義SpringBoot的Starter組件的文章就介紹到這了,更多相關(guān)SpringBoot自定義Starter組件內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Java中StringUtils工具類的一些用法實(shí)例
這篇文章主要介紹了Java中StringUtils工具類的一些用法實(shí)例,本文著重講解了isEmpty和isBlank方法的使用,另外也講解了trim、strip等方法的使用實(shí)例,需要的朋友可以參考下2015-06-06
java httpclient設(shè)置超時(shí)時(shí)間和代理的方法
這篇文章主要介紹了java httpclient設(shè)置超時(shí)時(shí)間和代理的方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-02-02
利用微信小程序+JAVA實(shí)現(xiàn)微信支付的全過(guò)程
微信支付是一種在線支付解決方案,允許用戶通過(guò)微信內(nèi)的支付功能進(jìn)行付款,下面這篇文章主要給大家介紹了關(guān)于利用微信小程序+JAVA實(shí)現(xiàn)微信支付的相關(guān)資料,需要的朋友可以參考下2024-08-08
一起來(lái)學(xué)習(xí)JAVA的運(yùn)算符
這篇文章主要為大家詳細(xì)介紹了JAVA的運(yùn)算符,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來(lái)幫助2022-03-03
Spring IOC的相關(guān)注解運(yùn)用詳解
這篇文章主要介紹了Spring IOC的相關(guān)注解運(yùn)用詳解,純注解實(shí)現(xiàn)IOC需要一個(gè)Java類代替xml文件,這個(gè)Java類上方需要添加@Configuration,表示該類是一個(gè)配置類,作用是代替配置文件,需要的朋友可以參考下2023-08-08
SpringCloud Hystrix-Dashboard儀表盤(pán)的實(shí)現(xiàn)
這篇文章主要介紹了SpringCloud Hystrix-Dashboard儀表盤(pán)的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-08-08

