我們知道SpringBoot Starter也就是啟動器。是SpringBoot元件化的一大優點。基於這個思想,基於這個思想SpringBoot 才變得非常強大,官方給我們提供很多開箱即用的啟動器。
Spring Boot Starter 是 Spring Boot 的一個重要特性,它有以下優點:
依賴管理:Starter 自動處理專案的依賴關係,使得開發者無需手動新增和管理每個依賴。
自動設定:Starter 提供了一種自動設定的方式,可以根據你的 classpath 和你定義的屬性自動設定 Spring 應用。
簡化開發:通過提供各種服務的 Starter(如資料庫、安全、快取等),極大地簡化了開發過程。
減少樣板程式碼:由於 Starter 的自動設定和依賴管理,開發者可以專注於業務邏輯,而不是設定和基礎設施程式碼。
快速原型開發:使用 Starter 可以快速建立可執行的原型。
易於理解和使用:Spring Boot Starter 的設計目標之一就是讓非專業的開發者也能快速上手。
社群支援:除了官方提供的 Starter,還有大量的社群提供的 Starter,可以滿足各種特定需求。
我現在手把手教大家如何封裝自己的starter 做自己的springboot元件,當然你也可以釋出自己的starter 到maven中央倉庫供大家使用
我們以WebMvcAutoConfiguration這個自動載入為例
自動設定類要能載入,有一個要求,原始碼分析結果是,需要在\META-INF\spring.factories中做如下設定
# Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration,\
org.springframework.boot.autoconfigure.aop.AopAutoConfiguration,\
這樣SpringBoot在啟動完成時候,會找到我們引入,的starter 找到\META-INF\spring.factories
屬性檔案,找到需要自動載入設定的類路徑,然後幫我們自動注入到Spring IOC 容器,我們在專案中就可以直接使用了。
這裡實現自動載入還要依賴一些註解如:
@Configuration // 指定這個類是個設定類
@ConditionalOnXXX // 在指定條件成立的情況下自動設定類生效
@AutoConfigureOrder //設定類順序
@AutoConfigureAfter // 在哪個設定類之後
@Bean //給容器中新增元件
@ConfigurationProperties //結合相關的XXXProperties類 來繫結相關的設定
@EnableConfigurationProperties // 讓XXXProperties加入到容器中,別人就可以自動裝配
剖析了SpringBoot 官方的starter 我們自定義自己的starter,(我們仿照著寫)
如果自定義屬性檔案中,需要IDEA智慧提示需要引入
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
這裡我以自己封裝總結我工作以來總結專案封裝的一個SpringBoot starter為例
<dependency>
<groupId>cn.soboys</groupId>
<artifactId>rest-api-spring-boot-starter</artifactId>
<version>1.2.0</version>
</dependency>
就是我自己封裝的start。已經發布中央倉庫。
目前更新版本1.3.0 功能如下
rest-api-spring-boot-starter
倉庫地址
github
rest-api:
enabled: false
logging:
path: ./logs
i18n:
# 若前端無header傳參則返回中文資訊
i18n-header: Lang
default-lang: cn
message:
# admin
internal_server_error:
en: Internal Server Error
cn: 系統錯誤
not_found:
en: Not Found
cn: 請求資源不存在
package cn.soboys.restapispringbootstarter.i18n;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Configuration;
import java.util.Map;
import java.util.Optional;
/**
* @author 公眾號 程式設計師三時
* @version 1.0
* @date 2023/6/26 11:55
* @webSite https://github.com/coder-amiao
*/
//@PropertySource(value = "classpath:i18n.yaml", factory = YamlPropertySourceFactory.class)
@Configuration
@ConfigurationProperties(prefix = "rest-api.i18n")
@Data
public class I18NMessage {
/**
* message-key:<lang:message>
*/
private Map<String, Map<String, String>> message;
/**
* Default language setting (Default "cn").
*/
private String defaultLang = "cn";
private String i18nHeader = "Lang";
/**
* get i18n message
*
* @param key
* @param language
* @return
*/
public String message(I18NKey key, String language) {
return Optional.ofNullable(message.get(key.key()))
.map(map -> map.get(language == null ? defaultLang : language))
.orElse(key.key());
}
/**
* get i18n message
*
* @param key
* @param language
* @return
*/
public String message(String key, String language) {
return Optional.ofNullable(message.get(key))
.map(map -> map.get(language == null ? defaultLang : language))
.orElse(key);
}
}
package cn.soboys.restapispringbootstarter.config;
import cn.soboys.restapispringbootstarter.ApplicationRunner;
import cn.soboys.restapispringbootstarter.ExceptionHandler;
import cn.soboys.restapispringbootstarter.ResultHandler;
import cn.soboys.restapispringbootstarter.aop.LimitAspect;
import cn.soboys.restapispringbootstarter.i18n.I18NMessage;
import cn.soboys.restapispringbootstarter.utils.RedisTempUtil;
import cn.soboys.restapispringbootstarter.utils.RestFulTemp;
import org.springframework.boot.autoconfigure.ImportAutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.client.ClientHttpRequestFactory;
import org.springframework.http.client.SimpleClientHttpRequestFactory;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.StringHttpMessageConverter;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.http.converter.support.AllEncompassingFormHttpMessageConverter;
import org.springframework.web.client.RestTemplate;
import java.nio.charset.Charset;
import java.util.List;
/**
* @author 公眾號 程式設計師三時
* @version 1.0
* @date 2023/6/27 11:36
* @webSite https://github.com/coder-amiao
*/
@Configuration
@ConditionalOnProperty(name = "rest-api.enabled", havingValue = "true")
public class BeanAutoConfiguration {
@Bean
public I18NMessage i18NMessage() {
return new I18NMessage();
}
@Bean
public ResultHandler resultHandler() {
return new ResultHandler();
}
@Bean
public ExceptionHandler exceptionHandler() {
return new ExceptionHandler();
}
@Bean
public StartupApplicationListener startupApplicationListener() {
return new StartupApplicationListener();
}
@Bean
public RestApiProperties restApiProperties() {
return new RestApiProperties();
}
@Bean
public RestApiProperties.LoggingProperties loggingProperties(RestApiProperties restApiProperties) {
return restApiProperties.new LoggingProperties();
}
@Bean
public ApplicationRunner applicationRunner() {
return new ApplicationRunner();
}
/**
* restTemplate 自動注入
*/
@Configuration
@ConditionalOnProperty(name = "rest-api.enabled", havingValue = "true")
class RestTemplateConfig {
/**
* 第三方請求要求的預設編碼
*/
private final Charset thirdRequest = Charset.forName("utf-8");
@Bean
public RestTemplate restTemplate(ClientHttpRequestFactory factory) {
RestTemplate restTemplate = new RestTemplate(factory);
// 處理請求中文亂碼問題
List<HttpMessageConverter<?>> messageConverters = restTemplate.getMessageConverters();
for (HttpMessageConverter<?> messageConverter : messageConverters) {
if (messageConverter instanceof StringHttpMessageConverter) {
((StringHttpMessageConverter) messageConverter).setDefaultCharset(thirdRequest);
}
if (messageConverter instanceof MappingJackson2HttpMessageConverter) {
((MappingJackson2HttpMessageConverter) messageConverter).setDefaultCharset(thirdRequest);
}
if (messageConverter instanceof AllEncompassingFormHttpMessageConverter) {
((AllEncompassingFormHttpMessageConverter) messageConverter).setCharset(thirdRequest);
}
}
return restTemplate;
}
@Bean
public ClientHttpRequestFactory simpleClientHttpRequestFactory() {
SimpleClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory();
factory.setConnectTimeout(15000);
factory.setReadTimeout(5000);
return factory;
}
@Bean
public RestFulTemp restFulTemp() {
return new RestFulTemp();
}
}
}
spring.factories
設定自己載入設定類
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
cn.soboys.restapispringbootstarter.config.BeanAutoConfiguration,\
cn.soboys.restapispringbootstarter.config.BeanAutoConfiguration.RestTemplateConfig,\
cn.soboys.restapispringbootstarter.utils.RedisTempUtil\
擴充套件思考,我們可以看到SpringBoot官方stater 很多啟用都類似
@Enablexxx
註解
這個怎麼實現。我的rest-api-spring-boot-starter
1.3.0已經實現不需要在application.properties設定一行 直接在啟動類或者設定類使用EnableRestFullApi
就可以使用全部功能
完善檔案使用可以看我
SpringBoot定義優雅全域性統一Restful API 響應框架完結撒花篇封裝starter元件
這篇文章
到此自己定義starter就寫完了 接下來就是打包,釋出到maven中央倉庫。
我會在 下一篇文章繼續分享
留下你的思考,關注公眾 程式設計師三時
持續輸出優質內容 希望給你帶來一點啟發和幫助