欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

我们如何看SpringBoot的源代码

程序员文章站 2022-05-25 23:47:21
...

1、快速生成一个简单的SpringBoot项目

进入地址: start.spring.io/ ,点击生成代码即可。

2、注解:@SpringBootApplication

一个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 呢?

2.1、注解:@SpringBootConfiguration

@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)。

2.2、注解:@ComponentScan

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.factoriesspring-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复制代码

看到这里,是不是有一点解惑了,为什么我们什么都没有干,它就已经具备了那么多的功能。因为在项目启动的时候,已经就给我们内置了这么多的服务。

3、容器在哪儿启动的?

3.1 为什么是Tomcat默认启动?

我们再回到开始的时候,为什么启动的时候看到了 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>复制代码

3.2 如果要指定其他的容器呢?

<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 @Configurationclasses 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);

}复制代码

3.3 那是在什么时候初始化容器的呢?

// 第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 ,是不是就全部都串联起来了?

感谢阅读至文末,彩蛋奉上

java核心笔记,BAT面试题,架构进阶视频,电子书籍

部分资料如下图:



转载于:https://juejin.im/post/5d034c1f6fb9a07ef7107040