SpringBoot?SPI?機(jī)制和實(shí)現(xiàn)自定義?starter
前言
實(shí)現(xiàn)starter,其實(shí)就是SpringBoot的自動(dòng)裝配原理的一個(gè)實(shí)踐,以前我也寫(xiě)過(guò)SpringBoot的自動(dòng)狀態(tài)原理的文章,文章鏈接
細(xì)心認(rèn)真對(duì)待,沒(méi)有什么是很難的。
一、SpringBoot 中的SPI機(jī)制
什么是spi呢,全稱(chēng)是Service Provider Interface。簡(jiǎn)單翻譯的話(huà),就是服務(wù)提供者接口,是一種尋找服務(wù)實(shí)現(xiàn)的機(jī)制。
其實(shí)就是一個(gè)規(guī)范定義、或者說(shuō)是實(shí)現(xiàn)的標(biāo)準(zhǔn)。
用生活中的例子說(shuō)就是,你買(mǎi)了一臺(tái)小米的手機(jī)。
但是你用的充電器并不一定非要是小米充電器,你可以拿其他廠商的充電器來(lái)進(jìn)行充電,只要滿(mǎn)足協(xié)議、端口等要求,那么就是可以充電的。這也是一種熱拔插的思想,并不是固定死的。
換成代碼來(lái)說(shuō)也是一樣的,我定義了一個(gè)接口,但是不想固定死具體的實(shí)現(xiàn)類(lèi),因?yàn)槟菢尤绻鼡Q實(shí)現(xiàn)類(lèi)就要改動(dòng)源代碼,這往往是不合適的。
那么我也可以定義一個(gè)規(guī)范,在之后需要更換實(shí)現(xiàn)類(lèi)或增加其他實(shí)現(xiàn)類(lèi)時(shí),遵守這個(gè)規(guī)范,我也可以動(dòng)態(tài)的去發(fā)現(xiàn)這些實(shí)現(xiàn)類(lèi)。
換在SpringBoot中,就是現(xiàn)在的SpringBoot這個(gè)平臺(tái)定義了一些規(guī)范和標(biāo)準(zhǔn),我現(xiàn)在想要讓SpringBoot平臺(tái)接納我。
我該如何做呢?
很簡(jiǎn)單,按照它的標(biāo)準(zhǔn)和規(guī)范做事。
SpringBoot在啟動(dòng)的時(shí)候,會(huì)掃描所有jar包resource/META-INF/spring.factories文件,依據(jù)類(lèi)的全限定名,利用反射機(jī)制將Bean裝載進(jìn)容器中。
看完這段話(huà),我想你應(yīng)該對(duì)今天的文章應(yīng)該有個(gè)大概的理解啦。
二、自定義 starter
說(shuō)一說(shuō)我的小實(shí)踐:
在這個(gè) starter 中,實(shí)現(xiàn)
- 發(fā)送短線(xiàn)的Template
- 對(duì)象存儲(chǔ)的Template
的自動(dòng)裝配~
大致就是四步:
- 用于映射配置文件中的配置的類(lèi)xxxxProperties
- 用于操作xxxx的接口和客戶(hù)端等等,如本文中的OssTemplate
- 自動(dòng)配置類(lèi)xxxxAutoConfiguration ,并且向容器中注入xxxxTemplate
- 在spring.factories中將xxxxAutoConfiguration添加進(jìn)EnableAutoConfiguration的vaule集合中
對(duì)象存儲(chǔ)我用的是阿里云的oss,里面的配置都是可以用的, 短信的話(huà),就是個(gè)模擬的啦~,勿怪啦

2.1、準(zhǔn)備一個(gè)Maven項(xiàng)目
刪除src目錄,
然后再創(chuàng)建兩個(gè) Maven項(xiàng)目(我個(gè)人習(xí)慣,習(xí)慣創(chuàng)建空Maven項(xiàng)目,實(shí)際上創(chuàng)建SpringBoot項(xiàng)目也是一樣)

最外層的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、準(zhǔn)備Properties類(lèi)
就是用來(lái)映射配置文件的~
?/**
? * @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、準(zhǔn)備要注入的類(lèi)
就是我們最后要通過(guò)自動(dòng)裝配注入進(jìn)SpringBoot操作的類(lèi)
我這里分別是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填寫(xiě)B(tài)ucket所在地域?qū)?yīng)的Endpoint。以華東1(杭州)為例,Endpoint填寫(xiě)為https://oss-cn-hangzhou.aliyuncs.com。
? ? ? ? ?String endpoint = ossProperties.getEndpoint();
? ? ? ? ?// 阿里云主賬號(hào)AccessKey擁有所有API的訪問(wèn)權(quán)限,風(fēng)險(xiǎn)很高。強(qiáng)烈建議您創(chuàng)建并使用RAM賬號(hào)進(jìn)行API訪問(wèn)或日常運(yùn)維,請(qǐng)登錄 https://ram.console.aliyun.com 創(chuàng)建RAM賬號(hào)。
? ? ? ? ?String accessKeyId = ossProperties.getAccessKey();
? ? ? ? ?String accessKeySecret = ossProperties.getSecret();
? ? ? ? ?// 創(chuàng)建OSSClient實(shí)例。
? ? ? ? ?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);
? ? ? ? ?// 依次填寫(xiě)B(tài)ucket名稱(chēng)(例如examplebucket)和Object完整路徑(例如exampledir/exampleobject.txt)。Object完整路徑中不能包含Bucket名稱(chēng)。
? ? ? ? ?ossClient.putObject(ossProperties.getBucketName(), storePath, is);
? ? ? ? ?String url = ossProperties.getUrl() + storePath;
? ? ? ? ?// 關(guān)閉OSSClient。
? ? ? ? ?ossClient.shutdown();
? ? ? ? ?return url + "#" + storePath;
? }
? ? ?public void remove(String fileUrl) {
? ? ? ? ?// yourEndpoint填寫(xiě)B(tài)ucket所在地域?qū)?yīng)的Endpoint。以華東1(杭州)為例,Endpoint填寫(xiě)為https://oss-cn-hangzhou.aliyuncs.com。
? ? ? ? ?String endpoint = ossProperties.getEndpoint();
? ? ? ? ?// 阿里云賬號(hào)AccessKey擁有所有API的訪問(wèn)權(quán)限,風(fēng)險(xiǎn)很高。強(qiáng)烈建議您創(chuàng)建并使用RAM用戶(hù)進(jìn)行API訪問(wèn)或日常運(yùn)維,請(qǐng)登錄RAM控制臺(tái)創(chuàng)建RAM用戶(hù)。
? ? ? ? ?String accessKeyId = ossProperties.getAccessKey();
? ? ? ? ?String accessKeySecret = ossProperties.getSecret();
? ? ? ? ?// 填寫(xiě)B(tài)ucket名稱(chēng)。
? ? ? ? ?String bucketName = ossProperties.getBucketName();
? ? ? ? ?// 填寫(xiě)文件完整路徑。文件完整路徑中不能包含Bucket名稱(chēng)。
? ? ? ? ?//2022/01/21/f0870eb3-4714-4fae-9fc3-35e72202f193.jpg
? ? ? ? ?String objectName = fileUrl;
? ? ? ? ?// 創(chuàng)建OSSClient實(shí)例。
? ? ? ? ?OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
? ? ? ? ?// 刪除文件或目錄。如果要?jiǎng)h除目錄,目錄必須為空。
? ? ? ? ?ossClient.deleteObject(bucketName, objectName);
? ? ? ? ?// 關(guān)閉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、編寫(xiě)spring.factories
在resource目錄下,創(chuàng)建一個(gè)META-INF文件夾,
在META-INF文件夾下創(chuàng)建一個(gè)spring.factories文件
內(nèi)容是
?org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ ? com.nzc.CommonAutoConfig
如果有多個(gè)就是:
?org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ ? com.nzc.CommonAutoConfig \ ? com.xxx.xxx

到這一步之后,我們將這個(gè)項(xiàng)目,達(dá)成Jar包,然后在要使用的項(xiàng)目中進(jìn)行引入。

2.6、應(yīng)用測(cè)試
- 1、創(chuàng)建一個(gè)SpringBoot 的啟動(dòng)類(lèi),有啟動(dòng)類(lèi)才能進(jìn)行測(cè)試,不然沒(méi)上下文環(huán)境~
- 2、編寫(xiě)配置文件
?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的配置修改正確是可以用的~
編寫(xiě)測(cè)試類(lèi):
?@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");
? ? }
?}證明是可以使用的~

后記
寫(xiě)得較為簡(jiǎn)單,也通俗易懂~,應(yīng)該能明白吧,哈哈,
如果文中有存在錯(cuò)誤或者是不對(duì)的地方,請(qǐng)留下您的評(píng)論,我會(huì)及時(shí)修正,非常感謝!
這次可能是說(shuō)點(diǎn)廢話(huà),以前我覺(jué)得工作三四年的Java開(kāi)發(fā)工作者,應(yīng)該是會(huì)懂很多很多東西。
因?yàn)槭呛蠖碎_(kāi)發(fā)嗎,很多時(shí)候不可避免的要接觸到一些其他東西,
運(yùn)維部署、測(cè)試、前端、底層、架構(gòu)什么的,我說(shuō)的是接觸,而不是精通~,不要罵我。只是個(gè)人看法。
到此這篇關(guān)于SpringBoot SPI 機(jī)制和實(shí)現(xiàn)自定義 starter的文章就介紹到這了,更多相關(guān)SpringBoot SPI內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Java導(dǎo)出網(wǎng)頁(yè)表格Excel過(guò)程詳解
這篇文章主要介紹了Java導(dǎo)出網(wǎng)頁(yè)表格Excel過(guò)程詳解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-07-07
DUCC配置平臺(tái)實(shí)現(xiàn)一個(gè)動(dòng)態(tài)化線(xiàn)程池示例代碼
這篇文章主要為大家介紹了DUCC配置平臺(tái)實(shí)現(xiàn)一個(gè)動(dòng)態(tài)化線(xiàn)程池示例代碼,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-02-02
MyBatis入門(mén)初體驗(yàn)之使用大全(2)
這篇文章主要介紹了MyBatis入門(mén)初體驗(yàn)之使用大全(2)的相關(guān)資料,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友可以參考下2016-07-07
java 三種將list轉(zhuǎn)換為map的方法詳解
這篇文章主要介紹了java 三種將list轉(zhuǎn)換為map的方法詳解的相關(guān)資料,需要的朋友可以參考下2017-01-01
springboot集成Deepseek4j的項(xiàng)目實(shí)踐
本文主要介紹了springboot集成Deepseek4j的項(xiàng)目實(shí)踐,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2025-03-03
java實(shí)現(xiàn)圖片的上傳與展示實(shí)例代碼
這篇文章主要給大家介紹了關(guān)于java實(shí)現(xiàn)圖片的上傳與展示的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2018-12-12
java二叉查找樹(shù)的實(shí)現(xiàn)代碼
這篇文章主要為大家詳細(xì)介紹了java二叉查找樹(shù)的實(shí)現(xiàn)代碼,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-08-08
基于Java實(shí)現(xiàn)一個(gè)復(fù)雜關(guān)系表達(dá)式過(guò)濾器
這篇文章主要為大家詳細(xì)介紹了如何基于Java實(shí)現(xiàn)一個(gè)復(fù)雜關(guān)系表達(dá)式過(guò)濾器。文中的示例代碼講解詳細(xì),感興趣的小伙伴可以了解一下2022-07-07

