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系列教程前言&目錄


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM