进入地址: https://start.spring.io/ ,点击生成代码即可。
一个Web项目,只需要这一行注解。有这么厉害吗?我们一起看看它究竟做了什么?
@SpringBootApplication
public class SpringBootDemoApplication {
public static void main(String[] args) {
SpringApplication.run(SpringBootDemoApplication.class, args);
}
}
The @SpringBootApplication annotation is equivalent to using @Configuration , @EnableAutoConfiguration , and @ComponentScan with their default attributes
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = {
@Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication {
看代码,明明是 @SpringBootConfiguration 呢,怎么说是 @Configuration 呢?
@Configuration
public @interface SpringBootConfiguration {
}
然后再进入到里面去,发现竟然是 Component 注解?是不是非常熟悉呢?
@Component
public @interface Configuration {
Spring provides further stereotype annotations: @Component , @Service , and @Controller . @Component is a generic stereotype for any Spring-managed component. @Repository , @Service , and @Controller are specializations of @Component for more specific use cases (in the persistence, service, and presentation layers, respectively)。
org.springframework.boot.SpringApplication
// 第1步
public ConfigurableApplicationContext run(String... args) {
refreshContext(context);
}
// 第2步
public ConfigurableApplicationContext run(String... args) {
ConfigurableApplicationContext context = null;
Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
configureHeadlessProperty();
SpringApplicationRunListeners listeners = getRunListeners(args);
listeners.starting();
try {
ConfigurableEnvironment environment = prepareEnvironment(listeners,
applicationArguments);
configureIgnoreBeanInfo(environment);
Banner printedBanner = printBanner(environment);
context = createApplicationContext();
exceptionReporters = getSpringFactoriesInstances(
SpringBootExceptionReporter.class,
new Class[] { ConfigurableApplicationContext.class }, context);
prepareContext(context, environment, listeners, applicationArguments,
printedBanner);
refreshContext(context);
afterRefresh(context, applicationArguments);
listeners.started(context);
// Called after the context has been refreshed.
callRunners(context, applicationArguments);
}
listeners.running(context);
return context;
}
// 第3步
protected void refresh(ApplicationContext applicationContext) {
Assert.isInstanceOf(AbstractApplicationContext.class, applicationContext);
((AbstractApplicationContext) applicationContext).refresh();
}
// 第4步
org.springframework.context.support.AbstractApplicationContext
public void refresh() throws BeansException, IllegalStateException {
// Invoke factory processors registered as beans in the context.
invokeBeanFactoryPostProcessors(beanFactory);
}
// 第5步
org.springframework.context.support.PostProcessorRegistrationDelegate
for (BeanFactoryPostProcessor postProcessor : beanFactoryPostProcessors) {
if (postProcessor instanceof BeanDefinitionRegistryPostProcessor) {
registryProcessor.postProcessBeanDefinitionRegistry(registry);
}
}
// 第6步
org.springframework.context.annotation.ConfigurationClassPostProcessor
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
processConfigBeanDefinitions(registry);
}
// 第7步
public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
do {
parser.parse(candidates);
}
}
// 第8步
org.springframework.context.annotation.ConfigurationClassParser
protected void processConfigurationClass(ConfigurationClass configClass) throws IOException {
do {
sourceClass = doProcessConfigurationClass(configClass, sourceClass);
}
}
// 第9步
protected final SourceClass doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass)
throws IOException {
// Process any @PropertySource annotations
for (AnnotationAttributes propertySource : AnnotationConfigUtils.attributesForRepeatable(
sourceClass.getMetadata(), PropertySources.class,
org.springframework.context.annotation.PropertySource.class)) {
if (this.environment instanceof ConfigurableEnvironment) {
processPropertySource(propertySource);
}
else {
logger.info("Ignoring @PropertySource annotation on [" + sourceClass.getMetadata().getClassName() +
"]. Reason: Environment must implement ConfigurableEnvironment");
}
}
// Process any @ComponentScan annotations
Set<AnnotationAttributes> componentScans = AnnotationConfigUtils.attributesForRepeatable(
sourceClass.getMetadata(), ComponentScans.class, ComponentScan.class);
if (!componentScans.isEmpty() &&
!this.conditionEvaluator.shouldSkip(sourceClass.getMetadata(), ConfigurationPhase.REGISTER_BEAN)) {
for (AnnotationAttributes componentScan : componentScans) {
// The config class is annotated with @ComponentScan -> perform the scan immediately
Set<BeanDefinitionHolder> scannedBeanDefinitions =
this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName());
// Check the set of scanned definitions for any further config classes and parse recursively if needed
for (BeanDefinitionHolder holder : scannedBeanDefinitions) {
BeanDefinition bdCand = holder.getBeanDefinition().getOriginatingBeanDefinition();
if (bdCand == null) {
bdCand = holder.getBeanDefinition();
}
if (ConfigurationClassUtils.checkConfigurationClassCandidate(bdCand, this.metadataReaderFactory)) {
parse(bdCand.getBeanClassName(), holder.getBeanName());
}
}
}
}
// Process any @Import annotations
processImports(configClass, sourceClass, getImports(sourceClass), true);
// Process any @ImportResource annotations
AnnotationAttributes importResource =
AnnotationConfigUtils.attributesFor(sourceClass.getMetadata(), ImportResource.class);
if (importResource != null) {
String[] resources = importResource.getStringArray("locations");
Class<? extends BeanDefinitionReader> readerClass = importResource.getClass("reader");
for (String resource : resources) {
String resolvedResource = this.environment.resolveRequiredPlaceholders(resource);
configClass.addImportedResource(resolvedResource, readerClass);
}
}
}
// 第10步
private void processImports(ConfigurationClass configClass, SourceClass currentSourceClass,
Collection<SourceClass> importCandidates, boolean checkForCircularImports) {
String[] importClassNames = selector.selectImports(currentSourceClass.getMetadata());
Collection<SourceClass> importSourceClasses = asSourceClasses(importClassNames);
processImports(configClass, currentSourceClass, importSourceClasses, false);
}
// 第11步
org.springframework.boot.autoconfigure.AutoConfigurationImportSelector
@Override
public String[] selectImports(AnnotationMetadata annotationMetadata) {
AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(
autoConfigurationMetadata, annotationMetadata);
}
// 第12步
private List<String> filter(List<String> configurations,
AutoConfigurationMetadata autoConfigurationMetadata) {
for (AutoConfigurationImportFilter filter : getAutoConfigurationImportFilters()) {
invokeAwareMethods(filter);
boolean[] match = filter.match(candidates, autoConfigurationMetadata);
for (int i = 0; i < match.length; i++) {
if (!match[i]) {
skip[i] = true;
candidates[i] = null;
skipped = true;
}
}
}
return new ArrayList<>(result);
}
// 第13步
protected List<AutoConfigurationImportFilter> getAutoConfigurationImportFilters() {
return SpringFactoriesLoader.loadFactories(AutoConfigurationImportFilter.class,
this.beanClassLoader);
}
// 第14步
org.springframework.core.io.support.SpringFactoriesLoader
public static <T> List<T> loadFactories(Class<T> factoryClass, @Nullable ClassLoader classLoader) {
List<String> factoryNames = loadFactoryNames(factoryClass, classLoaderToUse);
return result;
}
// 第15步
private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) {
try {
Enumeration<URL> urls = (classLoader != null ?
classLoader.getResources(FACTORIES_RESOURCE_LOCATION) :
ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION));
return result;
}
}
public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories";
也就是说,其实 spring.factories 是 spring-core 的功能。
看一下 spring-boot-autoconfigure 项目里面的 spring.factories 。
# 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 # 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
看到这里,是不是有一点解惑了,为什么我们什么都没有干,它就已经具备了那么多的功能。因为在项目启动的时候,已经就给我们内置了这么多的服务。
我们再回到开始的时候,为什么启动的时候看到了 Tomcat 的日志呢?
Connected to the target VM, address: '127.0.0.1:56945', transport: 'socket' . _ __ _ _ /// / ___'_ __ _ _(_)_ __ __ _ / / / / ( ( )/___ | '_ | '_| | '_ // _` | / / / / /// ___)| |_)| | | | | || (_| | ) ) ) ) ' | | .__|_| |_|_| |_/__, | / / / / =========|_|==============|___/=/_/_/_/ :: Spring Boot :: 2019-06-13 09:15:11.818 INFO 16978 --- [ main] c.e.s.SpringBootDemoApplication : Starting SpringBootDemoApplication on bogon with PID 16978 (/Users/chenyuan/Dropbox/Workspaces/IdeaProjects/spring-boot-demo/target/classes started by chenyuan in /Users/chenyuan/Dropbox/Workspaces/IdeaProjects/spring-src-leaning) 2019-06-13 09:15:11.823 INFO 16978 --- [ main] c.e.s.SpringBootDemoApplication : No active profile set, falling back to default profiles: default // 这里日志显示,有一个embedded的tomcat启动了8080端口 2019-06-13 09:15:13.597 INFO 16978 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port(s): 8080 (http) 2019-06-13 09:15:13.644 INFO 16978 --- [ main] o.apache.catalina.core.StandardService : Starting service [Tomcat] 2019-06-13 09:15:13.645 INFO 16978 --- [ main] org.apache.catalina.core.StandardEngine : Starting Servlet engine: [Apache Tomcat/9.0.14] 2019-06-13 09:15:13.653 INFO 16978 --- [ main] o.a.catalina.core.AprLifecycleListener : The APR based Apache Tomcat Native library which allows optimal performance in production environments was not found on the java.library.path: [/Users/chenyuan/Library/Java/Extensions:/Library/Java/Extensions:/Network/Library/Java/Extensions:/System/Library/Java/Extensions:/usr/lib/java:.] 2019-06-13 09:15:13.752 INFO 16978 --- [ main] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext 2019-06-13 09:15:13.752 INFO 16978 --- [ main] o.s.web.context.ContextLoader : Root WebApplicationContext: initialization completed in 1862 ms 2019-06-13 09:15:14.018 INFO 16978 --- [ main] o.s.s.concurrent.ThreadPoolTaskExecutor : Initializing ExecutorService 'applicationTaskExecutor' 2019-06-13 09:15:14.226 INFO 16978 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8080 (http) with context path '' 2019-06-13 09:15:14.231 INFO 16978 --- [ main] c.e.s.SpringBootDemoApplication : Started SpringBootDemoApplication in 3.007 seconds (JVM running for 3.924)
# Auto Configure org.springframework.boot.autoconfigure.EnableAutoConfiguration=/
org.springframework.boot.autoconfigure.web.servlet.ServletWebServerFactoryAutoConfiguration
@Bean
@ConditionalOnClass(name = "org.apache.catalina.startup.Tomcat")
public TomcatServletWebServerFactoryCustomizer tomcatServletWebServerFactoryCustomizer(
ServerProperties serverProperties) {
return new TomcatServletWebServerFactoryCustomizer(serverProperties);
}
<!-- spring-boot-demo/pom.xml -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- spring-boot-starter-web/pom.xml -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</dependency>
<!-- spring-boot-starters/spring-boot-starter-tomcat/pom.xml -->
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-core</artifactId>
<exclusions>
<exclusion>
<groupId>org.apache.tomcat</groupId>
<artifactId>tomcat-annotations-api</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jetty</artifactId>
</dependency>
</dependencies>
把项目中Tomca的starter注释掉,引入Jetty容器即可。
这么更换后,为什么就又能引入了呢?
org.springframework.boot.autoconfigure.web.servlet.ServletWebServerFactoryConfiguration
@Configuration
@ConditionalOnClass({ Servlet.class, Server.class, Loader.class,WebAppContext.class })
@ConditionalOnMissingBean(value = ServletWebServerFactory.class, search = SearchStrategy.CURRENT)
public static class EmbeddedJetty {
@Bean
public JettyServletWebServerFactory JettyServletWebServerFactory() {
return new JettyServletWebServerFactory();
}
}
The @ConditionalOnClass and @ConditionalOnMissingClass annotations let @Configuration classes be included based on the presence or absence of specific classes.
这里的 Servlet.class, Server.class, Loader.class,WebAppContext.class 就是Jetty里面的包。
这里还设计了一个工厂模式,获取一个WebServer。
@FunctionalInterface
public interface ServletWebServerFactory {
/**
* Gets a new fully configured but paused {@link WebServer} instance. Clients should
* not be able to connect to the returned server until {@link WebServer#start()} is
* called (which happens when the {@link ApplicationContext} has been fully
* refreshed).
* @param initializers {@link ServletContextInitializer}s that should be applied as
* the server starts
* @return a fully configured and started {@link WebServer}
* @see WebServer#stop()
*/
WebServer getWebServer(ServletContextInitializer... initializers);
}
// 第1步
org.springframework.context.support.AbstractApplicationContext
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
try {
// Initialize other special beans in specific context subclasses.
onRefresh();
}
}
// 第2步
org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext
protected void onRefresh() {
super.onRefresh();
try {
createWebServer();
}
catch (Throwable ex) {
throw new ApplicationContextException("Unable to start web server", ex);
}
}
// 第3步
private void createWebServer() {
WebServer webServer = this.webServer;
ServletContext servletContext = getServletContext();
if (webServer == null && servletContext == null) {
ServletWebServerFactory factory = getWebServerFactory();
this.webServer = factory.getWebServer(getSelfInitializer());
}
else if (servletContext != null) {
try {
getSelfInitializer().onStartup(servletContext);
}
catch (ServletException ex) {
throw new ApplicationContextException("Cannot initialize servlet context",
ex);
}
}
initPropertySources();
}
在看到 factory.getWebServer ,是不是就全部都串联起来了?