博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Spring boot 启动过程工作原理
阅读量:4037 次
发布时间:2019-05-24

本文共 40751 字,大约阅读时间需要 135 分钟。

1. SpringBootApplication rum()方法

@SpringBootApplication  //注解public class SpringBootTestApplication{​    public static void main(String[] args) {        ConfigurableApplicationContext context  =SpringApplication.run(SpringBootStudySourceApplication.class, args);    }}

2. SpringApplication注解

/** * Indicates a {@link Configuration configuration} class that declares one or more * {@link Bean @Bean} methods and also triggers {@link EnableAutoConfiguration * auto-configuration} and {@link ComponentScan component scanning}. This is a convenience * annotation that is equivalent to declaring {@code @Configuration}, * {@code @EnableAutoConfiguration} and {@code @ComponentScan}. * * @author Phillip Webb * @author Stephane Nicoll * @since 1.2.0 */@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 {​    /**     * Exclude specific auto-configuration classes such that they will never be applied.     * @return the classes to exclude     */    @AliasFor(annotation = EnableAutoConfiguration.class)    Class
[] exclude() default {};​ /** * Exclude specific auto-configuration class names such that they will never be * applied. * @return the class names to exclude * @since 1.3.0 */ @AliasFor(annotation = EnableAutoConfiguration.class) String[] excludeName() default {};​ /** * Base packages to scan for annotated components. Use {@link #scanBasePackageClasses} * for a type-safe alternative to String-based package names. * @return base packages to scan * @since 1.3.0 */ @AliasFor(annotation = ComponentScan.class, attribute = "basePackages") String[] scanBasePackages() default {};​ /** * Type-safe alternative to {@link #scanBasePackages} for specifying the packages to * scan for annotated components. The package of each class specified will be scanned. *

* Consider creating a special no-op marker class or interface in each package that * serves no purpose other than being referenced by this attribute. * @return base packages to scan * @since 1.3.0 */ @AliasFor(annotation = ComponentScan.class, attribute = "basePackageClasses") Class

[] scanBasePackageClasses() default {};​}​@EnableAutoConfiguration  @ComponentScan @configuration  三个注解的复合​​

3. SpringApplication构造方法

/**     * Create a new {@link SpringApplication} instance. The application context will load     * beans from the specified primary sources (see {@link SpringApplication class-level}     * documentation for details. The instance can be customized before calling     * {@link #run(String...)}.     * @param resourceLoader the resource loader to use     * @param primarySources the primary bean sources     * @see #run(Class, String[])     * @see #setSources(Set)     */    @SuppressWarnings({ "unchecked", "rawtypes" })    public SpringApplication(ResourceLoader resourceLoader, Class
... primarySources) { this.resourceLoader = resourceLoader;        //指定类型 Assert.notNull(primarySources, "PrimarySources must not be null"); this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));        //web类型(servlet、reactive、Noweb) this.webApplicationType = WebApplicationType.deduceFromClasspath();        //从MATA-INF/spring.factories 获取ApplicationContextInitializer(接口的注释 ) setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class)); setListeners((Collection)            //从MATA-INF/spring.factories      ApplicationListener(监听事件)             getSpringFactoriesInstances(ApplicationListener.class));        //执行main方法 this.mainApplicationClass = deduceMainApplicationClass(); }
/**     * Run the Spring application, creating and refreshing a new     * {@link ApplicationContext}.     * @param args the application arguments (usually passed from a Java main method)     * @return a running {@link ApplicationContext}     */    public ConfigurableApplicationContext run(String... args) {        //开始计时        StopWatch stopWatch = new StopWatch();        stopWatch.start();        ConfigurableApplicationContext context = null;        Collection
exceptionReporters = new ArrayList<>();        //设置系统属性java.awt.handless configureHeadlessProperty();        //获取到META-INF/spring.factories中的配置SpringApplicationRunListeners SpringApplicationRunListeners listeners = getRunListeners(args);        //循环执行 listeners.starting(); try {            //命令行为参数,包装了ApplicationArguments ApplicationArguments applicationArguments = new DefaultApplicationArguments( args);            //主备好environment ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);            // configureIgnoreBeanInfo(environment);            //打印图标 Banner printedBanner = printBanner(environment);            //创建applicationContext context = createApplicationContext();            //获取到META-INF/spring.factories中的配置SpringBootExceptionReporter exceptionReporters = getSpringFactoriesInstances( SpringBootExceptionReporter.class, new Class[] { ConfigurableApplicationContext.class }, context);            //准备ApplicationContext prepareContext(context, environment, listeners, applicationArguments, printedBanner);            //刷新ApplicationContext refreshContext(context); afterRefresh(context, applicationArguments); stopWatch.stop(); if (this.logStartupInfo) { new StartupInfoLogger(this.mainApplicationClass) .logStarted(getApplicationLog(), stopWatch); }            //发布started事件 listeners.started(context);            //执行所有的runners callRunners(context, applicationArguments);              /**            runners.addAll(context.getBeansOfType(ApplicationRunner.class).values());    runners.addAll(context.getBeansOfType(CommandLineRunner.class).values());            **/ } catch (Throwable ex) { handleRunFailure(context, ex, exceptionReporters, listeners); throw new IllegalStateException(ex); }​ try {            //发布所有running事件 listeners.running(context);           } catch (Throwable ex) { handleRunFailure(context, ex, exceptionReporters, null); throw new IllegalStateException(ex); }        //返回 return context; }​

4. 环境准备过程

private ConfigurableEnvironment prepareEnvironment(            SpringApplicationRunListeners listeners,            ApplicationArguments applicationArguments) {        // Create and configure the environment        //系统环境变量、系统参数、具体应用类配置参数        ConfigurableEnvironment environment = getOrCreateEnvironment();        //环境配置         /**configurePropertySources(environment, args);        configureProfiles(environment, args);        **/        configureEnvironment(environment, applicationArguments.getSourceArgs());        //触发RunListener环境准备回调        listeners.environmentPrepared(environment);        //绑定springApplication        bindToSpringApplication(environment);        if (!this.isCustomEnvironment) {            environment = new EnvironmentConverter(getClassLoader())                    .convertEnvironmentIfNecessary(environment, deduceEnvironmentClass());        }        ConfigurationPropertySources.attach(environment);        return environment;    }

5. 参数的配置是在哪加载的

/**     * Configure which profiles are active (or active by default) for this application     * environment. Additional profiles may be activated during configuration file     * processing via the {@code spring.profiles.active} property.     * @param environment this application's environment     * @param args arguments passed to the {@code run} method     * @see #configureEnvironment(ConfigurableEnvironment, String[])     * @see org.springframework.boot.context.config.ConfigFileApplicationListener     */    protected void configureProfiles(ConfigurableEnvironment environment, String[] args) {        environment.getActiveProfiles(); // ensure they are initialized        // But these ones should go first (last wins in a property key clash)        Set
profiles = new LinkedHashSet<>(this.additionalProfiles); profiles.addAll(Arrays.asList(environment.getActiveProfiles())); environment.setActiveProfiles(StringUtils.toStringArray(profiles)); }

ConfigFileApplicationListener

//实现了EnvironmentPostProcessor ,在这里加载配置文件public class ConfigFileApplicationListener        implements EnvironmentPostProcessor, SmartApplicationListener, Ordered { //    @Override    public void postProcessEnvironment(ConfigurableEnvironment environment,            SpringApplication application) {        addPropertySources(environment, application.getResourceLoader());    }        //实现了ApplicationListener        @Override    public void onApplicationEvent(ApplicationEvent event) {        if (event instanceof ApplicationEnvironmentPreparedEvent) {            onApplicationEnvironmentPreparedEvent(                    (ApplicationEnvironmentPreparedEvent) event);        }        if (event instanceof ApplicationPreparedEvent) {            onApplicationPreparedEvent(event);        }    }                private void onApplicationEnvironmentPreparedEvent(            ApplicationEnvironmentPreparedEvent event) {        List
postProcessors = loadPostProcessors(); postProcessors.add(this); AnnotationAwareOrderComparator.sort(postProcessors); for (EnvironmentPostProcessor postProcessor : postProcessors) { postProcessor.postProcessEnvironment(event.getEnvironment(), event.getSpringApplication()); } }        /** * Post-process the given {@code environment}. * @param environment the environment to post-process * @param application the application to which the environment belongs */ void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application);​}​

栈执行链:

6. ConfigurableApplicationContext

创建准备过程

/**     * Strategy method used to create the {@link ApplicationContext}. By default this     * method will respect any explicitly set application context or application context     * class before falling back to a suitable default.     * @return the application context (not yet refreshed)     * @see #setApplicationContextClass(Class)     */    protected ConfigurableApplicationContext createApplicationContext() { // 逻辑:如果没有编程式指定contextClass,webApplicationType来选择对应默认ApplicationContext实现类        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); }​//默认的三个常量名包含了什么?怎么执行的?/** * The class name of application context that will be used by default for non-web * environments. */ public static final String DEFAULT_CONTEXT_CLASS = "org.springframework.context." + "annotation.AnnotationConfigApplicationContext";​ /** * The class name of application context that will be used by default for web * environments. */ public static final String DEFAULT_SERVLET_WEB_CONTEXT_CLASS = "org.springframework.boot." + "web.servlet.context.AnnotationConfigServletWebServerApplicationContext";​ /** * The class name of application context that will be used by default for reactive web * environments. */ public static final String DEFAULT_REACTIVE_WEB_CONTEXT_CLASS = "org.springframework." + "boot.web.reactive.context.AnnotationConfigReactiveWebServerApplicationContext";​​

加载过程

private void prepareContext(ConfigurableApplicationContext context,            ConfigurableEnvironment environment, SpringApplicationRunListeners listeners,            ApplicationArguments applicationArguments, Banner printedBanner) {        //设置环境对象        context.setEnvironment(environment);        //设置beanNameGenerator resourceLoader addConversionService        postProcessApplicationContext(context);    //3、应用初始化器对ApplicationContext进行初始化处理(Initializers在构造SpringApplication时就从spring.factories中加载到了)        applyInitializers(context);    //发布事件    /**    @Override    public void contextPrepared(ConfigurableApplicationContext context) {        this.initialMulticaster.multicastEvent(new ApplicationContextInitializedEvent(                this.application, this.args, context));    }    **/        listeners.contextPrepared(context);    //打印startup日志信息        if (this.logStartupInfo) {            logStartupInfo(context.getParent() == null);            logStartupProfileInfo(context);        }        // Add boot specific singleton beans  单例bean注入工厂        ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();        beanFactory.registerSingleton("springApplicationArguments", applicationArguments);        if (printedBanner != null) {            beanFactory.registerSingleton("springBootBanner", printedBanner);        }        if (beanFactory instanceof DefaultListableBeanFactory) {            ((DefaultListableBeanFactory) beanFactory)                    .setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);        }        // Load the sources 加载PrimarySource、其他编程式指定的source 配置类中的Bean定        Set sources = getAllSources();        Assert.notEmpty(sources, "Sources must not be empty");        load(context, sources.toArray(new Object[0]));          //发布applictionContext加载bean定义完毕事件        listeners.contextLoaded(context);    }

刷新事件

private void refreshContext(ConfigurableApplicationContext context) {        refresh(context);        if (this.registerShutdownHook) {            try {                context.registerShutdownHook();            }            catch (AccessControlException ex) {                // Not allowed in some environments.            }        }    }        /**     * Refresh the underlying {@link ApplicationContext}.     * @param applicationContext the application context to refresh     */    protected void refresh(ApplicationContext applicationContext) {        Assert.isInstanceOf(AbstractApplicationContext.class, applicationContext);        ((AbstractApplicationContext) applicationContext).refresh();    }

bean是在哪加载的

/**     * Create a new {@link SpringApplication} instance. The application context will load     * beans from the specified primary sources (see {@link SpringApplication class-level}     * documentation for details. The instance can be customized before calling     * {@link #run(String...)}.     * @param resourceLoader the resource loader to use     * @param primarySources the primary bean sources     * @see #run(Class, String[])     * @see #setSources(Set)     */    @SuppressWarnings({ "unchecked", "rawtypes" })    public SpringApplication(ResourceLoader resourceLoader, Class
... primarySources) { this.resourceLoader = resourceLoader; Assert.notNull(primarySources, "PrimarySources must not be null"); this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources)); this.webApplicationType = WebApplicationType.deduceFromClasspath(); //初始化bean定义 setInitializers((Collection) getSpringFactoriesInstances( ApplicationContextInitializer.class)); setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class)); this.mainApplicationClass = deduceMainApplicationClass(); }​//​private
Collection
getSpringFactoriesInstances(Class
type) { return getSpringFactoriesInstances(type, new Class
[] {}); }​ private
Collection
getSpringFactoriesInstances(Class
type, Class
[] parameterTypes, Object... args) { ClassLoader classLoader = getClassLoader(); // Use names and ensure unique to protect against duplicates Set
names = new LinkedHashSet<>( SpringFactoriesLoader.loadFactoryNames(type, classLoader)); List
instances = createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names); AnnotationAwareOrderComparator.sort(instances); return instances; }​​//# Auto Configure//org.springframework.boot.autoconfigure.EnableAutoConfiguration=\org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration,\org.springframework.boot.autoconfigure.aop.AopAutoConfiguration,\​

/*

* Copyright 2012-2017 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*     http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.boot.autoconfigure;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;
import org.springframework.boot.web.servlet.server.ServletWebServerFactory;
import org.springframework.context.annotation.Conditional;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.core.io.support.SpringFactoriesLoader;
/**
* Enable auto-configuration of the Spring Application Context, attempting to guess and
* configure beans that you are likely to need. Auto-configuration classes are usually
* applied based on your classpath and what beans you have defined. For example, if you
* have {@code tomcat-embedded.jar} on your classpath you are likely to want a
* {@link TomcatServletWebServerFactory} (unless you have defined your own
* {@link ServletWebServerFactory} bean).
* <p>
* When using {@link SpringBootApplication}, the auto-configuration of the context is
* automatically enabled and adding this annotation has therefore no additional effect.
* <p>
* Auto-configuration tries to be as intelligent as possible and will back-away as you
* define more of your own configuration. You can always manually {@link #exclude()} any
* configuration that you never want to apply (use {@link #excludeName()} if you don't
* have access to them). You can also exclude them via the
* {@code spring.autoconfigure.exclude} property. Auto-configuration is always applied
* after user-defined beans have been registered.
* <p>
* The package of the class that is annotated with {@code @EnableAutoConfiguration},
* usually via {@code @SpringBootApplication}, has specific significance and is often used
* as a 'default'. For example, it will be used when scanning for {@code @Entity} classes.
* It is generally recommended that you place {@code @EnableAutoConfiguration} (if you're
* not using {@code @SpringBootApplication}) in a root package so that all sub-packages
* and classes can be searched.
* <p>
* Auto-configuration classes are regular Spring {@link Configuration} beans. They are
* located using the {@link SpringFactoriesLoader} mechanism (keyed against this class).
* Generally auto-configuration beans are {@link Conditional @Conditional} beans (most
* often using {@link ConditionalOnClass @ConditionalOnClass} and
* {@link ConditionalOnMissingBean @ConditionalOnMissingBean} annotations).
*
* @author Phillip Webb
* @author Stephane Nicoll
* @see ConditionalOnBean
* @see ConditionalOnMissingBean
* @see ConditionalOnClass
* @see AutoConfigureAfter
* @see SpringBootApplication
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)//最终执行的类
public @interface EnableAutoConfiguration {
String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";
/**
* Exclude specific auto-configuration classes such that they will never be applied.
* @return the classes to exclude
*/
Class<?>[] exclude() default {};
/**
* Exclude specific auto-configuration class names such that they will never be
* applied.
* @return the class names to exclude
* @since 1.3.0
*/
String[] excludeName() default {};
}
//AutoConfigurationImportSelector实现了DeferredImportSelector
//所谓延迟:在所有指定的、包扫描到的@Configuration类中的bean定义注册后,才会来处理延迟导入的
/**
* A variation of {@link ImportSelector} that runs after all {@code @Configuration} beans
* have been processed. This type of selector can be particularly useful when the selected
* imports are {@code @Conditional}.
*
* <p>Implementations can also extend the {@link org.springframework.core.Ordered}
* interface or use the {@link org.springframework.core.annotation.Order} annotation to
* indicate a precedence against other {@link DeferredImportSelector DeferredImportSelectors}.
*
* <p>Implementations may also provide an {@link #getImportGroup() import group} which
* can provide additional sorting and filtering logic across different selectors.
*
* @author Phillip Webb
* @author Stephane Nicoll
* @since 4.0
*/
public interface DeferredImportSelector extends ImportSelector {
   
}
为什么要延迟导入的方式?
   让我们自己编程配置的bean提前注册,这样自动配置时的条件判断能发现到我们配置的,就能做到不再配置
自动配置的bean等。比如:如果我们自己配置了数据源bean,则使用我们配置的数据源,不在自动配置数据源。数
据源自动配置的代码中可以看到@ConditionalOnMissingBean({ DataSource.class, XADataSource.class }):
   
@Configuration
@Conditional(PooledDataSourceCondition.class)
@ConditionalOnMissingBean({ DataSource.class, XADataSource.class })
@Import({ DataSourceConfiguration.Hikari.class, DataSourceConfiguration.Tomcat.class,
DataSourceConfiguration.Dbcp2.class, DataSourceConfiguration.Generic.class,
DataSourceJmxConfiguration.class })
protected static class PooledDataSourceConfiguration {
}

callRunners

private void callRunners(ApplicationContext context, ApplicationArguments args) {        List runners = new ArrayList<>();        runners.addAll(context.getBeansOfType(ApplicationRunner.class).values());        runners.addAll(context.getBeansOfType(CommandLineRunner.class).values());        AnnotationAwareOrderComparator.sort(runners);        for (Object runner : new LinkedHashSet<>(runners)) {            if (runner instanceof ApplicationRunner) {                callRunner((ApplicationRunner) runner, args);            }            if (runner instanceof CommandLineRunner) {                callRunner((CommandLineRunner) runner, args);            }        }    }​    private void callRunner(ApplicationRunner runner, ApplicationArguments args) {        try {            (runner).run(args);        }        catch (Exception ex) {            throw new IllegalStateException("Failed to execute ApplicationRunner", ex);        }    }​    private void callRunner(CommandLineRunner runner, ApplicationArguments args) {        try {            (runner).run(args.getSourceArgs());        }        catch (Exception ex) {            throw new IllegalStateException("Failed to execute CommandLineRunner", ex);        }    }​ApplicationRunner,CommandLineRunner 有何作用?        @SpringBootApplicationpublic class SpringBootTestApplication implements ApplicationRunner {   public static void main(String[] args) {    SpringApplication.run(SpringBootTestApplication.class, args); }  @Override  public void run(ApplicationArguments args) throws Exception {    System.out.println("***************** " + mybean); }}​​@SpringBootApplicationpublic class SpringBootTestApplication implements ApplicationRunner {  public static void main(String[] args) {    ConfigurableApplicationContext context =      SpringApplication.run(SpringBootTestApplication.class, args);    MyBean mybean = context.getBean(MyBean.class);    mybean.doService(); }}​

7. tomcat如何跑起来

context = createApplicationContext();                /**     * Strategy method used to create the {@link ApplicationContext}. By default this     * method will respect any explicitly set application context or application context     * class before falling back to a suitable default.     * @return the application context (not yet refreshed)     * @see #setApplicationContextClass(Class)     */    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); }​ /** * The class name of application context that will be used by default for web * environments. */ public static final String DEFAULT_SERVLET_WEB_CONTEXT_CLASS = "org.springframework.boot." + "web.servlet.context.AnnotationConfigServletWebServerApplicationContext";​​​/** * {@link ServletWebServerApplicationContext} that accepts annotated classes as input - in * particular {@link org.springframework.context.annotation.Configuration @Configuration} * -annotated classes, but also plain {@link Component @Component} classes and JSR-330 * compliant classes using {@code javax.inject} annotations. Allows for registering * classes one by one (specifying class names as config location) as well as for classpath * scanning (specifying base packages as config location). *

* Note: In case of multiple {@code @Configuration} classes, later {@code @Bean} * definitions will override ones defined in earlier loaded files. This can be leveraged * to deliberately override certain bean definitions via an extra Configuration class. * * @author Phillip Webb * @see #register(Class...) * @see #scan(String...) * @see ServletWebServerApplicationContext * @see AnnotationConfigWebApplicationContext */public class AnnotationConfigServletWebServerApplicationContext extends ServletWebServerApplicationContext implements AnnotationConfigRegistry {    }​//父类/** * A {@link WebApplicationContext} that can be used to bootstrap itself from a contained * {@link ServletWebServerFactory} bean. *

* This context will create, initialize and run an {@link WebServer} by searching for a * single {@link ServletWebServerFactory} bean within the {@link ApplicationContext} * itself. The {@link ServletWebServerFactory} is free to use standard Spring concepts * (such as dependency injection, lifecycle callbacks and property placeholder variables). *

* In addition, any {@link Servlet} or {@link Filter} beans defined in the context will be * automatically registered with the web server. In the case of a single Servlet bean, the * '/' mapping will be used. If multiple Servlet beans are found then the lowercase bean * name will be used as a mapping prefix. Any Servlet named 'dispatcherServlet' will * always be mapped to '/'. Filter beans will be mapped to all URLs ('/*'). *

* For more advanced configuration, the context can instead define beans that implement * the {@link ServletContextInitializer} interface (most often * {@link ServletRegistrationBean}s and/or {@link FilterRegistrationBean}s). To prevent * double registration, the use of {@link ServletContextInitializer} beans will disable * automatic Servlet and Filter bean registration. *

   这个context会通过从自身查找一个ServletWebServerFactory单例bean来创建、初始化、运行一个WebServer  

此外,在context中定义的Servlet、Filter bean会被自动注册到Web Server。如果只有一个Servlet bean,则会将它映射到'/' 请求地址;多个Servlet bean时,则bean name 的小写将作为 mapping 前缀;bean名为'dispatcherServlet' 的Servlet将映射到 '/'。Filter beans将会映射到'/*'(所有url)

更高级的配置ServletContext的方式:定义实现ServletContextInitializer接口的bean,更常用的方式是通过配置ServletRegistrationBean和FilterRegistrationBean的方式来配Servlet、Filter.为防止重复注册,当使用ServletContextInitializer beans 时会关闭自动Servlet和Filter Bean注册。

* Although this context can be used directly, most developers should consider using the * {@link AnnotationConfigServletWebServerApplicationContext} or * {@link XmlServletWebServerApplicationContext} variants. * * @author Phillip Webb * @author Dave Syer * @see AnnotationConfigServletWebServerApplicationContext * @see XmlServletWebServerApplicationContext * @see ServletWebServerFactory */public class ServletWebServerApplicationContext extends GenericWebApplicationContext implements ConfigurableWebServerApplicationContext {​ private static final Log logger = LogFactory .getLog(ServletWebServerApplicationContext.class);​ /** * Constant value for the DispatcherServlet bean name. A Servlet bean with this name * is deemed to be the "main" servlet and is automatically given a mapping of "/" by * default. To change the default behavior you can use a * {@link ServletRegistrationBean} or a different bean name. */ public static final String DISPATCHER_SERVLET_NAME = "dispatcherServlet";​ private volatile WebServer webServer;​ private ServletConfig servletConfig;​ private String serverNamespace;​ /** * Create a new {@link ServletWebServerApplicationContext}. */ public ServletWebServerApplicationContext() { }​ /** * Create a new {@link ServletWebServerApplicationContext} with the given * {@code DefaultListableBeanFactory}. * @param beanFactory the DefaultListableBeanFactory instance to use for this context */ public ServletWebServerApplicationContext(DefaultListableBeanFactory beanFactory) { super(beanFactory); }​ /** * Register ServletContextAwareProcessor. * @see ServletContextAwareProcessor */ @Override protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) { beanFactory.addBeanPostProcessor( new WebApplicationContextServletContextAwareProcessor(this)); beanFactory.ignoreDependencyInterface(ServletContextAware.class); registerWebApplicationScopes(); }​    //子类实现模板方法 @Override public final void refresh() throws BeansException, IllegalStateException { try { super.refresh(); } catch (RuntimeException ex) { stopAndReleaseWebServer(); throw ex; } }        //子类实现模板方法 @Override protected void onRefresh() { super.onRefresh(); try {            //创建容器 createWebServer(); } catch (Throwable ex) { throw new ApplicationContextException("Unable to start web server", ex); } }​ @Override protected void finishRefresh() { super.finishRefresh();        //webServer创建过程 WebServer webServer = startWebServer(); if (webServer != null) { publishEvent(new ServletWebServerInitializedEvent(webServer, this)); } }​ @Override protected void onClose() { super.onClose(); stopAndReleaseWebServer(); }​     private void createWebServer() { WebServer webServer = this.webServer; ServletContext servletContext = getServletContext(); if (webServer == null && servletContext == null) { ServletWebServerFactory factory = getWebServerFactory();            //-----implements TomcatServletWebServerFactory--- 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(); }​ /** 从容器中找ServletWebServerFactory类型的Bean,只能有一个。 * Returns the {@link ServletWebServerFactory} that should be used to create the * embedded {@link WebServer}. By default this method searches for a suitable bean in * the context itself. * @return a {@link ServletWebServerFactory} (never {@code null}) */ protected ServletWebServerFactory getWebServerFactory() { // Use bean names so that we don't consider the hierarchy String[] beanNames = getBeanFactory() .getBeanNamesForType(ServletWebServerFactory.class); if (beanNames.length == 0) { throw new ApplicationContextException( "Unable to start ServletWebServerApplicationContext due to missing " + "ServletWebServerFactory bean."); } if (beanNames.length > 1) { throw new ApplicationContextException( "Unable to start ServletWebServerApplicationContext due to multiple " + "ServletWebServerFactory beans : " + StringUtils.arrayToCommaDelimitedString(beanNames)); } return getBeanFactory().getBean(beanNames[0], ServletWebServerFactory.class); }}​//ServletWebServerFactory    /**Factory interface that can be used to create a {@link WebServer}.@author Phillip Webb@see WebServer@since 2.0.0*/@FunctionalInterfacepublic interface ServletWebServerFactory {  /**  获得一个完全配置但暂停的新WebServer实例,当ApplicationContext完成refresh后再调用   WebServer.start(),客户端才可以进行连接。  @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);}​/** * {@link AbstractServletWebServerFactory} that can be used to create * {@link TomcatWebServer}s. Can be initialized using Spring's * {@link ServletContextInitializer}s or Tomcat {@link LifecycleListener}s. *

* Unless explicitly configured otherwise this factory will create containers that listen * for HTTP requests on port 8080. * * @author Phillip Webb * @author Dave Syer * @author Brock Mills * @author Stephane Nicoll * @author Andy Wilkinson * @author Eddú Meléndez * @author Christoffer Sawicki * @since 2.0.0 * @see #setPort(int) * @see #setContextLifecycleListeners(Collection) * @see TomcatWebServer */public class TomcatServletWebServerFactory extends AbstractServletWebServerFactory implements ConfigurableTomcatWebServerFactory, ResourceLoaderAware {​@Override public WebServer getWebServer(ServletContextInitializer... initializers) { Tomcat tomcat = new Tomcat(); File baseDir = (this.baseDirectory != null) ? this.baseDirectory : createTempDir("tomcat"); tomcat.setBaseDir(baseDir.getAbsolutePath()); Connector connector = new Connector(this.protocol); tomcat.getService().addConnector(connector); customizeConnector(connector); tomcat.setConnector(connector); tomcat.getHost().setAutoDeploy(false); configureEngine(tomcat.getEngine()); for (Connector additionalConnector : this.additionalTomcatConnectors) { tomcat.getService().addConnector(additionalConnector); } prepareContext(tomcat.getHost(), initializers); return getTomcatWebServer(tomcat); }}​

TomcatServletWebServerFactory这个Bean哪里配置的

 

/** * {@link EnableAutoConfiguration Auto-configuration} for servlet web servers. * * @author Phillip Webb * @author Dave Syer * @author Ivan Sopov * @author Brian Clozel * @author Stephane Nicoll */@Configuration@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE)@ConditionalOnClass(ServletRequest.class)@ConditionalOnWebApplication(type = Type.SERVLET)@EnableConfigurationProperties(ServerProperties.class)@Import({ ServletWebServerFactoryAutoConfiguration.BeanPostProcessorsRegistrar.class,        ServletWebServerFactoryConfiguration.EmbeddedTomcat.class,        ServletWebServerFactoryConfiguration.EmbeddedJetty.class,        ServletWebServerFactoryConfiguration.EmbeddedUndertow.class })public class ServletWebServerFactoryAutoConfiguration {​    @Bean    public ServletWebServerFactoryCustomizer servletWebServerFactoryCustomizer(            ServerProperties serverProperties) {        return new ServletWebServerFactoryCustomizer(serverProperties);    }​    @Bean    @ConditionalOnClass(name = "org.apache.catalina.startup.Tomcat")    public TomcatServletWebServerFactoryCustomizer tomcatServletWebServerFactoryCustomizer(            ServerProperties serverProperties) {        return new TomcatServletWebServerFactoryCustomizer(serverProperties);    }}​​//-------------------------EmbeddedTomcat ---------------------------​/** * Configuration classes for servlet web servers * 

* Those should be {@code @Import} in a regular auto-configuration class to guarantee * their order of execution. * * @author Phillip Webb * @author Dave Syer * @author Ivan Sopov * @author Brian Clozel * @author Stephane Nicoll */@Configurationclass ServletWebServerFactoryConfiguration {​ @Configuration @ConditionalOnClass({ Servlet.class, Tomcat.class, UpgradeProtocol.class }) @ConditionalOnMissingBean(value = ServletWebServerFactory.class, search = SearchStrategy.CURRENT) public static class EmbeddedTomcat {​        //注入tomcatbean @Bean public TomcatServletWebServerFactory tomcatServletWebServerFactory() { return new TomcatServletWebServerFactory(); }​ }​ /** * Nested configuration if Jetty is being used. */ @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(); }​ }​ /** * Nested configuration if Undertow is being used. */ @Configuration @ConditionalOnClass({ Servlet.class, Undertow.class, SslClientAuthMode.class }) @ConditionalOnMissingBean(value = ServletWebServerFactory.class, search = SearchStrategy.CURRENT) public static class EmbeddedUndertow {​ @Bean public UndertowServletWebServerFactory undertowServletWebServerFactory() { return new UndertowServletWebServerFactory(); }​ }}​​//-----------------------参数的解读------------​/** * {@link ConfigurationProperties} for a web server (e.g. port and path settings). * * @author Dave Syer * @author Stephane Nicoll * @author Andy Wilkinson * @author Ivan Sopov * @author Marcos Barbero * @author Eddú Meléndez * @author Quinten De Swaef * @author Venil Noronha * @author Aurélien Leboulanger * @author Brian Clozel * @author Olivier Lamy * @author Chentao Qu */@ConfigurationProperties(prefix = "server", ignoreUnknownFields = true)public class ServerProperties {    }​​

 

转载地址:http://vujdi.baihongyu.com/

你可能感兴趣的文章
[互联网关注]李开复教大学生回答如何学好编程
查看>>
[关注大学生]李开复给中国计算机系大学生的7点建议
查看>>
[关注大学生]大学毕业生择业:是当"鸡头"还是"凤尾"?
查看>>
[茶余饭后]10大毕业生必听得歌曲
查看>>
gdb调试命令的三种调试方式和简单命令介绍
查看>>
C++程序员的几种境界
查看>>
VC++ MFC SQL ADO数据库访问技术使用的基本步骤及方法
查看>>
VUE-Vue.js之$refs,父组件访问、修改子组件中 的数据
查看>>
Vue-子组件改变父级组件的信息
查看>>
Python自动化之pytest常用插件
查看>>
Python自动化之pytest框架使用详解
查看>>
【正则表达式】以个人的理解帮助大家认识正则表达式
查看>>
性能调优之iostat命令详解
查看>>
性能调优之iftop命令详解
查看>>
非关系型数据库(nosql)介绍
查看>>
移动端自动化测试-Windows-Android-Appium环境搭建
查看>>
Xpath使用方法
查看>>
移动端自动化测试-Mac-IOS-Appium环境搭建
查看>>
Selenium之前世今生
查看>>
Selenium-WebDriverApi接口详解
查看>>