1. 程式人生 > >SpringBoot SpringApplication底層原始碼分析與自動裝配

SpringBoot SpringApplication底層原始碼分析與自動裝配

目錄

丟擲問題

@SpringBootApplication
public class LearnspringbootApplication {

    public static void main(String[] args) {
        SpringApplication.run(LearnspringbootApplication.class, args);
    }
}

大家可以看到,如上所示是一個很常見的SpringBoot啟動類,我們可以看到僅僅使用了一個Main方法就啟動了整個SpringBoot專案是不是很神奇,下面我們來仔細剖析以下這一段程式碼,這段程式碼中我們可以仔細地觀察到最重要的兩個部分,分別是@SpringBootApplication

註解和SpringApplication這個類。

  • @SpringBootApplication註解
  • SpringApplication類

@SpringBootApplication註解剖析

開啟這個@SpringBootApplication註解,如下所示

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = {
        @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
        @Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication {

    @AliasFor(annotation = EnableAutoConfiguration.class)
    Class<?>[] exclude() default {};


    @AliasFor(annotation = EnableAutoConfiguration.class)
    String[] excludeName() default {};


    @AliasFor(annotation = ComponentScan.class, attribute = "basePackages")
    String[] scanBasePackages() default {};

    @AliasFor(annotation = ComponentScan.class, attribute = "basePackageClasses")
    Class<?>[] scanBasePackageClasses() default {};

}

我們可以發現;我們可以在@SpringBootApplication註解中使用exclude(),excludeName(),scanBasePackages(),scanBasePackageClasses() 這四個方法來進行自定義我們需要排除裝配的Bean,掃描包路徑,掃描類路徑。

搭眼一瞅,在@SpringBootApplication註解上還有下面那麼多註解。

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = {
        @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
        @Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })

這四個註解不用看,就是關於註解的一些定義

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited

@SpringBootConfiguration註解我們點進去看一下,發現是下面這個樣子,@SpringBootConfiguration註解上又標註了@Configuration註解,想必在@Configuration註解上也標註了@Component註解,這不就是我們上一章節說的Spring的模式註解。總的來說嘛,SpringBootConfiguration註解的作用就是把類變成可以被Spring管理的Bean

結論 1 :也就是說標註@SpringBootApplication註解的類會成為Spring的Bean

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Configuration
public @interface SpringBootConfiguration {

}

我們再來看一下@EnableAutoConfiguration,從名字上我們就可以看到“啟用自動裝配”的意思。那我們可要仔細看一下。從下面我們可以看到只有兩個我們需要了解的註解,分別是@AutoConfigurationPackage@Import註解。

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {

    String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";


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


    String[] excludeName() default {};

}

當我點進去@AutoConfigurationPackage註解中,發現該註解又啟用了一個模組裝配@Import(AutoConfigurationPackages.Registrar.class)(上一章節有講到);所以又點進去AutoConfigurationPackages.Registrar.class這個類,發現這個類又實現了兩個介面ImportBeanDefinitionRegistrarDeterminableImports 在該類的實現方法中的PackageImport();最後終於發現了下面這段程式碼。

    PackageImport(AnnotationMetadata metadata) {
            this.packageName = ClassUtils.getPackageName(metadata.getClassName());
        }

結論 2 :SpringBoot預設會裝配啟動類路徑的所有包下可裝配的Bean;也就是說如果你把SpringBoot啟動類放在一個單獨的包中,則SpringBoot不會裝配到你的其他Bean。這時候你就要使用@SpringBootApplicationscanBasePackages()方法進行另行配置。

此時@EnableAutoConfiguration註解僅僅就剩下@Import(AutoConfigurationImportSelector.class)沒有看了,不過從註解上我們可以看到使用@Import註解,所以可以知道SpringBoot使用的是模組裝配的介面實現方式。所以我麼針對AutoConfigurationImportSelector這個類仔細剖析一下。AutoConfigurationImportSelector - > AutoConfigurationImportSelector.selectImports() ->getAutoConfigurationEntry() -> getCandidateConfigurations() ->SpringFactoriesLoader.loadFactoryNames() -> loadFactoryNames() ->loadSpringFactories() ; 哈哈果然原始碼不經扒;看下面原始碼;META-INF/spring.factories這不就是配置SpringBoot自動配置的檔案嘛。

public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories";

Enumeration<URL> urls = (classLoader != null ?
                    classLoader.getResources(FACTORIES_RESOURCE_LOCATION) :
                    ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION));

結論 3 :SpringBoot在啟動時會自動載入Classpth路徑下的META-INF/spring.factories檔案,所以我們可以將需要自動配置的Bean寫入這個檔案,SPringBoot會替我們自動裝配。這也正是配置SpringBoot自動配置的步驟。

SpringApplication類剖析

@SpringBootApplication
public class LearnspringbootApplication {

    public static void main(String[] args) {
        SpringApplication.run(LearnspringbootApplication.class, args);
    }
}

在Main方法中我們可以看到SpringApplication作為一個啟動類來啟動SpringBoot應用程式。那麼SpringApplication類是如何進行啟動整個應用程式的呢?

第一步:配置SpringBoot Bean來源

    public SpringApplication(Class<?>... primarySources) {
        this(null, primarySources);
    }

從SpringApplication類的構造方法中我們可以看到,這裡傳入了一個主Bean來源;因為我們將標註了@SpringBootApplication註解的LearnspringbootApplication.class傳遞了進來,所以@SpringBootApplication掃描到的Bean和自動裝配的Bean會作為主Bean來源。當然我們可以呼叫該類的setSources()方法設定自己的SpringXML配置。

第二步 :自動推斷SpringBoot的應用型別

this.webApplicationType = WebApplicationType.deduceFromClasspath();

從上面一句程式碼(既SpringApplication初始化方法中一行程式碼);我們觀察deduceFromClasspath()方法可以看到,SpringBoot判斷類路徑下是否存在下面類進而判斷SpringBoot的應用型別。三種類型分別是NONESERVLETREACTIVE 。當然我們也可以呼叫setWebApplicationType()自行設定。

    private static final String[] SERVLET_INDICATOR_CLASSES = { "javax.servlet.Servlet",
            "org.springframework.web.context.ConfigurableWebApplicationContext" };

    private static final String WEBMVC_INDICATOR_CLASS = "org.springframework."
            + "web.servlet.DispatcherServlet";

    private static final String WEBFLUX_INDICATOR_CLASS = "org."
            + "springframework.web.reactive.DispatcherHandler";

    private static final String JERSEY_INDICATOR_CLASS = "org.glassfish.jersey.servlet.ServletContainer";

    private static final String SERVLET_APPLICATION_CONTEXT_CLASS = "org.springframework.web.context.WebApplicationContext";

    private static final String REACTIVE_APPLICATION_CONTEXT_CLASS = "org.springframework.boot.web.reactive.context.ReactiveWebApplicationContext";

第三步:推斷SpringBoot的引導類

this.mainApplicationClass = deduceMainApplicationClass();

從上面一句程式碼(既SpringApplication初始化方法中一行程式碼);我們可以通過deduceMainApplicationClass()方法可以看到SpringBoot根據Main 執行緒執行堆疊判斷實際的引導類。(PS:存在一種情況就是標註@SpringBootApplication註解的並不是引導類情況)

    private Class<?> deduceMainApplicationClass() {
        try {
            StackTraceElement[] stackTrace = new RuntimeException().getStackTrace();
            for (StackTraceElement stackTraceElement : stackTrace) {
                if ("main".equals(stackTraceElement.getMethodName())) {
                    return Class.forName(stackTraceElement.getClassName());
                }
            }
        }
        catch (ClassNotFoundException ex) {
            // Swallow and continue
        }
        return null;
    }

第四步:載入應用上下文初始化器

setInitializers((Collection) getSpringFactoriesInstances(
                ApplicationContextInitializer.class));

從上面一句程式碼(既SpringApplication初始化方法中一行程式碼);我們發現setInitializers()方法會呼叫getSpringFactoriesInstances() -> getSpringFactoriesInstances() -> getSpringFactoriesInstances() 該方法會使用SpringFactoriesLoader類記進行載入配置資源既META-INF/spring.factories,利用 Spring 工廠載入機制,例項化 ApplicationContextInitializer 實現類,並排序物件集合。並使用AnnotationAwareOrderComparator類的sort()方法進行排序。

    private <T> Collection<T> getSpringFactoriesInstances(Class<T> type,
            Class<?>[] parameterTypes, Object... args) {
        ClassLoader classLoader = getClassLoader();
        // Use names and ensure unique to protect against duplicates
        Set<String> names = new LinkedHashSet<>(
                SpringFactoriesLoader.loadFactoryNames(type, classLoader));
        List<T> instances = createSpringFactoriesInstances(type, parameterTypes,
                classLoader, args, names);
        AnnotationAwareOrderComparator.sort(instances);
        return instances;
    }

第五步 :載入應用事件監聽器

setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));

從上面一句程式碼(既SpringApplication初始化方法中一行程式碼);從setListeners() 方法中可以看到該方法仍然呼叫getSpringFactoriesInstances()方法,不同的是利用 Spring 工廠載入META-INF/spring.factories,例項化 ApplicationListener 實現類,並排序物件集合

第六步:啟動SpringApplication 執行監聽器( SpringApplicationRunListeners )

SpringApplication類的run()方法中,我們可以看到下面程式碼getRunListeners()方法同樣利用 Spring 工廠載入機制,讀取 SpringApplicationRunListener 物件集合,並且封裝到組合類
SpringApplicationRunListeners物件中並啟動執行監聽器。

        SpringApplicationRunListeners listeners = getRunListeners(args);
        listeners.starting();

第七步:監聽SpringBoot/Spring事件

Spring Boot 通過 SpringApplicationRunListener 的實現類 EventPublishingRunListener 利用 Spring Framework 事件
API ,廣播 Spring Boot 事件。

第八步:建立SpringBoot的應用上下文

context = createApplicationContext();

SpringApplication類的run()方法中,我們可看到createApplicationContext()根據第二步推斷的SpringBoot應用型別建立相應的上下文。

    protected ConfigurableApplicationContext createApplicationContext() {
        Class<?> contextClass = this.applicationContextClass;
        if (contextClass == null) {
            try {
                switch (this.webApplicationType) {
                case SERVLET:
                    contextClass = Class.forName(DEFAULT_SERVLET_WEB_CONTEXT_CLASS);
                    break;
                case REACTIVE:
                    contextClass = Class.forName(DEFAULT_REACTIVE_WEB_CONTEXT_CLASS);
                    break;
                default:
                    contextClass = Class.forName(DEFAULT_CONTEXT_CLASS);
                }
            }
            catch (ClassNotFoundException ex) {
                throw new IllegalStateException(
                        "Unable create a default ApplicationContext, "
                                + "please specify an ApplicationContextClass",
                        ex);
            }
        }
        return (ConfigurableApplicationContext) BeanUtils.instantiateClass(contextClass);
    }

根據推斷的SpringBoot應用型別建立下面三種之一的上下文

    public static final String DEFAULT_CONTEXT_CLASS = "org.springframework.context."
            + "annotation.AnnotationConfigApplicationContext";


    public static final String DEFAULT_SERVLET_WEB_CONTEXT_CLASS = "org.springframework.boot."
            + "web.servlet.context.AnnotationConfigServletWebServerApplicationContext";


    public static final String DEFAULT_REACTIVE_WEB_CONTEXT_CLASS = "org.springframework."
            + "boot.web.reactive.context.AnnotationConfigReactiveWebServerApplicationContext";

第九步:建立 Environment

ConfigurableEnvironment environment = prepareEnvironment(listeners,
                    applicationArguments);
            configureIgnoreBeanInfo(environment);

SpringApplication類的run()方法中,我們可看到prepareEnvironment()根據第二步推斷的SpringBoot應用型別建立相應的上下文。建立不同的Environment 。從下面可以看到他們分別是StandardServletEnvironmentStandardReactiveWebEnvironmentStandardEnvironment

    private ConfigurableEnvironment getOrCreateEnvironment() {
        if (this.environment != null) {
            return this.environment;
        }
        switch (this.webApplicationType) {
        case SERVLET:
            return new StandardServletEnvironment();
        case REACTIVE:
            return new StandardReactiveWebEnvironment();
        default:
            return new StandardEnvironment();
        }
    }

結論

  1. 標註@SpringBootApplication註解的類會成為Spring的Bean

  2. SpringBoot預設會裝配啟動類路徑的所有包下可裝配的Bean;也就是說如果你把SpringBoot啟動類放在一個單獨的包中,則SpringBoot不會裝配到你的其他Bean。這時候你就要使用@SpringBootApplicationscanBasePackages()方法進行另行配置。

  3. SpringBoot在啟動時會自動載入Classpth路徑下的META-INF/spring.factories檔案,所以我們可以將需要自動配置的Bean寫入這個檔案。同樣SpringBoot也會掃描Jar包中的META-INF/spring.factories檔案;例如當匯入spring-boot-starter起步依賴的時候,並且啟用了自動裝配註解@EnableAutoConfiguration,就將會替我們自動裝配如如下類;如果滿足條件的話。

    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

該教程所屬Java工程師之SpringBoot系列教程,本系列相關博文目錄 Java工程師之SpringBoot系列教程前言&目錄