帶你深入了解 SpringBoot 自動配置原理及自定義Starter

1.SpringBoot自動配置原理

從@SpringBootApplication注解開始說,這個注解是一個復合注解,他是由以下幾個注解構(gòu)成的。

// 用于講其他配置類,注入到spring ioc中的

@SpringBootConfiguration

// 自動配置最重要的注解

@EnableAutoConfiguration

// 用于掃描其他注解(@service、@controller)等等

@ComponentScan(

? ? excludeFilters = {@Filter(

? ? type = FilterType.CUSTOM,

? ? classes = {TypeExcludeFilter.class}

), @Filter(

? ? type = FilterType.CUSTOM,

? ? classes = {AutoConfigurationExcludeFilter.class}

)}

)


記得點贊收藏加關(guān)注哦 ,需要下載PDF版本和獲取更多知識點、面試題的朋友可以加q群:580763979? ?備注:簡書? ?免費領(lǐng)取~

接下來從@EnableAutoConfiguration開始講起


其中關(guān)鍵的地方就是這個AutoConfigurationImportSelector類

@Import({AutoConfigurationImportSelector.class})


他里面的selectImports方法中g(shù)etAutoConfigurationEntry就是獲取自動配置的重要組成

public String[] selectImports(AnnotationMetadata annotationMetadata) {

if (!this.isEnabled(annotationMetadata)) {

? ? return NO_IMPORTS;

} else {

? ? AutoConfigurationImportSelector.AutoConfigurationEntry autoConfigurationEntry = this.getAutoConfigurationEntry(annotationMetadata);

? ? return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());

}

}

protected AutoConfigurationImportSelector.AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {

if (!this.isEnabled(annotationMetadata)) {

? ? return EMPTY_ENTRY;

} else {

? ? AnnotationAttributes attributes = this.getAttributes(annotationMetadata);

? ? List<String> configurations = this.getCandidateConfigurations(annotationMetadata, attributes);

? ? configurations = this.removeDuplicates(configurations);

? ? Set<String> exclusions = this.getExclusions(annotationMetadata, attributes);

? ? this.checkExcludedClasses(configurations, exclusions);

? ? configurations.removeAll(exclusions);

? ? configurations = this.getConfigurationClassFilter().filter(configurations);

? ? this.fireAutoConfigurationImportEvents(configurations, exclusions);

? ? return new AutoConfigurationImportSelector.AutoConfigurationEntry(configurations, exclusions);

}

}


通過上述獲取在META-INF/spring.factories,

protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {

? ? List<String> configurations = SpringFactoriesLoader.loadFactoryNames(this.getSpringFactoriesLoaderFactoryClass(), this.getBeanClassLoader());

? ? Assert.notEmpty(configurations, "No auto configuration classes found in META-INF/spring.factories. If you are using a custom packaging, make sure that file is correct.");

? ? return configurations;

}


在spring.factories中會存在很多這樣的鍵值對

# Auto Configure

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\

org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration,\

org.springframework.boot.autoconfigure.aop.AopAutoConfiguration,\


當springboot啟動的時候就會加載這些xxxAutoConfigureation,這里以RedisAutoConfiguration為例,介紹是如何進行配置的。

// 只有符合這種要求的,才會將xxxAutoConfigureation加載到spring中

@ConditionalOnClass({RedisOperations.class})

// 開啟配置類

@EnableConfigurationProperties({RedisProperties.class})

@Import({LettuceConnectionConfiguration.class, JedisConnectionConfiguration.class})

public class RedisAutoConfiguration {


RedisProperties配置類,看到這個類,是不是很熟悉,他就是我們在yml里面配置的東西

@ConfigurationProperties(

? ? prefix = "spring.redis"

)

public class RedisProperties {

? ? private int database = 0;

? ? private String url;

? ? private String host = "localhost";

? ? private String username;

? ? private String password;

? ? private int port = 6379;

? ? private boolean ssl;

? ? private Duration timeout;

? ? private Duration connectTimeout;

? ? private String clientName;

}


總結(jié):通過上述流程實現(xiàn)將快速配置,減少了繁瑣的xml配置,如果要配置,只需簡單的在yml配置即可。

2.自定義starter,簡單實現(xiàn)一個線程池的創(chuàng)建

創(chuàng)建一個thread-pool-execute-starter的工程

// 添加依賴

<groupId>com.angel.item</groupId>

<artifactId>thread-pool-execute-starter</artifactId>

<version>1.0</version>

<dependencies>

? ? <dependency>

? ? ? ? <groupId>org.springframework.boot</groupId>

? ? ? ? <artifactId>spring-boot-starter</artifactId>

? ? </dependency>

</dependencies>


自動配置類

@Configuration

// 配置配置屬性

@EnableConfigurationProperties(ThreadPoolExecutorProperties.class)

// 只有這個類才會生校

@ConditionalOnClass(ThreadPoolExecutor.class)

public class ThreadPoolAutoConfiguration {

? ? /**

? ? * 阻塞隊列

? ? */

? ? private final BlockingQueue<Runnable> workQueue = new ArrayBlockingQueue<>(4);

? ? /**

? ? * 拒絕策略

? ? */

? ? private final RejectedExecutionHandler reject = new ThreadPoolExecutor.AbortPolicy();

? ? /**

? ? * 線程池類型:CPU密集型:1;IO密集型:2

? ? */

? ? @Value("${scenes}")

? ? private Integer scenes;

? ? /**

? ? * 核心線程數(shù)大小

? ? */

? ? private Integer corePoolSize;

? ? /**

? ? * 最大線程數(shù)大小

? ? */

? ? private Integer maximumPoolSize;

? ? /**

? ? * 空閑線程存活時長

? ? */

? ? private Long keepAliveTime;

? ? /**

? ? * 存活時長單位

? ? */

? ? private TimeUnit unit;

? ? @PostConstruct

? ? public void init() {

? ? ? ? // 獲取系統(tǒng)CPU核心數(shù)

? ? ? ? int cpuCoreNumber = Runtime.getRuntime().availableProcessors();

? ? ? ? this.corePoolSize = cpuCoreNumber;

? ? ? ? this.maximumPoolSize = 25 * cpuCoreNumber;

? ? ? ? this.keepAliveTime = 60 * 3L;

? ? ? ? this.unit = TimeUnit.SECONDS;

? ? }

? ? /**

? ? * N: CPU核心數(shù)

? ? * CPU密集型:corePoolSize = N + 1

? ? * IO密集型:corePoolSize = 2 * N

? ? */

? ? @Bean

? ? public ThreadPoolExecutor threadPoolExecutor() {

? ? ? ? // cpu密集型

? ? ? ? if (scenes == 1) {

? ? ? ? ? ? corePoolSize = corePoolSize + 1;

? ? ? ? } else {

? ? ? ? ? ? // io密集型

? ? ? ? ? ? corePoolSize = 2 * corePoolSize;

? ? ? ? }

? ? ? ? return new ThreadPoolExecutor(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, reject);

? ? }

}


配置類屬性

@ConfigurationProperties(

? ? ? ? prefix = "thread.pool"

)

public class ThreadPoolExecutorProperties {

? ? private Integer scenes = 1;

? ? public Integer getScenes() {

? ? ? ? return scenes;

? ? }

? ? public void setScenes(Integer scenes) {

? ? ? ? this.scenes = scenes;

? ? }

}


在resources中新建META-INF/spring.factories

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\

com.angel.item.ThreadPoolAutoConfiguration


將工程重新打包,mvn clean install -U

在另外的工程中引入上面的坐標

<dependency>

? ? <groupId>com.angel.item</groupId>

? ? <artifactId>thread-pool-execute-starter</artifactId>

? ? <version>1.0</version>

</dependency>


在yml配置即可

thread:

? pool:

? ? scenes: 1


mvn package 重新打包

總結(jié):通過上述配置自定義starter就可以實現(xiàn)了

總結(jié)

我這里也準備了一線大廠面試資料和超硬核PDF技術(shù)文檔,以及我為大家精心準備的多套簡歷模板(不斷更新中),希望大家都能找到心儀的工作!

有需要的朋友可以加q群:580763979? ?備注:簡書? ?免費領(lǐng)取~

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容