自定義springboot-starter揭秘自動(dòng)配置

使用springboot開發(fā)應(yīng)用已經(jīng)有一段時(shí)間了鹅搪,我們都沉醉于它簡(jiǎn)潔的配置和平滑的上手曲線。
在springboot的開發(fā)中遭铺,starter是一個(gè)核心的配置丽柿,只需要引入對(duì)應(yīng)模塊的starter,然后在application.properties中引入對(duì)應(yīng)的配置項(xiàng)魂挂,就可以開發(fā)業(yè)務(wù)邏輯了甫题。
這一切都?xì)w功于springboot的自動(dòng)配置的能力。
那么本文就讓我們基于Jedis客戶端封裝一個(gè)我們自己的簡(jiǎn)易版starter涂召,較為深入的了解一下springboot的自動(dòng)配置魔法坠非。

新建原型項(xiàng)目

首先讓我們新建一個(gè)maven項(xiàng)目,引入基礎(chǔ)依賴果正,核心依賴為

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter</artifactId>
</dependency>  

該依賴中包含的spring-boot-autoconfigure提供了自動(dòng)配置的功能炎码。
完整pom如下

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.snowalker</groupId>
    <artifactId>my-redis-starter</artifactId>
    <version>1.0.0</version>
    <packaging>jar</packaging>

    <name>my-redis-starter</name>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.5.3.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <!-- https://mvnrepository.com/artifact/redis.clients/jedis -->
        <dependency>
            <groupId>redis.clients</groupId>
            <artifactId>jedis</artifactId>
            <version>2.9.0</version>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>

1.配置參數(shù)映射RedisProperties

這里我們新建一個(gè)類,類名為RedisProperties秋泳,就是一個(gè)POJO類潦闲,目的是映射配置文件application.properties到實(shí)體的字段中。

@ConfigurationProperties(prefix = "redis.starter")
public class RedisProperties {

    private String host;
    private int port;

    public String getHost() {
        return host;
    }

    public void setHost(String host) {
        this.host = host;
    }

    public int getPort() {
        return port;
    }

    public void setPort(int port) {
        this.port = port;
    }
}

可以看到就是一個(gè)普通的POJO類迫皱,在類上添加注解 @ConfigurationProperties(prefix = “redis.starter”) 標(biāo)記當(dāng)前類為一個(gè)配置屬性類歉闰,對(duì)應(yīng)的配置文件中配置項(xiàng)的前綴為:redis.starter。

對(duì)于本例來講卓起,配置文件中對(duì)應(yīng)的完整配置項(xiàng)為:

redis.starter.host=xxx.xxx.xxx.xxx
redis.starter.port=xxxx

2.實(shí)現(xiàn)自動(dòng)化配置RedisAutoConfiguration.java

自動(dòng)化配置的核心就是提供實(shí)體bean的組裝和初始化和敬,對(duì)于本starter而言,我們主要組裝的核心bean就是 Jedis 這個(gè)實(shí)體戏阅。

@Configuration
@ConditionalOnClass(Jedis.class)    // 存在Jedis這個(gè)類才裝配當(dāng)前類
@EnableConfigurationProperties(RedisProperties.class)
public class RedisAutoConfiguration {


    @Bean
    @ConditionalOnMissingBean   // 沒有Jedis這個(gè)類才進(jìn)行裝配
    public Jedis jedis(RedisProperties redisProperties) {
        return new Jedis(redisProperties.getHost(), redisProperties.getPort());
    }
}

可以看到昼弟,我們這里通過@Bean注解組裝了一個(gè)Jedis的Bean,外界只需要通過注入即可使用饲握。

先解釋下幾個(gè)核心的注解:

@Configuration: 聲明當(dāng)前類為一個(gè)配置類
@ConditionalOnClass(Jedis.class):當(dāng)SpringIoc容器內(nèi)存在Jedis這個(gè)Bean時(shí)才裝配當(dāng)前配置類
@EnableConfigurationProperties(RedisProperties.class):這是一個(gè)開啟使用配置參數(shù)的注解私杜,value值就是我們配置實(shí)體參數(shù)映射的ClassType,將配置實(shí)體作為配置來源救欧。
@ConditionalOnMissingBean:當(dāng)SpringIoc容器內(nèi)不存在Jedis這個(gè)Bean的時(shí)候才進(jìn)行裝配,否則不裝配锣光。

Starter自動(dòng)化運(yùn)作原理

我們開發(fā)springboot應(yīng)用的時(shí)候都知道要在啟動(dòng)類加注解:@SpringBootApplication

在注解@SpringBootApplication上存在一個(gè)開啟自動(dòng)化配置的注解@EnableAutoConfiguration來完成自動(dòng)化配置笆怠,注解源碼如下所示:

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import({EnableAutoConfigurationImportSelector.class})
public @interface EnableAutoConfiguration {
    String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";

    Class<?>[] exclude() default {};

    String[] excludeName() default {};
}

在@EnableAutoConfiguration注解內(nèi)使用到了@import注解來完成導(dǎo)入配置的功能,
而EnableAutoConfigurationImportSelector內(nèi)部則是使用了SpringFactoriesLoader.loadFactoryNames方法進(jìn)行掃描具有META-INF/spring.factories文件的jar包誊爹。

先來看下spring-boot-autoconfigure包內(nèi)的spring.factories文件內(nèi)容蹬刷,如下所示:

# Initializers
org.springframework.context.ApplicationContextInitializer=\
org.springframework.boot.autoconfigure.SharedMetadataReaderFactoryContextInitializer,\
org.springframework.boot.autoconfigure.logging.AutoConfigurationReportLoggingInitializer

# Application Listeners
org.springframework.context.ApplicationListener=\
org.springframework.boot.autoconfigure.BackgroundPreinitializer

# Auto Configuration Import Listeners
org.springframework.boot.autoconfigure.AutoConfigurationImportListener=\
org.springframework.boot.autoconfigure.condition.ConditionEvaluationReportAutoConfigurationImportListener

# Auto Configuration Import Filters
org.springframework.boot.autoconfigure.AutoConfigurationImportFilter=\
org.springframework.boot.autoconfigure.condition.OnClassCondition

# Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration,\
org.springframework.boot.autoconfigure.aop.AopAutoConfiguration,\
.....省略

可以看到配置的結(jié)構(gòu)形式是Key/Value形式瓢捉,如果存在多個(gè)Value時(shí)則使用,隔開,那我們?cè)谧远xstarter內(nèi)也可以使用這種形式來完成办成,因?yàn)槲覀兊哪康氖菫榱送瓿勺詣?dòng)化配置泡态,所以我們這里Key則是需要使用org.springframework.boot.autoconfigure.EnableAutoConfiguration

3.自定義spring.factories

自定義spring.factories的步驟很簡(jiǎn)單,只需要在src/main/resource目錄下創(chuàng)建META-INF目錄,并在該目錄下添加文件spring.factories迂卢,文件內(nèi)容為:

org.springframework.boot.autoconfigure.EnableAutoConfiguration=
com.snowalker.demo.redis.RedisAutoConfiguration

到這里某弦,我們自定義my-redis-starter的步驟已經(jīng)完成,那么就讓我們建立一個(gè)測(cè)試項(xiàng)目來測(cè)試一下這個(gè)starter是否有效而克。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末靶壮,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子员萍,更是在濱河造成了極大的恐慌腾降,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,496評(píng)論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件碎绎,死亡現(xiàn)場(chǎng)離奇詭異螃壤,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)筋帖,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,407評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門奸晴,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人幕随,你說我怎么就攤上這事蚁滋。” “怎么了赘淮?”我有些...
    開封第一講書人閱讀 162,632評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵辕录,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我梢卸,道長(zhǎng)走诞,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,180評(píng)論 1 292
  • 正文 為了忘掉前任蛤高,我火速辦了婚禮蚣旱,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘戴陡。我一直安慰自己塞绿,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,198評(píng)論 6 388
  • 文/花漫 我一把揭開白布恤批。 她就那樣靜靜地躺著异吻,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上诀浪,一...
    開封第一講書人閱讀 51,165評(píng)論 1 299
  • 那天棋返,我揣著相機(jī)與錄音,去河邊找鬼雷猪。 笑死睛竣,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的求摇。 我是一名探鬼主播射沟,決...
    沈念sama閱讀 40,052評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼月帝!你這毒婦竟也來了躏惋?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,910評(píng)論 0 274
  • 序言:老撾萬榮一對(duì)情侶失蹤嚷辅,失蹤者是張志新(化名)和其女友劉穎簿姨,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體簸搞,經(jīng)...
    沈念sama閱讀 45,324評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡扁位,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,542評(píng)論 2 332
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了趁俊。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片域仇。...
    茶點(diǎn)故事閱讀 39,711評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖寺擂,靈堂內(nèi)的尸體忽然破棺而出暇务,到底是詐尸還是另有隱情,我是刑警寧澤怔软,帶...
    沈念sama閱讀 35,424評(píng)論 5 343
  • 正文 年R本政府宣布垦细,位于F島的核電站,受9級(jí)特大地震影響挡逼,放射性物質(zhì)發(fā)生泄漏括改。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,017評(píng)論 3 326
  • 文/蒙蒙 一家坎、第九天 我趴在偏房一處隱蔽的房頂上張望嘱能。 院中可真熱鬧,春花似錦虱疏、人聲如沸惹骂。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,668評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽析苫。三九已至,卻和暖如春穿扳,著一層夾襖步出監(jiān)牢的瞬間衩侥,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,823評(píng)論 1 269
  • 我被黑心中介騙來泰國(guó)打工矛物, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留茫死,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,722評(píng)論 2 368
  • 正文 我出身青樓履羞,卻偏偏與公主長(zhǎng)得像峦萎,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子忆首,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,611評(píng)論 2 353

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