新聞中心
1、本篇前言
Spring Boot為我們提供了簡化企業(yè)級開發(fā)絕大多數(shù)場景的
starter pom【比如springb-boot-starter-web,springb-boot-starter-jdbc等】, 使用應用場景所需要的starter pom,只需要引入對應的starter,即可以得到Spring Boot為我們提供的自動配置的Bean。
然而,可能在很多情況下,我們需要自定義stater,這樣可以方便公司內部系統(tǒng)調用共同的配置模塊的時候可以自動進行裝載配置。比如公司的很多內部系統(tǒng)都有認證授權模塊、以及基于AOP實現(xiàn)的日志切面等,這些技術在不同的項目中邏輯基本相同,而這些功能可以通過starter自動配置的形式進行配置,即可達到可復用的效果。

專注于為中小企業(yè)提供網站制作、成都做網站服務,電腦端+手機端+微信端的三站合一,更高效的管理,為中小企業(yè)良慶免費做網站提供優(yōu)質的服務。我們立足成都,凝聚了一批互聯(lián)網行業(yè)人才,有力地推動了成百上千企業(yè)的穩(wěn)健成長,幫助中小企業(yè)通過網站建設實現(xiàn)規(guī)模擴充和轉變。
(1)Starter的概念
SpringBoot之所以大大地簡化了我們的開發(fā),用到的一個很重要的技術就是Starter機制!
Starter機制拋棄了以前xml中繁雜的配置,將各種配置統(tǒng)一集成進了Starter中,開發(fā)人員只需要在maven中引入Starter依賴,SpringBoot就能自動掃描出要加載的配置信息并按相應的默認配置來啟動項目。
所以Starter可以理解為一個可拔插式的插件,提供了一系列便利的依賴描述符,使得我們可以獲得所需的所有Spring和相關技術的一站式服務。應用程序只需要在maven中引入Starter依賴,SpringBoot就能自動掃描到要加載的信息并啟動相應的默認配置,我們可以把Starter看做是Springboot的場景啟動器。
(2)Starter的優(yōu)點
- Starter可以讓我們擺脫開發(fā)過程中對各種依賴庫的沖突處理。
- 可以簡化原有xml中各種負載的配置信息。
- SpringBoot提供了針對一般研發(fā)中各種場景的spring-boot-starter依賴,所有這些依賴模塊都遵循著約定成俗的默認配置(”約定大于配置“),并允許我們調整這些配置。Starter的出現(xiàn)極大的幫助開發(fā)者們從繁瑣的框架配置中解放出來,從而更專注于業(yè)務代碼。
(3)自定義Starter的場景
在我們的日常開發(fā)工作中,經常會有一些獨立于業(yè)務之外的配置模塊,我們經常將其放到一個特定的包下,然后如果另一個工程需要復用這塊功能的時候,只需要將其在pom中引用依賴即可,利用SpringBoot為我們完成自動裝配即可。
常見的自定義Starter場景比如:
- 動態(tài)數(shù)據源
- 登錄模塊
- 基于AOP技術實現(xiàn)日志切面
- …
(4)自定義Starter命名規(guī)范
SpringBoot官方建議其官方推出的starter以spring-boot-starter-xxx的格式來命名,而第三方開發(fā)者自定義的starter則以xxxx-spring-boot-starter的規(guī)則來命名,比如 mybatis-spring-boot-starter。
(5)自定義starter中幾個重要注解
- @Configuration: 表明此類是一個配置類,將變?yōu)橐粋€bean被Spring進行管理。
- @EnableConfigurationProperties: 啟用屬性配置,將讀取指定類里面的屬性。
- @ConditionalOnClass: 當類路徑下面有指定的類時,進行自動配置。
- @ConditionalOnProperty: 判斷指定的屬性是否具備指定的值。
- @ConditionalOnMissingBean:當容器中沒有指定bean是,創(chuàng)建此bean。
- @Import: 引入其他的配置類
2、自定義Starter記錄日志案例
(1)項目結構
兩個工程如下:log-spring-boot-starter[starter模塊],spring-boot-demo-starter-test[starter使用演示工程]。
(2)log-spring-boot-starter項目pom文件添加依賴
org.springframework.boot
spring-boot-starter
org.springframework.boot
spring-boot-configuration-processor
true
org.springframework.boot
spring-boot-starter-web
org.projectlombok
lombok
true
org.springframework.boot
spring-boot-starter-test
test
(3)編寫請求日志注解
/**
* 功能描述: 請求日志注解
* @author TuYong
* @date 2022/9/7 20:48
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface RequestLog {
//接口方法上的描述信息
String desc() default "";
}
(4)編寫配置類
@Setter
@Getter
@ConfigurationProperties(prefix = "request.log")
public class LogProperties {
private Boolean enabled = Boolean.FALSE;
}
(5)編寫日志攔截器
/**
* 功能描述: 日志攔截器
* @author TuYong
* @date 2022/9/7 20:49
*/
@Slf4j
public class LogInterceptor implements HandlerInterceptor {
private static final ThreadLocalTHREAD_LOCAL = new ThreadLocal<>();
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
HandlerMethod handlerMethod = (HandlerMethod) handler;
RequestLog methodAnnotation = handlerMethod.getMethodAnnotation(RequestLog.class);
if(methodAnnotation != null){
long start = System.currentTimeMillis();
THREAD_LOCAL.set(start);
}
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
HandlerMethod handlerMethod = (HandlerMethod) handler;
RequestLog methodAnnotation = handlerMethod.getMethodAnnotation(RequestLog.class);
if(methodAnnotation != null){
Method method = handlerMethod.getMethod();
String requestUri = request.getRequestURI();
String methodName = method.getDeclaringClass().getName()+":"+method.getName();
String desc = methodAnnotation.desc();
long end = System.currentTimeMillis();
long start = THREAD_LOCAL.get();
long l = end - start;
THREAD_LOCAL.remove();
log.info("請求路徑:{},請求方法:{},描述信息:{},總計耗時:{}",requestUri,methodName,desc,l);
}
}
}
(6)編寫自動配置類
/**
* 功能描述: 自動配置
* @author TuYong
* @date 2022/9/7 20:55
*/
@Configuration
@EnableConfigurationProperties({LogProperties.class})
@ConditionalOnProperty(
prefix = "request.log",
name = {"enabled"},
havingValue = "true"
)
public class LogAutoConfiguration implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new LogInterceptor()).addPathPatterns("/api/**");
WebMvcConfigurer.super.addInterceptors(registry);
}
}
(7)編寫spring.factories
在resources/META-INF/下建立spring.factories文件,配置自動裝配類路徑
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
cn.javaxxw.springboot.LogAutoConfiguration
(8)創(chuàng)建starter演示工程引入starter依賴
cn.javaxxw
log-spring-boot-starter
0.0.1-SNAPSHOT
org.springframework.boot
spring-boot-starter-web
(9)編寫測試接口并使用starter中定義的注解
@RestController
@RequestMapping("api")
public class ApiController {
@GetMapping("test")
@RequestLog(desc = "測試接口")
public Object test(){
return "test api!";
}
}
(10)配置文件
server:
port: 8080
# 開啟starter組件
request:
log:
enabled: true
(11)功能測試
通過請求測試接口,我們可以看到starter中的攔截器已經生效
(12)演示工程代碼
gitee: https://gitee.com/trazen/springboot-demo.git
3、原理解析
第二章節(jié)中的開發(fā)流程,有兩個地方需要我們了解一下:
(1)starter的自動識別加載:spring.factories里的EnableAutoConfiguration原理。
(2)實現(xiàn)自動加載的智能化、可配置化:@Configuration配置類里注解。
(1)配置類自動加載機制
在SpringBoot的啟動類都會加上@SpringBootApplication注解。這個注解會引入@EnableAutoConfiguration注解。然后@EnableAutoConfiguration會@Import(AutoConfigurationImportSelector.class)。
AutoConfigurationImportSelector.class的selectImports方法最終會通過SpringFactoriesLoader.loadFactoryNames,加載META-INF/spring.factories里的EnableAutoConfiguration配置值,也就是我們上文中設置的資源文件。
(2)自動加載的智能化可配置化
實際項目中,我們并不總是希望使用默認配置。比如有時候我想自己配置相關功能,或者只有某些bean沒有被加載時才會加載starter配置類。這些常見的場景Starter都可以實現(xiàn),并提供了如下的解決方案:
@Conditional*注解
springboot starter提供了一系列的@Conditional*注解,代表什么時候啟用對應的配置,具體的可以去查看springboot的官方文檔。常用注解如下:
- @ConditionalOnBean:當容器里有指定的Bean的條件下。
- @ConditionalOnClass: 當類路徑下面有指定的類時,進行自動配置。
- @ConditionalOnProperty: 判斷指定的屬性是否具備指定的值。
- @ConditionalOnMissingBean:當容器中沒有指定bean是,創(chuàng)建此bean。
比如我們案例中的 @ConditionalOnProperty(prefix = "request.log", name = {"enabled"},havingValue = "true") ,只有在應用配置 request.log.enabled = true 時該請求日志攔截功能才會生效。
@ConfigurationProperties注解
這個注解主要是為了解決如下場景:我想要使用starter的默認配置類,但是又想對配置中的某些參數(shù)進行自定義配置。@ConfigurationProperties類就是做這個工作的。例如上述例子中,我們在配置中使用enabled參數(shù)來決定是否啟動該組件的日志攔截功能。
文章名稱:進階篇-SpringBoot2.x自定義starter啟動器
本文網址:http://fisionsoft.com.cn/article/ccchsdj.html


咨詢
建站咨詢
