如何實現(xiàn)自定義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類加載器實現(xiàn)。
這個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官方規(guī)定自定義組件的命名:
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(); }
兩個接口實現(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 "汪汪"; } }
再建一個配置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; }
最后新建一個核心自動裝備配置類:
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點擊對應操作(注意不是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>
三、組件集成依賴測試
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類并調(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、最后通過項目啟動類啟動項目(項目啟動類就一個@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、接口測試
調(diào)用http接口測試:
修改"animal.name"值為"cat",再次調(diào)用http接口訪問:
四、源碼地址,參考資料
組件代碼:https://download.csdn.net/download/u010132847/87426046
集成自定義組件代碼:https://download.csdn.net/download/u010132847/87426048
到此這篇關于實現(xiàn)自定義SpringBoot的Starter組件的文章就介紹到這了,更多相關SpringBoot自定義Starter組件內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
Springboot集成阿里云OSS上傳文件系統(tǒng)教程
這篇文章主要介紹了Springboot集成阿里云OSS上傳文件系統(tǒng)教程,通過詳細的圖文展示,代碼步驟的展示和文件配置信息,希望對你有所幫助2021-06-06詳解springboot如何更新json串里面的內(nèi)容
這篇文章主要為大家介紹了springboot 如何更新json串里面的內(nèi)容,文中有詳細的解決方案供大家參考,對大家的學習或工作有一定的幫助,需要的朋友可以參考下2023-10-10spring mvc4.1.6 spring4.1.6 hibernate4.3.11 mysql5.5.25開發(fā)環(huán)境搭
這篇文章主要介紹了spring mvc4.1.6 + spring4.1.6 + hibernate4.3.11+mysql5.5.25開發(fā)環(huán)境搭建圖文教程,需要的朋友可以參考下2016-06-06