帶你深入了解 SpringBoot 自動(dòng)配置原理及自定義Starter

1.SpringBoot自動(dòng)配置原理

從@SpringBootApplication注解開(kāi)始說(shuō)沧竟,這個(gè)注解是一個(gè)復(fù)合注解铸敏,他是由以下幾個(gè)注解構(gòu)成的。

// 用于講其他配置類(lèi)悟泵,注入到spring ioc中的

@SpringBootConfiguration

// 自動(dòng)配置最重要的注解

@EnableAutoConfiguration

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

@ComponentScan(

? ? excludeFilters = {@Filter(

? ? type = FilterType.CUSTOM,

? ? classes = {TypeExcludeFilter.class}

), @Filter(

? ? type = FilterType.CUSTOM,

? ? classes = {AutoConfigurationExcludeFilter.class}

)}

)


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

接下來(lái)從@EnableAutoConfiguration開(kāi)始講起


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

@Import({AutoConfigurationImportSelector.class})


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

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);

}

}


通過(guò)上述獲取在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中會(huì)存在很多這樣的鍵值對(duì)

# Auto Configure

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\

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

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


當(dāng)springboot啟動(dòng)的時(shí)候就會(huì)加載這些xxxAutoConfigureation,這里以RedisAutoConfiguration為例朽肥,介紹是如何進(jìn)行配置的禁筏。

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

@ConditionalOnClass({RedisOperations.class})

// 開(kāi)啟配置類(lèi)

@EnableConfigurationProperties({RedisProperties.class})

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

public class RedisAutoConfiguration {


RedisProperties配置類(lèi)衡招,看到這個(gè)類(lèi)篱昔,是不是很熟悉,他就是我們?cè)趛ml里面配置的東西

@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é):通過(guò)上述流程實(shí)現(xiàn)將快速配置蚁吝,減少了繁瑣的xml配置旱爆,如果要配置,只需簡(jiǎn)單的在yml配置即可窘茁。

2.自定義starter怀伦,簡(jiǎn)單實(shí)現(xiàn)一個(gè)線程池的創(chuàng)建

創(chuàng)建一個(gè)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>


自動(dòng)配置類(lèi)

@Configuration

// 配置配置屬性

@EnableConfigurationProperties(ThreadPoolExecutorProperties.class)

// 只有這個(gè)類(lèi)才會(huì)生校

@ConditionalOnClass(ThreadPoolExecutor.class)

public class ThreadPoolAutoConfiguration {

? ? /**

? ? * 阻塞隊(duì)列

? ? */

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

? ? /**

? ? * 拒絕策略

? ? */

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

? ? /**

? ? * 線程池類(lèi)型:CPU密集型:1;IO密集型:2

? ? */

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

? ? private Integer scenes;

? ? /**

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

? ? */

? ? private Integer corePoolSize;

? ? /**

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

? ? */

? ? private Integer maximumPoolSize;

? ? /**

? ? * 空閑線程存活時(shí)長(zhǎng)

? ? */

? ? private Long keepAliveTime;

? ? /**

? ? * 存活時(shí)長(zhǎng)單位

? ? */

? ? 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);

? ? }

}


配置類(lèi)屬性

@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

在另外的工程中引入上面的坐標(biāo)

<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é):通過(guò)上述配置自定義starter就可以實(shí)現(xiàn)了

總結(jié)

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

有需要的朋友可以加q群:580763979? ?備注:簡(jiǎn)書(shū)? ?免費(fèi)領(lǐng)取~

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末桑孩,一起剝皮案震驚了整個(gè)濱河市拜鹤,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌流椒,老刑警劉巖敏簿,帶你破解...
    沈念sama閱讀 206,968評(píng)論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異宣虾,居然都是意外死亡惯裕,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,601評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門(mén)绣硝,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)蜻势,“玉大人,你說(shuō)我怎么就攤上這事鹉胖∥章辏” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 153,220評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵甫菠,是天一觀的道長(zhǎng)挠铲。 經(jīng)常有香客問(wèn)我,道長(zhǎng)寂诱,這世上最難降的妖魔是什么市殷? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 55,416評(píng)論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮刹衫,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘搞挣。我一直安慰自己带迟,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,425評(píng)論 5 374
  • 文/花漫 我一把揭開(kāi)白布囱桨。 她就那樣靜靜地躺著仓犬,像睡著了一般。 火紅的嫁衣襯著肌膚如雪舍肠。 梳的紋絲不亂的頭發(fā)上搀继,一...
    開(kāi)封第一講書(shū)人閱讀 49,144評(píng)論 1 285
  • 那天,我揣著相機(jī)與錄音翠语,去河邊找鬼叽躯。 笑死,一個(gè)胖子當(dāng)著我的面吹牛肌括,可吹牛的內(nèi)容都是我干的点骑。 我是一名探鬼主播,決...
    沈念sama閱讀 38,432評(píng)論 3 401
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼黑滴!你這毒婦竟也來(lái)了憨募?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 37,088評(píng)論 0 261
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤袁辈,失蹤者是張志新(化名)和其女友劉穎菜谣,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體晚缩,經(jīng)...
    沈念sama閱讀 43,586評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡尾膊,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,028評(píng)論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了橡羞。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片眯停。...
    茶點(diǎn)故事閱讀 38,137評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖卿泽,靈堂內(nèi)的尸體忽然破棺而出莺债,到底是詐尸還是另有隱情,我是刑警寧澤签夭,帶...
    沈念sama閱讀 33,783評(píng)論 4 324
  • 正文 年R本政府宣布齐邦,位于F島的核電站,受9級(jí)特大地震影響第租,放射性物質(zhì)發(fā)生泄漏措拇。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,343評(píng)論 3 307
  • 文/蒙蒙 一慎宾、第九天 我趴在偏房一處隱蔽的房頂上張望丐吓。 院中可真熱鬧,春花似錦趟据、人聲如沸券犁。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,333評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)粘衬。三九已至,卻和暖如春咳促,著一層夾襖步出監(jiān)牢的瞬間稚新,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,559評(píng)論 1 262
  • 我被黑心中介騙來(lái)泰國(guó)打工跪腹, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留褂删,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,595評(píng)論 2 355
  • 正文 我出身青樓尺迂,卻偏偏與公主長(zhǎng)得像笤妙,于是被迫代替她去往敵國(guó)和親冒掌。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,901評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容