目錄
一、什么是SpringBoot starter機(jī)制
二、為什么要自定義starter
三、什么時(shí)候需要?jiǎng)?chuàng)建自定義starter
四、自動(dòng)加載核心注解說(shuō)明
五、自定義starter的開(kāi)發(fā)流程
案例一:為短信發(fā)送功能創(chuàng)建一個(gè)starter
案例二:AOP方式統(tǒng)一服務(wù)日志
?一、什么是SpringBoot starter機(jī)制
SpringBoot中的starter是一種非常重要的機(jī)制(自動(dòng)化配置),能夠拋棄以前繁雜的配置,將其統(tǒng)一集成進(jìn)starter,應(yīng)用者只需要在maven中引入starter依賴,SpringBoot就能自動(dòng)掃描到要加載的信息并啟動(dòng)相應(yīng)的默認(rèn)配置。
starter讓我們擺脫了各種依賴庫(kù)的處理,需要配置各種信息的困擾。SpringBoot會(huì)自動(dòng)通過(guò)classpath路徑下的類(lèi)發(fā)現(xiàn)需要的Bean,并注冊(cè)進(jìn)IOC容器。SpringBoot提供了針對(duì)日常企業(yè)應(yīng)用研發(fā)各種場(chǎng)景的spring-boot-starter依賴模塊。
所有這些依賴模塊都遵循著約定成俗的默認(rèn)配置,并允許我們調(diào)整這些配置,即遵循“約定大于配置”的理念。
二、為什么要自定義starter
在我們的日常開(kāi)發(fā)工作中,經(jīng)常會(huì)有一些獨(dú)立于業(yè)務(wù)之外的配置模塊,我們經(jīng)常將其放到一個(gè)特定的包下,然后如果另一個(gè)工程需要復(fù)用這塊功能的時(shí)候,需要將代碼硬拷貝到另一個(gè)工程,重新集成一遍,麻煩至極。
如果我們將這些可獨(dú)立于業(yè)務(wù)代碼之外的功配置模塊封裝成一個(gè)個(gè)starter,復(fù)用的時(shí)候只需要將其在pom中引用依賴即可,SpringBoot為我們完成自動(dòng)裝配,簡(jiǎn)直不要太爽
三、什么時(shí)候需要?jiǎng)?chuàng)建自定義starter
在我們的日常開(kāi)發(fā)工作中,可能會(huì)需要開(kāi)發(fā)一個(gè)通用模塊,以供其它工程復(fù)用。SpringBoot就為我們提供這樣的功能機(jī)制,我們可以把我們的通用模塊封裝成一個(gè)個(gè)starter,這樣其它工程復(fù)用的時(shí)候只需要在pom中引用依賴即可,由SpringBoot為我們完成自動(dòng)裝配。
常見(jiàn)場(chǎng)景:
? ?1.通用模塊-短信發(fā)送模塊
? ?2.基于AOP技術(shù)實(shí)現(xiàn)日志切面? ?3.分布式雪花ID,Long-->string,解決精度問(wèn)題
? ? ?jackson2/fastjson? ?4.微服務(wù)項(xiàng)目的數(shù)據(jù)庫(kù)連接池配置
? ?5.微服務(wù)項(xiàng)目的每個(gè)模塊都要訪問(wèn)redis數(shù)據(jù)庫(kù),每個(gè)模塊都要配置redisTemplate
? ? ?也可以通過(guò)starter解決
四、自動(dòng)加載核心注解說(shuō)明
starter 組件開(kāi)發(fā),核心是自動(dòng)注解類(lèi)的注解順序,即根據(jù)條件進(jìn)行注解
?關(guān)于自動(dòng)加載核心注解,詳情可見(jiàn):https://blog.csdn.net/qq_19782697/article/details/100727302
五、自定義starter的開(kāi)發(fā)流程
那么前面對(duì)自定義 starter 機(jī)制簡(jiǎn)單介紹了一下,接下來(lái)就進(jìn)入正題!
自定義starter的開(kāi)發(fā)流程:
? ?1.創(chuàng)建Starter項(xiàng)目(spring-initl 2.1.14)
? ?2.定義Starter需要的配置類(lèi)(Properties)
? ?3.編寫(xiě)Starter項(xiàng)目的業(yè)務(wù)功能
? ?4.編寫(xiě)自動(dòng)配置類(lèi)
? ?5.編寫(xiě)spring.factories文件加載自動(dòng)配置類(lèi)
? ?6.打包安裝
? ?7.其它項(xiàng)目引用
案例一:為短信發(fā)送功能創(chuàng)建一個(gè)starter
1.創(chuàng)建Starter項(xiàng)目
?
?starter項(xiàng)目和SpringBoot工程結(jié)構(gòu)沒(méi)有什么區(qū)別,下面就把一些特殊的要求羅列一下
? ? ?1.1.命名規(guī)范
? ? ? ?SpringBoot官方命名方式
? ? ? ?格式:spring-boot-starter-{模塊名}
? ? ? ?舉例:spring-boot-starter-web
? ? ? ?自定義命名方式
? ? ? ?格式:{模塊名}-spring-boot-starter
? ? ? ?舉例:mystarter-spring-boot-starter
? ? ?1.2.必須引入的依賴<!--表示兩個(gè)項(xiàng)目之間依賴不傳遞;不設(shè)置optional或者optional是false,表示傳遞依賴--> <!--例如:project1依賴a.jar(optional=true),project2依賴project1,則project2不依賴a.jar--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-configuration-processor</artifactId> <optional>true</optional> </dependency>
如果我們剛剛創(chuàng)建項(xiàng)目時(shí)選擇了Spring Configuration Processor,在pom.xml文件中就會(huì)有上面的依賴
2.編寫(xiě)相關(guān)屬性類(lèi)(XxxProperties):SmsProperties.java
--@ConfigurationProperties注解基本用法
? ? ? ?前綴定義了哪些外部屬性將綁定到類(lèi)的字段上
? ? ? ?根據(jù) Spring Boot 寬松的綁定規(guī)則,類(lèi)的屬性名稱(chēng)必須與外部屬性的名稱(chēng)匹配
? ? ? ?我們可以簡(jiǎn)單地用一個(gè)值初始化一個(gè)字段來(lái)定義一個(gè)默認(rèn)值
? ? ? ?類(lèi)本身可以是包私有的
? ? ? ?類(lèi)的字段必須有公共 setter 方法 ??? ? ?注意:SmsProperties代碼寫(xiě)完后會(huì)報(bào)如下錯(cuò)誤,這是正常的,因?yàn)?br> ? ? ? ? ?還有配置類(lèi)AutoConfig和一個(gè)注解@EnableConfigurationProperties沒(méi)有加
? ? ? ? ?(Not registered via @EnableConfigurationProperties or marked as Spring component)package com.zking.zzcloudspringbootstarter.sms; import org.springframework.boot.context.properties.ConfigurationProperties; import java.io.Serializable; @ConfigurationProperties("zzcloud.sms") public class SmsProperties implements Serializable { private String accessKeyId;//訪問(wèn)ID、即帳號(hào) private String accessKeySecret;//訪問(wèn)憑證,即密碼 public String getAccessKeyId() { return accessKeyId; } public void setAccessKeyId(String accessKeyId) { this.accessKeyId = accessKeyId; } public String getAccessKeySecret() { return accessKeySecret; } public void setAccessKeySecret(String accessKeySecret) { this.accessKeySecret = accessKeySecret; } }
3.編寫(xiě)Starter項(xiàng)目的業(yè)務(wù)功能?
ISmsService和SmsServiceImpl相關(guān)代碼如下:package com.zking.zzcloudspringbootstarter.sms; public interface ISmsService { /** * 發(fā)送短信 * * @param phone 要發(fā)送的手機(jī)號(hào) * @param signName 短信簽名-在短信控制臺(tái)中找 * @param templateCode 短信模板-在短信控制臺(tái)中找 * @param data 要發(fā)送的內(nèi)容 */ void send(String phone, String signName, String templateCode, String data); }
package com.zking.zzcloudspringbootstarter.sms; import com.zking.zzcloudspringbootstarter.sms.ISmsService; public class SmsServiceImpl implements ISmsService { private String accessKeyId;//訪問(wèn)ID、即帳號(hào) private String accessKeySecret;//訪問(wèn)憑證,即密碼 public SmsServiceImpl(String accessKeyId, String accessKeySecret) { this.accessKeyId = accessKeyId; this.accessKeySecret = accessKeySecret; } @Override public void send(String phone, String signName, String templateCode, String data) { System.out.println("接入短信系統(tǒng),accessKeyId=" + accessKeyId + ",accessKeySecret=" + accessKeySecret); System.out.println("短信發(fā)送,phone=" + phone + ",signName=" + signName + ",templateCode=" + templateCode + ",data=" + data); } }
4.編寫(xiě)自動(dòng)配置類(lèi)AutoConfig?
? ? 4.1. @Configuration:
? ? ? ?定義一個(gè)配置類(lèi)
? ? 4.2. @EnableConfigurationProperties:
? ? ? ?@EnableConfigurationProperties注解的作用是@ConfigurationProperties注解生效。
? ? ? ?如果只配置@ConfigurationProperties注解,在IOC容器中是獲取不到properties配置文? ? ? ? ? ?件轉(zhuǎn)化的bean的?package com.zking.zzcloudspringbootstarter.config; import com.zking.zzcloudspringbootstarter.sms.SmsProperties; import com.zking.zzcloudspringbootstarter.sms.SmsServiceImpl; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import javax.annotation.Resource; @Configuration //表示這個(gè)類(lèi)為配置類(lèi) @EnableConfigurationProperties({SmsProperties.class}) public class SmsAutoConfig { @Resource private SmsProperties smsProperties; @Bean public SmsServiceImpl smsServiceImpl(){ return new SmsServiceImpl(smsProperties.getAccessKeyId(),smsProperties.getAccessKeySecret()); } }
5.編寫(xiě)spring.factories文件加載自動(dòng)配置類(lèi)
? ? ?5.1.在resources下新建META-INF文件夾,然后創(chuàng)建spring.factories文件
? ? ?5.2.在該文件中加入如下配置,該配置指定上步驟中定義的配置類(lèi)為自動(dòng)裝配的配置org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ com.zking.zzcloudspringbootstarter.config.SmsAutoConfig
注1:其中AutoConfig是starter配置文件的類(lèi)限定名,多個(gè)之間逗號(hào)分割,還可以\進(jìn)行轉(zhuǎn)義即相當(dāng)于去掉后面換行和空格符號(hào),如下所示
?# Auto Configure org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ com.baomidou.mybatisplus.autoconfigure.MybatisPlusLanguageDriverAutoConfiguration,\ com.baomidou.mybatisplus.autoconfigure.MybatisPlusAutoConfiguration
6.打包安裝
打包時(shí)需要注意一下,SpringBoot項(xiàng)目打包的JAR是可執(zhí)行JAR,它的類(lèi)放在BOOT-INF目錄下,如果直接作為其他項(xiàng)目的依賴,會(huì)找不到類(lèi)??梢酝ㄟ^(guò)修改pom文件來(lái)解決,代碼如下:
<plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> <configuration> <classifier>exec</classifier> </configuration> </plugin>
打包前,先查看我們maven倉(cāng)庫(kù)的位置,并設(shè)置到自己本地倉(cāng)庫(kù)位置中去,再打包。過(guò)程如下:
成功后,我們可以發(fā)現(xiàn)我們本地倉(cāng)庫(kù)就會(huì)有剛剛我們打包完的項(xiàng)目:
到這里為止,我們的整個(gè)自定義starter的準(zhǔn)備工作就做完了,如下是我的整個(gè)自定義starter文件的結(jié)構(gòu):
7.在其他項(xiàng)目中的應(yīng)用?
7.1.首先在其他項(xiàng)目的pom.xml中引入相關(guān)依賴:
?7.2.在application.yml文件中添加配置
?為了展示效果,我們寫(xiě)一個(gè)測(cè)試類(lèi),看能否看到我們想要的效果,測(cè)試代碼如下:
package com.zking.springboot02.service.impl; import com.zking.springboot02.Springboot02Application; import com.zking.springboot02.model.Book; import com.zking.springboot02.service.IBookService; import com.zking.springboot02.utils.PageBean; import com.zking.zzcloudspringbootstarter.sms.ISmsService; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.data.redis.core.RedisTemplate; import javax.annotation.Resource; import java.util.List; @SpringBootTest(classes = Springboot02Application.class) class SmsServiceImplTest { @Resource private ISmsService smsService; @BeforeEach void setUp() { } @AfterEach void tearDown() { } @Test void testRedis() { smsService.send("15575488448","pengying","1","小彭不會(huì)禿頭加油干!"); } }
控制臺(tái)效果如下:
?如果控制臺(tái)有如上效果,說(shuō)明我們整個(gè)自定義starter的過(guò)程就成功了!
案例二:AOP方式統(tǒng)一服務(wù)日志
原先實(shí)現(xiàn)統(tǒng)一日志都是放到每個(gè)工程中以AOP方式實(shí)現(xiàn),現(xiàn)在有了starter方式,就可以將公司的日志規(guī)范集中到這里來(lái)統(tǒng)一管理。
這里我們使用之前創(chuàng)建好的項(xiàng)目進(jìn)行案例二的編寫(xiě),步驟與上同理:
1.導(dǎo)入aop相關(guān)依賴
<!--aop相關(guān)依賴--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-aop</artifactId> </dependency>
2.編寫(xiě)相關(guān)屬性類(lèi)(XxxProperties):WebLogProperties.java
package com.zking.zzcloudspringbootstarter.sms; import org.springframework.boot.context.properties.ConfigurationProperties; import java.io.Serializable; @ConfigurationProperties("zzcloud.weblog") public class WebLogProperties implements Serializable { public Boolean enabled; //Boolean封裝類(lèi),默認(rèn)為null public Boolean getEnabled() { return enabled; } public void setEnabled(Boolean enabled) { this.enabled = enabled; } }
3.編寫(xiě)Starter項(xiàng)目的業(yè)務(wù)功能?
package com.zking.zzcloudspringbootstarter.weblog; import lombok.extern.slf4j.Slf4j; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.annotation.AfterReturning; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.aspectj.lang.annotation.Pointcut; import org.springframework.stereotype.Component; import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.context.request.ServletRequestAttributes; import javax.servlet.http.HttpServletRequest; import java.util.Arrays; @Aspect @Component @Slf4j public class WebLogAspect { //@Pointcut("execution(public * com.zking..controller.*.*(..))") @Pointcut("execution(* *..*Controller.*(..))") public void webLog(){} @Before("webLog()") public void doBefore(JoinPoint joinPoint) throws Throwable { // 接收到請(qǐng)求,記錄請(qǐng)求內(nèi)容 ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); HttpServletRequest request = attributes.getRequest(); // 記錄下請(qǐng)求內(nèi)容 log.info("開(kāi)始服務(wù):{}", request.getRequestURL().toString()); log.info("客戶端IP :{}" , request.getRemoteAddr()); log.info("參數(shù)值 :{}", Arrays.toString(joinPoint.getArgs())); } @AfterReturning(returning = "ret", pointcut = "webLog()") public void doAfterReturning(Object ret) throws Throwable { // 處理完請(qǐng)求,返回內(nèi)容 log.info("返回值 : {}" , ret); } }
4.編寫(xiě)自動(dòng)配置類(lèi)AutoConfig?
4.1.@ConditionalOnProperty(prefix = "zzcloud.weblog",value = "enabled", matchIfMissing = true):
matchIfMissing屬性:默認(rèn)情況下matchIfMissing為false,也就是說(shuō)如果未進(jìn)行屬性配置,則自動(dòng)配置不生效。如果matchIfMissing為true,則表示如果沒(méi)有對(duì)應(yīng)的屬性配置,則自動(dòng)配置默認(rèn)生效
4.2.@ConditionalOnMissingBean:
在@bean定義上,它的作用就是在容器加載它作用的bean時(shí),檢查容器中是否存在目標(biāo)類(lèi)型(ConditionalOnMissingBean注解的value值)的bean了,如果存在這跳過(guò)原始bean的BeanDefinition加載動(dòng)作。package com.zking.zzcloudspringbootstarter.config; import com.zking.zzcloudspringbootstarter.sms.SmsProperties; import com.zking.zzcloudspringbootstarter.sms.SmsServiceImpl; import com.zking.zzcloudspringbootstarter.sms.WebLogProperties; import com.zking.zzcloudspringbootstarter.weblog.WebLogAspect; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import javax.annotation.Resource; @Configuration //表示這個(gè)類(lèi)為配置類(lèi) @EnableConfigurationProperties({WebLogProperties.class}) @ConditionalOnProperty(prefix = "zzcloud.weblog",value = "enabled",matchIfMissing = true) public class WebLogAutoConfig { @Bean @ConditionalOnMissingBean public WebLogAspect webLogAspect(){ return new WebLogAspect(); } }
5.編寫(xiě)spring.factories文件加載自動(dòng)配置類(lèi)
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ com.zking.zzcloudspringbootstarter.config.SmsAutoConfig,\ com.zking.zzcloudspringbootstarter.config.WebLogAutoConfig
6.打包,操作同上
7.在其他項(xiàng)目中引用
7.1.導(dǎo)入依賴,由于這里我們使用的是之前的那個(gè)項(xiàng)目,這里就不需要重復(fù)導(dǎo)入依賴了
7.2.在application.yml文件中添加配置
?測(cè)試如下:這里我用該項(xiàng)目里的方法進(jìn)行測(cè)試
?如果我不使用日志,效果如下:
反之如果我使用日志,就會(huì)拿到我請(qǐng)求的路徑、我的客戶端以及我的參數(shù)值,效果如下:
?如果由以上效果,說(shuō)明我的案例二:AOP方式統(tǒng)一服務(wù)日志就成功了!
今天的學(xué)習(xí)記錄就到這了,拜拜!文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-427181.html
說(shuō)明:學(xué)習(xí)記錄,若有錯(cuò)誤,歡迎指正,若有疑問(wèn),歡迎評(píng)論? ??文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-427181.html
到了這里,關(guān)于SpringBoot之自定義starter的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!