朱曄和你聊Spring系列S1E2:SpringBoot並不神祕

朱曄和你聊Spring系列S1E2:SpringBoot並不神祕

 【編輯器丟失了全部代碼的高亮,建議查看PDF格式文檔java

文本咱們會一步一步作一個例子來看看SpringBoot的自動配置是如何實現的,而後來看一些SpringBoot留給咱們的擴展點。react

 

本身製做一個SpringBoot Starter

 

咱們知道SpringBoot提供了很是多的啓動器,引入了啓動器依賴便可直接享受到自動依賴配置和自動屬性配置:git

 

https://github.com/spring-projects/spring-boot/tree/master/spring-boot-project/spring-boot-startersgithub

在第一篇文章中我提到,在SpringBoot出現以前,咱們須要使用SpringMVC、Spring Data、Spring Core都須要對Spring內部的各類組件進行Bean以及Bean依賴的配置,在90%的時候咱們用的是默認的配置,不會自定義任何擴展類,這個時候也須要由使用者來手動配置顯然不合理,有了SpringBoot,咱們只需引入啓動器依賴,而後啓動器就能夠本身作爲本身的一些內部組件作自動配置,大大方便了使用者。啓動器的實現很是簡單,咱們來看下實現過程。web

首先建立一個Maven空項目,引入SpringBoot:redis

<?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>me.josephzhu</groupId>
    <artifactId>spring101</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>jar</packaging>

    <name>spring101</name>
    <description></description>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.0.5.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.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>


</project>

 

 

而後咱們建立一個Starter模塊隸屬於父項目:spring

<?xml version="1.0" encoding="UTF-8"?>

<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0"

         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>me.josephzhu</groupId>

    <artifactId>spring101-customstarter</artifactId>

    <version>0.0.1-SNAPSHOT</version>

    <packaging>jar</packaging>



    <name>spring101-customstarter</name>

    <description></description>



    <parent>

        <groupId>me.josephzhu</groupId>

        <artifactId>spring101</artifactId>

        <version>0.0.1-SNAPSHOT</version>

    </parent>



    <dependencies>

        <dependency>

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

            <artifactId>spring-boot-autoconfigure</artifactId>

        </dependency>

    </dependencies>



</project>

 

 

接下去咱們建立一個服務抽象基類和實現,這個服務很是簡單,會依賴到一些屬性,而後會有不一樣的實現(無參構造函數設置了打招呼用語的默認值爲Hello):數據庫

package me.josephzhu.spring101customstarter;



import org.springframework.beans.factory.annotation.Autowired;



public abstract class AbstractMyService {



    protected String word;

    public AbstractMyService(String word) {

        this.word = word;

    }



    public AbstractMyService() {

        this ("Hello");

    }



    @Autowired

    protected MyServiceProperties properties;



    public abstract String hello();

}

 

這裏注入了自定義屬性類:apache

package me.josephzhu.spring101customstarter;



import lombok.Data;

import org.springframework.boot.context.properties.ConfigurationProperties;



@ConfigurationProperties(prefix = "spring101")

@Data

public class MyServiceProperties {

    /**

     * user name

     */

    private String name;

    /**

     * user age *Should between 1 and 120

     */

    private Integer age;

    /**

     * determine the service version you want use

     */

    private String version;

}

 

這裏看到了若是咱們須要定義一個自定義類來關聯配置源(好比application.properties文件配置)是多麼簡單,使用@ConfigurationProperties註解標註咱們的POJO告知註解咱們配置的前綴便可。額外提一句,若是但願咱們的IDE能夠針對自定義配置有提示的話(自動完成,並且帶上註解中的提示語),能夠引入以下的依賴:json

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-configuration-processor</artifactId>
    <optional>true</optional>
</dependency>

這樣編譯後就會在META-INF下面生成一個叫作spring-configuration-metadata.json的文件:

{
  "hints": [],
  "groups": [
    {
      "sourceType": "me.josephzhu.spring101customstarter.MyServiceProperties",
      "name": "spring101",
      "type": "me.josephzhu.spring101customstarter.MyServiceProperties"
   
}
  ],
  "properties": [
    {
      "sourceType": "me.josephzhu.spring101customstarter.MyServiceProperties",
      "name": "spring101.age",
      "description": "user age *Should between 1 and 120",
      "type": "java.lang.Integer"
   
},
    {
      "sourceType": "me.josephzhu.spring101customstarter.MyServiceProperties",
      "name": "spring101.name",
      "description": "user name",
      "type": "java.lang.String"
   
},
    {
      "sourceType": "me.josephzhu.spring101customstarter.MyServiceProperties",
      "name": "spring101.version",
      "description": "determine the service version you want use",
      "type": "java.lang.String"
   
}
  ]
}

以後在使用配置的時候就能夠有提示:

 

 

咱們先來寫第一個服務實現,以下,只是輸出一下使用到的一些自定義屬性:

package me.josephzhu.spring101customstarter;



import org.springframework.stereotype.Service;



@Service

public class MyService extends AbstractMyService {



    public MyService(String word) {

        super(word);

    }



    public MyService(){}



    @Override

    public String hello() {

        return String.format("V1 %s >> %s:%s !!", word, properties.getName(), properties.getAge());

    }



}

 

關鍵的一步來了,接下去咱們須要定義自動配置類:

package me.josephzhu.spring101customstarter;



import org.springframework.boot.context.properties.EnableConfigurationProperties;

import org.springframework.context.annotation.Bean;

import org.springframework.context.annotation.Configuration;



@Configuration

@EnableConfigurationProperties(MyServiceProperties.class)

public class MyAutoConfiguration {

    @Bean

    MyService getMyService(){

        return new MyService();

    }

}

 

經過EnableConfigurationProperties來告訴Spring咱們須要關聯一個配置文件配置類(配置類鬥不須要設置@Component),經過@Configuration告訴Spring這是一個Bean的配置類,下面咱們定義了咱們Service的實現。

最後,咱們須要告訴SpringBoot如何來找到咱們的自動配置類,在合適的時候自動配置。咱們須要在項目資源目錄建一個META-INF文件夾,而後建立一個spring.factories文件,寫入下面的內容:

org.springframework.boot.autoconfigure.EnableAutoConfiguration=me.josephzhu.spring101customstarter.MyAutoConfiguration

 

好了,就是這麼簡單,接下去咱們建立一個項目來使用咱們的自定義啓動器來試試:

<?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>me.josephzhu</groupId>

    <artifactId>spring101-main</artifactId>

    <version>0.0.1-SNAPSHOT</version>

    <packaging>jar</packaging>



    <name>spring101-main</name>

    <description></description>



    <parent>

        <groupId>me.josephzhu</groupId>

        <artifactId>spring101</artifactId>

        <version>0.0.1-SNAPSHOT</version>

    </parent>



    <dependencies>

        <dependency>

            <groupId>me.josephzhu</groupId>

            <artifactId>spring101-customstarter</artifactId>

            <version>0.0.1-SNAPSHOT</version>

        </dependency>



    </dependencies>



    <build>

        <plugins>

            <plugin>

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

                <artifactId>spring-boot-maven-plugin</artifactId>

            </plugin>

        </plugins>

    </build>





</project>

 

建立一個Runner來調用服務:

package me.josephzhu.spring101main;



import lombok.extern.slf4j.Slf4j;

import me.josephzhu.spring101customstarter.AbstractMyService;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.boot.CommandLineRunner;

import org.springframework.stereotype.Component;



@Component

@Slf4j

public class Runner1 implements CommandLineRunner {



    @Autowired

    private AbstractMyService service;



    @Override

    public void run(String... args) {

        log.info(service.hello());

    }

}

 

建立主程序:

package me.josephzhu.spring101main;



import org.springframework.boot.SpringApplication;

import org.springframework.boot.autoconfigure.SpringBootApplication;



@SpringBootApplication

public class Spring101MainApplication {



    public static void main(String[] args) {

        SpringApplication.run(Spring101MainApplication.class, args);

    }



}

 

而後在main模塊的資源目錄下建立application.properties文件,寫入兩個配置:

spring101.age=35
spring101.name=zhuye

運行後能夠看到輸出:

2018-09-30 14:55:00.848  INFO 12704 --- [           main] me.josephzhu.spring101main.Runner1       : V1 Hello >> zhuye:35 !!

能夠證實,第一咱們的main模塊引入的starter正確被SpringBoot識別加載,第二starter中的Configuration正確執行不但加載了配置類,並且也正確注入了Service的一個實現。

 

如何實現條件配置?

 

做爲組件的開發者,咱們有的時候但願針對環境、配置、類的加載狀況等等進行各類更智能的自動配置,這個時候就須要使用Spring的Conditional特性。咱們來看一個例子,若是咱們的Service隨着發展演化出了v2版本,咱們但願用戶在默認的時候使用v1,若是須要的話能夠進行version屬性配置容許用戶切換到v2版本。實現起來很是簡單,首先定義另外一個v2版本的服務:

package me.josephzhu.spring101customstarter;



import org.springframework.stereotype.Service;



@Service

public class MyServiceV2 extends AbstractMyService {



    public MyServiceV2(String word) {

        super(word);

    }



    public MyServiceV2(){}



    @Override

    public String hello() {

        return String.format("V2 %s >> %s:%s !!", word, properties.getName(), properties.getAge());

    }



}

 

和版本v1沒有任何區別,只是標記了一下v2關鍵字。

而後咱們改造一下咱們的自動配置類:

package me.josephzhu.spring101customstarter;



import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;

import org.springframework.boot.context.properties.EnableConfigurationProperties;

import org.springframework.context.annotation.Bean;

import org.springframework.context.annotation.Configuration;



@Configuration

@EnableConfigurationProperties(MyServiceProperties.class)

public class MyAutoConfiguration {

    @Bean

    @ConditionalOnProperty(prefix = "spring101", name = "version", havingValue = "v1", matchIfMissing = true)

    MyService getMyService(){

        return new MyService();

    }



    @Bean

    @ConditionalOnProperty(prefix = "spring101", name = "version", havingValue = "v2")

    MyServiceV2 getMyServiceV2(){

        return new MyServiceV2();

    }

}

 

這裏主要是爲兩個Bean分別添加了@ConditionalOnProperty註解,註解是自解釋的。這裏說了若是version的值是v1或沒有定義version的話匹配到默認的v1版本的服務,若是配置設置爲v2的話匹配到v2版本的服務,就這麼簡單。

再來看一個例子,若是咱們的使用者但願本身定義服務的實現,這個時候咱們須要覆蓋自動配置爲咱們自動裝配的v1和v2,可使用另外一個註解@ConditionalOnMissingBean來告知SpringBoot,若是找不到Bean的話再來自動配置:

package me.josephzhu.spring101customstarter;



import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;

import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;

import org.springframework.boot.context.properties.EnableConfigurationProperties;

import org.springframework.context.annotation.Bean;

import org.springframework.context.annotation.Configuration;



@Configuration

@EnableConfigurationProperties(MyServiceProperties.class)

public class MyAutoConfiguration {

    @Bean

    @ConditionalOnMissingBean(MyService.class)

    @ConditionalOnProperty(prefix = "spring101", name = "version", havingValue = "v1", matchIfMissing = true)

    MyService getMyService(){

        return new MyService();

    }



    @Bean

    @ConditionalOnMissingBean(MyServiceV2.class)

    @ConditionalOnProperty(prefix = "spring101", name = "version", havingValue = "v2")

    MyServiceV2 getMyServiceV2(){

        return new MyServiceV2();

    }

}

 

這樣的話,若是客戶端本身定義了Service的實現的話,就可讓自動配置放棄自動配置使用客戶端本身定義的Bean。還有N多的Conditional註解可使用,甚至能夠自定義條件,具體能夠查看官方文檔。

 

進行一下測試

 

接下去,咱們來寫一下單元測試來驗證一下咱們以前的代碼,使用ApplicationContextRunner能夠方便得設置帶入的各類外部配置項以及自定義配置類:

在這裏咱們寫了三個測試用例:

  1. 在提供了合適的屬性配置後,能夠看到服務的輸出正確獲取到了屬性。
  2. 使用配置項version來切換服務的實現,在省略version,設置version爲1,設置version爲2的狀況下獲得正確的輸出,分別是v一、v1和v2。
  3. 在客戶端自定義實現(MyServiceConfig)後能夠看到並無加載使用自動配置裏定義的服務實現,最後輸出了打招呼用語Hi而不是Hello。
package me.josephzhu.spring101main;



import me.josephzhu.spring101customstarter.AbstractMyService;

import me.josephzhu.spring101customstarter.MyAutoConfiguration;

import me.josephzhu.spring101customstarter.MyService;

import org.junit.Test;

import org.springframework.boot.autoconfigure.AutoConfigurations;

import org.springframework.boot.test.context.runner.ApplicationContextRunner;

import org.springframework.context.annotation.Bean;

import org.springframework.context.annotation.Configuration;



import static org.assertj.core.api.Assertions.assertThat;





public class Spring101MainApplicationTests {



    private ApplicationContextRunner applicationContextRunner = new ApplicationContextRunner()

            .withConfiguration(AutoConfigurations.of(MyAutoConfiguration.class));



    @Test

    public void testService() {

        applicationContextRunner

                .withPropertyValues("spring101.age=35")

                .withPropertyValues("spring101.name=zhuye")

                .run(context -> {

                    assertThat(context).hasSingleBean(AbstractMyService.class);

                    assertThat(context.getBean(AbstractMyService.class).hello()).containsSequence("zhuye:35");

                    System.out.println(context.getBean(MyService.class).hello());

                });

    }



    @Test

    public void testConditionalOnProperty() {

        applicationContextRunner

                .run(context -> {

                    assertThat(context).hasSingleBean(AbstractMyService.class);

                    assertThat(context.getBean(AbstractMyService.class).hello()).containsSequence("V1 Hello");

                    System.out.println(context.getBean(AbstractMyService.class).hello());

                });

        applicationContextRunner

                .withPropertyValues("spring101.version=v1")

                .run(context -> {

                    assertThat(context).hasSingleBean(AbstractMyService.class);

                    assertThat(context.getBean(AbstractMyService.class).hello()).containsSequence("V1 Hello");

                    System.out.println(context.getBean(AbstractMyService.class).hello());

                });

        applicationContextRunner

                .withPropertyValues("spring101.version=v2")

                .run(context -> {

                    assertThat(context).hasSingleBean(AbstractMyService.class);

                    assertThat(context.getBean(AbstractMyService.class).hello()).containsSequence("V2 Hello");

                    System.out.println(context.getBean(AbstractMyService.class).hello());

                });



    }



    @Test

    public void testConditionalOnMissingBean() {

        applicationContextRunner

                .withUserConfiguration(MyServiceConfig.class)

                .run(context -> {

                    assertThat(context).hasSingleBean(MyService.class);

                    assertThat(context.getBean(MyService.class).hello()).containsSequence("V1 Hi");

                    System.out.println(context.getBean(MyService.class).hello());

                });

    }



}



@Configuration

class MyServiceConfig {

    @Bean

    MyService getService() {

        return new MyService("Hi");

    }

}

 

運行測試能夠看到三個測試均可以經過,控制檯也輸出了hello方法的返回值:

 

 

實現自定義的配置數據源

 

接下去咱們來看一下如何利用EnvironmentPostProcessor來實現一個自定義的配置數據源。咱們在starter項目中新建一個類,這個類使用了一個Yaml配置源加載器,而後咱們把加載到的自定義的PropertySource加入到PropertySource候選列表的第一個,這樣就能夠實現屬性優先從咱們定義的(classpath下的)config.yml來讀取:

package me.josephzhu.spring101customstarter;



import org.springframework.boot.SpringApplication;

import org.springframework.boot.env.EnvironmentPostProcessor;

import org.springframework.boot.env.YamlPropertySourceLoader;

import org.springframework.core.env.ConfigurableEnvironment;

import org.springframework.core.env.PropertySource;

import org.springframework.core.io.ClassPathResource;

import org.springframework.core.io.Resource;



public class MyPropertySourceEnvironmentPostProcessor implements EnvironmentPostProcessor {



    private final YamlPropertySourceLoader loader = new YamlPropertySourceLoader();



    @Override

    public void postProcessEnvironment(ConfigurableEnvironment environment,

                                       SpringApplication application) {

        PropertySource<?> propertySource = loadYaml(new ClassPathResource("config.yml"));

        environment.getPropertySources().addFirst(propertySource);

    }



    private PropertySource<?> loadYaml(Resource path) {

        if (!path.exists()) {

            throw new IllegalArgumentException("Resource " + path + " does not exist");

        }

        try {

            return this.loader.load(path.getFile().getAbsolutePath(), path).get(0);

        }

        catch (Exception ex) {

            throw new IllegalStateException("Failed to load yaml configuration from " + path, ex);

        }

    }

}

 

最關鍵的一步就是讓SpringBoot能加載到咱們這個PostProcessor,仍是老樣子,在spring,factories文件中加入一項配置便可:

org.springframework.boot.env.EnvironmentPostProcessor=me.josephzhu.spring101customstarter.MyPropertySourceEnvironmentPostProcessor

如今,咱們能夠在starter項目下的resrouces目錄下建立一個config.yml來驗證一下:

spring101:
  name: zhuye_yml

從新運行main項目能夠看到以下的輸出結果中包含了yml字樣:

2018-09-30 15:27:05.123  INFO 12769 --- [           main] me.josephzhu.spring101main.Runner1       : V1 Hello >> zhuye_yml:35 !!

咱們能夠爲項目添加一下Actuator模塊進行進一步驗證:

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

在配置文件中加入設置來放開全部的端口訪問:

management.endpoints.web.exposure.include=*

而後打開瀏覽器訪問http://127.0.0.1:8080/actuator/env

 

能夠看到,的確是添加了咱們自定義的config.yml做爲PropertySource。

 

自動配置的調試問題

 

對於複雜的項目,若是咱們發現自動配置不起做用,要搞清楚框架是如何在各類條件中作自動配置以及自動配置的匹配過程是比較麻煩的事情,這個時候咱們能夠打開SpringBoot的Debug來查看日誌:

 

咱們能夠在日誌中搜索咱們關注的類型的匹配狀況,是否是很直觀呢:

MyAutoConfiguration#getMyService matched:

      - @ConditionalOnProperty (spring101.version=v1) matched (OnPropertyCondition)

      - @ConditionalOnMissingBean (types: me.josephzhu.spring101customstarter.MyService; SearchStrategy: all) did not find any beans (OnBeanCondition)

MyAutoConfiguration#getMyServiceV2:

      Did not match:

         - @ConditionalOnProperty (spring101.version=v2) did not find property 'version' (OnPropertyCondition)

 

咱們能夠試試在出錯的時候系統給咱們的提示,來把配置文件中的version設置爲3:

spring101.version=v3

從新運行後看到以下輸出:

***************************

APPLICATION FAILED TO START

**************************

Description:

Field service in me.josephzhu.spring101main.Runner1 required a bean of type 'me.josephzhu.spring101customstarter.AbstractMyService' that could not be found.

               - Bean method 'getMyService' in 'MyAutoConfiguration' not loaded because @ConditionalOnProperty (spring101.version=v1) found different value in property 'version'

               - Bean method 'getMyServiceV2' in 'MyAutoConfiguration' not loaded because @ConditionalOnProperty (spring101.version=v2) found different value in property 'version'

Action:

Consider revisiting the entries above or defining a bean of type 'me.josephzhu.spring101customstarter.AbstractMyService' in your configuration.

這個所謂的分析報告是比較機械性的,做爲框架的開發者,咱們甚至能夠自定義叫作FailureAnalyzer的東西來作更明確的提示。實現上和以前的步驟幾乎同樣,首先自定義一個類:

package me.josephzhu.spring101customstarter;



import org.springframework.beans.factory.NoSuchBeanDefinitionException;

import org.springframework.boot.diagnostics.AbstractFailureAnalyzer;

import org.springframework.boot.diagnostics.FailureAnalysis;



public class MyFailureAnalyzer extends AbstractFailureAnalyzer<NoSuchBeanDefinitionException> {

    @Override

    protected FailureAnalysis analyze(Throwable rootFailure, NoSuchBeanDefinitionException cause) {

        if(cause.getBeanType().equals(AbstractMyService.class))

            return new FailureAnalysis("加載MyService失敗", "請檢查配置文件中的version屬性設置是不是v1或v2", rootFailure);



        return null;

    }

}

 

這裏咱們根據cause的Bean類型作了簡單判斷,若是發生錯誤的是咱們的Service類型的話,告知使用者明確的錯誤緣由(Description)以及怎麼來糾正這個錯誤(Action)。

而後老規矩,在spring.factories中進行關聯:

org.springframework.boot.diagnostics.FailureAnalyzer=me.josephzhu.spring101customstarter.MyFailureAnalyzer

從新運行程序後能夠看到以下的結果:

***************************

APPLICATION FAILED TO START

***************************

Description:

加載MyService失敗

Action:

請檢查配置文件中的version屬性設置是不是v1或v2

是否是直觀不少呢?這裏個人實現比較簡單,在正式的實現中你能夠根據上下文以及環境的各類狀況爲用戶進行全面的分析,分析服務啓動失敗的緣由。

 

SpringBoot的擴展點

 

在以前的幾個例子中,咱們進行了各類擴展配置,經過spring.factories進行了自動配置、環境後處理器配置以及錯誤分析器配置:

org.springframework.boot.autoconfigure.EnableAutoConfiguration=me.josephzhu.spring101customstarter.MyAutoConfiguration
org.springframework.boot.env.EnvironmentPostProcessor=me.josephzhu.spring101customstarter.MyPropertySourceEnvironmentPostProcessor
org.springframework.boot.diagnostics.FailureAnalyzer=me.josephzhu.spring101customstarter.MyFailureAnalyzer

其實,SpringBoot還有一些其它的擴展槽,以下是SpringBoot自帶的一些配置類:

# Initializers

org.springframework.context.ApplicationContextInitializer=\

org.springframework.boot.autoconfigure.SharedMetadataReaderFactoryContextInitializer,\

org.springframework.boot.autoconfigure.logging.ConditionEvaluationReportLoggingListener



# Application Listeners

org.springframework.context.ApplicationListener=\

org.springframework.boot.autoconfigure.BackgroundPreinitializer



# Environment Post Processors

org.springframework.boot.env.EnvironmentPostProcessor=\

org.springframework.boot.autoconfigure.security.oauth2.client.OAuth2ClientPropertiesEnvironmentPostProcessor



# 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.OnBeanCondition,\

org.springframework.boot.autoconfigure.condition.OnClassCondition,\

org.springframework.boot.autoconfigure.condition.OnWebApplicationCondition



# Auto Configure

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\

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

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

org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration,\

org.springframework.boot.autoconfigure.batch.BatchAutoConfiguration,\

org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration,\

org.springframework.boot.autoconfigure.cassandra.CassandraAutoConfiguration,\

org.springframework.boot.autoconfigure.cloud.CloudServiceConnectorsAutoConfiguration,\

org.springframework.boot.autoconfigure.context.ConfigurationPropertiesAutoConfiguration,\

org.springframework.boot.autoconfigure.context.MessageSourceAutoConfiguration,\

org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration,\

org.springframework.boot.autoconfigure.couchbase.CouchbaseAutoConfiguration,\

org.springframework.boot.autoconfigure.dao.PersistenceExceptionTranslationAutoConfiguration,\

org.springframework.boot.autoconfigure.data.cassandra.CassandraDataAutoConfiguration,\

org.springframework.boot.autoconfigure.data.cassandra.CassandraReactiveDataAutoConfiguration,\

org.springframework.boot.autoconfigure.data.cassandra.CassandraReactiveRepositoriesAutoConfiguration,\

org.springframework.boot.autoconfigure.data.cassandra.CassandraRepositoriesAutoConfiguration,\

org.springframework.boot.autoconfigure.data.couchbase.CouchbaseDataAutoConfiguration,\

org.springframework.boot.autoconfigure.data.couchbase.CouchbaseReactiveDataAutoConfiguration,\

org.springframework.boot.autoconfigure.data.couchbase.CouchbaseReactiveRepositoriesAutoConfiguration,\

org.springframework.boot.autoconfigure.data.couchbase.CouchbaseRepositoriesAutoConfiguration,\

org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchAutoConfiguration,\

org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchDataAutoConfiguration,\

org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchRepositoriesAutoConfiguration,\

org.springframework.boot.autoconfigure.data.jdbc.JdbcRepositoriesAutoConfiguration,\

org.springframework.boot.autoconfigure.data.jpa.JpaRepositoriesAutoConfiguration,\

org.springframework.boot.autoconfigure.data.ldap.LdapRepositoriesAutoConfiguration,\

org.springframework.boot.autoconfigure.data.mongo.MongoDataAutoConfiguration,\

org.springframework.boot.autoconfigure.data.mongo.MongoReactiveDataAutoConfiguration,\

org.springframework.boot.autoconfigure.data.mongo.MongoReactiveRepositoriesAutoConfiguration,\

org.springframework.boot.autoconfigure.data.mongo.MongoRepositoriesAutoConfiguration,\

org.springframework.boot.autoconfigure.data.neo4j.Neo4jDataAutoConfiguration,\

org.springframework.boot.autoconfigure.data.neo4j.Neo4jRepositoriesAutoConfiguration,\

org.springframework.boot.autoconfigure.data.solr.SolrRepositoriesAutoConfiguration,\

org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration,\

org.springframework.boot.autoconfigure.data.redis.RedisReactiveAutoConfiguration,\

org.springframework.boot.autoconfigure.data.redis.RedisRepositoriesAutoConfiguration,\

org.springframework.boot.autoconfigure.data.rest.RepositoryRestMvcAutoConfiguration,\

org.springframework.boot.autoconfigure.data.web.SpringDataWebAutoConfiguration,\

org.springframework.boot.autoconfigure.elasticsearch.jest.JestAutoConfiguration,\

org.springframework.boot.autoconfigure.elasticsearch.rest.RestClientAutoConfiguration,\

org.springframework.boot.autoconfigure.flyway.FlywayAutoConfiguration,\

org.springframework.boot.autoconfigure.freemarker.FreeMarkerAutoConfiguration,\

org.springframework.boot.autoconfigure.gson.GsonAutoConfiguration,\

org.springframework.boot.autoconfigure.h2.H2ConsoleAutoConfiguration,\

org.springframework.boot.autoconfigure.hateoas.HypermediaAutoConfiguration,\

org.springframework.boot.autoconfigure.hazelcast.HazelcastAutoConfiguration,\

org.springframework.boot.autoconfigure.hazelcast.HazelcastJpaDependencyAutoConfiguration,\

org.springframework.boot.autoconfigure.http.HttpMessageConvertersAutoConfiguration,\

org.springframework.boot.autoconfigure.http.codec.CodecsAutoConfiguration,\

org.springframework.boot.autoconfigure.influx.InfluxDbAutoConfiguration,\

org.springframework.boot.autoconfigure.info.ProjectInfoAutoConfiguration,\

org.springframework.boot.autoconfigure.integration.IntegrationAutoConfiguration,\

org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration,\

org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration,\

org.springframework.boot.autoconfigure.jdbc.JdbcTemplateAutoConfiguration,\

org.springframework.boot.autoconfigure.jdbc.JndiDataSourceAutoConfiguration,\

org.springframework.boot.autoconfigure.jdbc.XADataSourceAutoConfiguration,\

org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration,\

org.springframework.boot.autoconfigure.jms.JmsAutoConfiguration,\

org.springframework.boot.autoconfigure.jmx.JmxAutoConfiguration,\

org.springframework.boot.autoconfigure.jms.JndiConnectionFactoryAutoConfiguration,\

org.springframework.boot.autoconfigure.jms.activemq.ActiveMQAutoConfiguration,\

org.springframework.boot.autoconfigure.jms.artemis.ArtemisAutoConfiguration,\

org.springframework.boot.autoconfigure.groovy.template.GroovyTemplateAutoConfiguration,\

org.springframework.boot.autoconfigure.jersey.JerseyAutoConfiguration,\

org.springframework.boot.autoconfigure.jooq.JooqAutoConfiguration,\

org.springframework.boot.autoconfigure.jsonb.JsonbAutoConfiguration,\

org.springframework.boot.autoconfigure.kafka.KafkaAutoConfiguration,\

org.springframework.boot.autoconfigure.ldap.embedded.EmbeddedLdapAutoConfiguration,\

org.springframework.boot.autoconfigure.ldap.LdapAutoConfiguration,\

org.springframework.boot.autoconfigure.liquibase.LiquibaseAutoConfiguration,\

org.springframework.boot.autoconfigure.mail.MailSenderAutoConfiguration,\

org.springframework.boot.autoconfigure.mail.MailSenderValidatorAutoConfiguration,\

org.springframework.boot.autoconfigure.mongo.embedded.EmbeddedMongoAutoConfiguration,\

org.springframework.boot.autoconfigure.mongo.MongoAutoConfiguration,\

org.springframework.boot.autoconfigure.mongo.MongoReactiveAutoConfiguration,\

org.springframework.boot.autoconfigure.mustache.MustacheAutoConfiguration,\

org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration,\

org.springframework.boot.autoconfigure.quartz.QuartzAutoConfiguration,\

org.springframework.boot.autoconfigure.reactor.core.ReactorCoreAutoConfiguration,\

org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration,\

org.springframework.boot.autoconfigure.security.servlet.SecurityRequestMatcherProviderAutoConfiguration,\

org.springframework.boot.autoconfigure.security.servlet.UserDetailsServiceAutoConfiguration,\

org.springframework.boot.autoconfigure.security.servlet.SecurityFilterAutoConfiguration,\

org.springframework.boot.autoconfigure.security.reactive.ReactiveSecurityAutoConfiguration,\

org.springframework.boot.autoconfigure.security.reactive.ReactiveUserDetailsServiceAutoConfiguration,\

org.springframework.boot.autoconfigure.sendgrid.SendGridAutoConfiguration,\

org.springframework.boot.autoconfigure.session.SessionAutoConfiguration,\

org.springframework.boot.autoconfigure.security.oauth2.client.servlet.OAuth2ClientAutoConfiguration,\

org.springframework.boot.autoconfigure.security.oauth2.client.reactive.ReactiveOAuth2ClientAutoConfiguration,\

org.springframework.boot.autoconfigure.security.oauth2.resource.servlet.OAuth2ResourceServerAutoConfiguration,\

org.springframework.boot.autoconfigure.security.oauth2.resource.reactive.ReactiveOAuth2ResourceServerAutoConfiguration,\

org.springframework.boot.autoconfigure.solr.SolrAutoConfiguration,\

org.springframework.boot.autoconfigure.task.TaskExecutionAutoConfiguration,\

org.springframework.boot.autoconfigure.task.TaskSchedulingAutoConfiguration,\

org.springframework.boot.autoconfigure.thymeleaf.ThymeleafAutoConfiguration,\

org.springframework.boot.autoconfigure.transaction.TransactionAutoConfiguration,\

org.springframework.boot.autoconfigure.transaction.jta.JtaAutoConfiguration,\

org.springframework.boot.autoconfigure.validation.ValidationAutoConfiguration,\

org.springframework.boot.autoconfigure.web.client.RestTemplateAutoConfiguration,\

org.springframework.boot.autoconfigure.web.embedded.EmbeddedWebServerFactoryCustomizerAutoConfiguration,\

org.springframework.boot.autoconfigure.web.reactive.HttpHandlerAutoConfiguration,\

org.springframework.boot.autoconfigure.web.reactive.ReactiveWebServerFactoryAutoConfiguration,\

org.springframework.boot.autoconfigure.web.reactive.WebFluxAutoConfiguration,\

org.springframework.boot.autoconfigure.web.reactive.error.ErrorWebFluxAutoConfiguration,\

org.springframework.boot.autoconfigure.web.reactive.function.client.ClientHttpConnectorAutoConfiguration,\

org.springframework.boot.autoconfigure.web.reactive.function.client.WebClientAutoConfiguration,\

org.springframework.boot.autoconfigure.web.servlet.DispatcherServletAutoConfiguration,\

org.springframework.boot.autoconfigure.web.servlet.ServletWebServerFactoryAutoConfiguration,\

org.springframework.boot.autoconfigure.web.servlet.error.ErrorMvcAutoConfiguration,\

org.springframework.boot.autoconfigure.web.servlet.HttpEncodingAutoConfiguration,\

org.springframework.boot.autoconfigure.web.servlet.MultipartAutoConfiguration,\

org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration,\

org.springframework.boot.autoconfigure.websocket.reactive.WebSocketReactiveAutoConfiguration,\

org.springframework.boot.autoconfigure.websocket.servlet.WebSocketServletAutoConfiguration,\

org.springframework.boot.autoconfigure.websocket.servlet.WebSocketMessagingAutoConfiguration,\

org.springframework.boot.autoconfigure.webservices.WebServicesAutoConfiguration,\

org.springframework.boot.autoconfigure.webservices.client.WebServiceTemplateAutoConfiguration



# Failure analyzers

org.springframework.boot.diagnostics.FailureAnalyzer=\

org.springframework.boot.autoconfigure.diagnostics.analyzer.NoSuchBeanDefinitionFailureAnalyzer,\

org.springframework.boot.autoconfigure.jdbc.DataSourceBeanCreationFailureAnalyzer,\

org.springframework.boot.autoconfigure.jdbc.HikariDriverConfigurationFailureAnalyzer,\

org.springframework.boot.autoconfigure.session.NonUniqueSessionRepositoryFailureAnalyzer



# Template availability providers

org.springframework.boot.autoconfigure.template.TemplateAvailabilityProvider=\

org.springframework.boot.autoconfigure.freemarker.FreeMarkerTemplateAvailabilityProvider,\

org.springframework.boot.autoconfigure.mustache.MustacheTemplateAvailabilityProvider,\

org.springframework.boot.autoconfigure.groovy.template.GroovyTemplateAvailabilityProvider,\

org.springframework.boot.autoconfigure.thymeleaf.ThymeleafTemplateAvailabilityProvider,\

org.springframework.boot.autoconfigure.web.servlet.JspTemplateAvailabilityProvider
 

 

咱們能夠看到一共有8大類的擴展槽,這些槽貫穿了整個SpringBoot加載的整個過程,感興趣的讀者能夠逐一搜索查看Spring的文檔和源碼進行進一步的分析。

本文從如何作一個Starter實現自動配置開始,進一步闡述瞭如何實現智能的條件配置,如何,如何進行自動配置的測試,而後咱們自定義了環境後處理器來加載額外的配置源(你固然能夠實現更復雜的配置源,好比從Redis和數據庫中獲取配置)以及經過開啓Actutor來驗證,定義了配置錯誤分析器來給用戶明確的錯誤提示。最後,咱們看了一下spring.factories中的內容瞭解了SpringBoot內部定義的一些擴展槽和實現。

相關文章
相關標籤/搜索