spring boot实战(第十五篇)嵌入tomcat源码分析

嵌入tomcat源码分析

在启动spring boot工程时利用@SpringBootApplication注解,该注解启动@EnableAutoConfiguration自动配置,加载META-INF/spring.factories文件

# 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.web.EmbeddedServletContainerAutoConfiguration,\
 ...
org.springframework.boot.autoconfigure.webservices.WebServicesAutoConfiguration

 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

其中EmbeddedServletContainerAutoConfiguration被加载


@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE)
@Configuration
@ConditionalOnWebApplication
@Import(BeanPostProcessorsRegistrar.class)
public class EmbeddedServletContainerAutoConfiguration {
  ...
}
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

@ConditionalOnWebApplication注解表明只有在web环境下才会创建容器相关信息,因此应用无需容器则使用

new SpringApplicationBuilder(Xxx.class).web(false).run(args)实现。

TomcatEmbeddedServletContainerFactory.java


    @Configuration
    @ConditionalOnClass({ Servlet.class, Tomcat.class })
    @ConditionalOnMissingBean(value = EmbeddedServletContainerFactory.class, search = SearchStrategy.CURRENT)
    public static class EmbeddedTomcat {

        @Bean
        public TomcatEmbeddedServletContainerFactory tomcatEmbeddedServletContainerFactory() {
            return new TomcatEmbeddedServletContainerFactory();
        }

    }

 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

优先创建TomcatEmbeddedServletContainerFactory,由于存在@ConditionalOnMissingBean因此优先使用用户自定义的EmbeddedServletContainerFactory,

此时创建了工厂,但是tomcat是如何启动的呢?

spring boot中常使用的上下文为AnnotationConfigEmbeddedWebApplicationContext,通过前面的文章也知道加载BeanDefinition是在 
AbstractApplicationContext#refresh()方法中,具体详细的实现可以参考这里1 2,有阅读源码的备注信息.


public void refresh() throws BeansException, IllegalStateException {
        synchronized (this.startupShutdownMonitor) {  //同步锁
            // Prepare this context for refreshing.
            prepareRefresh();

            // Tell the subclass to refresh the internal bean factory.
            ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

            // Prepare the bean factory for use in this context.
            prepareBeanFactory(beanFactory);

            try {

                // Allows post-processing of the bean factory in context subclasses.
                postProcessBeanFactory(beanFactory);  //为BeanFactory设置后处理器,用依拓展

                // Invoke factory processors registered as beans in the context.
                invokeBeanFactoryPostProcessors(beanFactory);  //执行BeanFactoryPostProcessor,因此在执行BeanFactoryPostProcessor子类时,bean是没有被实例化的

                // Register bean processors that intercept bean creation.
                registerBeanPostProcessors(beanFactory);

                // Initialize message source for this context.
                initMessageSource();

                // Initialize event multicaster for this context.
                initApplicationEventMulticaster();

                // Initialize other special beans in specific context subclasses.
                onRefresh();

                // Check for listener beans and register them.
                registerListeners();

                // Instantiate all remaining (non-lazy-init) singletons.
                finishBeanFactoryInitialization(beanFactory);

                // Last step: publish corresponding event.
                finishRefresh();
            }

            catch (BeansException ex) {
                if (logger.isWarnEnabled()) {
                    logger.warn("Exception encountered during context initialization - " +
                            "cancelling refresh attempt: " + ex);
                }

                // Destroy already created singletons to avoid dangling resources.
                destroyBeans();

                // Reset 'active' flag.
                cancelRefresh(ex);

                // Propagate exception to caller.
                throw ex;
            }

            finally {
                // Reset common introspection caches in Spring's core, since we
                // might not ever need metadata for singleton beans anymore...
                resetCommonCaches();  //释放缓存
            }
        }
    }
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65

其中的onRefresh();交由子类实现EmbeddedWebApplicationContextpublic class AnnotationConfigEmbeddedWebApplicationContext 
extends EmbeddedWebApplicationContext

    @Override
    protected void onRefresh() {
        super.onRefresh();
        try {
            createEmbeddedServletContainer();
        }
        catch (Throwable ex) {
            throw new ApplicationContextException("Unable to start embedded container",
                    ex);
        }
    }

 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

调用方法

 /** * 创建内嵌容器 */
    private void createEmbeddedServletContainer() {
        EmbeddedServletContainer localContainer = this.embeddedServletContainer;
        ServletContext localServletContext = getServletContext();
        if (localContainer == null && localServletContext == null) {
            EmbeddedServletContainerFactory containerFactory = getEmbeddedServletContainerFactory();  //获取自动加载的工厂
            this.embeddedServletContainer = containerFactory
                    .getEmbeddedServletContainer(getSelfInitializer());
        }
        else if (localServletContext != null) {
            try {
                getSelfInitializer().onStartup(localServletContext);
            }
            catch (ServletException ex) {
                throw new ApplicationContextException("Cannot initialize servlet context",
                        ex);
            }
        }
        initPropertySources();
    }
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22

getEmbeddedServletContainerFactory 获取容器工厂,通过

containerFactory.getEmbeddedServletContainer(getSelfInitializer());
 
 
  • 1

创建一个内建容器,这里的getSelfInitializer()返回一个ServletContextInitializer,其实现为

return new ServletContextInitializer() {
            @Override
  prepareContext(tomcat.getHost(), initializers);           public void onStartup(ServletContext servletContext) throws ServletException {
                selfInitialize(servletContext);
            }
        }; customizer.customize(bean)
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

其中的selfInitialize(servletContext);等后续再回过来看,这里很关键。

继续看containerFactory.getEmbeddedServletContainer(getSelfInitializer());方法,默认调用TomcatEmbeddedServletContainerFactory中的方法:


@Override
    public EmbeddedServletContainer getEmbeddedServletContainer(
            ServletContextInitializer... initializers) {
        Tomcat tomcat = new Tomcat();  //构建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);
        tomcat.getEngine().setBackgroundProcessorDelay(-1);
        for (Connector additionalConnector : this.additionalTomcatConnectors) {
            tomcat.getService().addConnector(additionalConnector);
        }
        prepareContext(tomcat.getHost(), initializers);
        return getTomcatEmbeddedServletContainer(tomcat);
    }
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

首先构造一个tomcat实例,设置connector信息,在customizeConnector(connector)中会设置端口等其他配置信息,那么有个疑问来了,tomcat中的配置信息是怎么加载的?

那么又要回到EmbeddedServletContainerAutoConfiguration类,其申明@Import(BeanPostProcessorsRegistrar.class),那么需要看下BeanPostProcessorsRegistrar,其实现很简单


public static class BeanPostProcessorsRegistrar implements ImportBeanDefinitionRegistrar, BeanFactoryAware {

        private ConfigurableListableBeanFactory beanFactory;

        /** * 在解析import的时候自动绑定各种aware * @param beanFactory * @throws BeansException */
        @Override
        public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
            if (beanFactory instanceof ConfigurableListableBeanFactory) {
                this.beanFactory = (ConfigurableListableBeanFactory) beanFactory;
            }
        }

        @Override
        public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata,
                BeanDefinitionRegistry registry) {
            if (this.beanFactory == null) {
                return;
            }
            if (ObjectUtils.isEmpty(this.beanFactory.getBeanNamesForType(
                    EmbeddedServletContainerCustomizerBeanPostProcessor.class, true,
                    false))) {
                registry.registerBeanDefinition(
                        "embeddedServletContainerCustomizerBeanPostProcessor",
                        new RootBeanDefinition(
                                EmbeddedServletContainerCustomizerBeanPostProcessor.class));

            }
            if (ObjectUtils.isEmpty(this.beanFactory.getBeanNamesForType(
                    ErrorPageRegistrarBeanPostProcessor.class, true, false))) {
                registry.registerBeanDefinition("errorPageRegistrarBeanPostProcessor",
                        new RootBeanDefinition(
                                ErrorPageRegistrarBeanPostProcessor.class));

            }
        }

    }
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43

registerBeanDefinitions注册了一个名称为embeddedServletContainerCustomizerBeanPostProcessor的bean,其类型为EmbeddedServletContainerCustomizerBeanPostProcessor(在自定义Beandefinition时可以采用BeanDefinitionBuilder工具类),该bean为一个bean的后处理器


public class EmbeddedServletContainerCustomizerBeanPostProcessor implements BeanPostProcessor, ApplicationContextAware {
}
 
 
  • 1
  • 2
  • 3
  • 4

覆写postProcessBeforeInitializationpostProcessAfterInitialization方法,其大概的调用顺序可以简单理解为:

 调用顺序
  BeanFactoryPostProcessor#postProcessBeanFactory -> 构造方法 -> ApplicationContextAware#setApplicationContext -> BeanPostProcessor#postProcessBeforeInitialization-> PostConstruct注解方法 -> InitializingBean#afterPropertiesSet -> BeanPostProcessor#postProcessAfterInitialization

 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

@Override
    public Object postProcessBeforeInitialization(Object bean, String beanName)
            throws BeansException {
        if (bean instanceof ConfigurableEmbeddedServletContainer) {
            postProcessBeforeInitialization((ConfigurableEmbeddedServletContainer) bean);
        }
        return bean;
    }
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

调用postProcessBeforeInitialization方法


private void postProcessBeforeInitialization(
            ConfigurableEmbeddedServletContainer bean) {
        for (EmbeddedServletContainerCustomizer customizer : getCustomizers()) {  //
            customizer.customize(bean);
        }
    }
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

需要获取getCustomizers


private Collection<EmbeddedServletContainerCustomizer> getCustomizers() {
        if (this.customizers == null) {
            // Look up does not include the parent context
            this.customizers = new ArrayList<EmbeddedServletContainerCustomizer>(
                    this.applicationContext
                            .getBeansOfType(EmbeddedServletContainerCustomizer.class,
                                    false, false)
                            .values());
            Collections.sort(this.customizers, AnnotationAwareOrderComparator.INSTANCE);
            this.customizers = Collections.unmodifiableList(this.customizers);
        }
        return this.customizers;
    }
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

获取EmbeddedServletContainerCustomizer类型的bean,调用其customizer.customize(bean),那么来看下ServerProperties的实现

@ConfigurationProperties(prefix = "server", ignoreUnknownFields = true)
public class ServerProperties implements EmbeddedServletContainerCustomizer, EnvironmentAware, Ordered {

}
 
 
  • 1
  • 2
  • 3
  • 4
  • 5

customize方法为

public void customize(ConfigurableEmbeddedServletContainer container) {
        if (getPort() != null) {
            container.setPort(getPort());
        }
        if (getAddress() != null) {
            container.setAddress(getAddress());
        }
        if (getContextPath() != null) {
            container.setContextPath(getContextPath());
        }
        if (getDisplayName() != null) {
            container.setDisplayName(getDisplayName());
        }
        if (getSession().getTimeout() != null) {
            container.setSessionTimeout(getSession().getTimeout());
        }
        container.setPersistSession(getSession().isPersistent());
        container.setSessionStoreDir(getSession().getStoreDir());
        if (getSsl() != null) {
            container.setSsl(getSsl());
        }
        if (getJspServlet() != null) {
            container.setJspServlet(getJspServlet());
        }
        if (getCompression() != null) {
            container.setCompression(getCompression());
        }
        container.setServerHeader(getServerHeader());
        if (container instanceof TomcatEmbeddedServletContainerFactory) {
            getTomcat().customizeTomcat(this,
                    (TomcatEmbeddedServletContainerFactory) container);
        }
        if (container instanceof JettyEmbeddedServletContainerFactory) {
            getJetty().customizeJetty(this,
                    (JettyEmbeddedServletContainerFactory) container);
        }

        if (container instanceof UndertowEmbeddedServletContainerFactory) {
            getUndertow().customizeUndertow(this,
                    (UndertowEmbeddedServletContainerFactory) container);
        }
        container.addInitializers(new SessionConfiguringInitializer(this.session));
        container.addInitializers(new InitParameterConfiguringServletContextInitializer(
                getContextParameters()));
    }

 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46

container设置了各种属性值,至此,内嵌容器属性赋值解释完毕,继续看前面的prepareContext(tomcat.getHost(), initializers);方法


protected void prepareContext(Host host, ServletContextInitializer[] initializers) {
        File docBase = getValidDocumentRoot();
        docBase = (docBase != null ? docBase : createTempDir("tomcat-docbase"));
        TomcatEmbeddedContext context = new TomcatEmbeddedContext();  //上下文,继承StandardContext
        context.setName(getContextPath());
        context.setDisplayName(getDisplayName());
        context.setPath(getContextPath());
        context.setDocBase(docBase.getAbsolutePath());
        context.addLifecycleListener(new FixContextListener());
        context.setParentClassLoader(
                this.resourceLoader != null ? this.resourceLoader.getClassLoader()
                        : ClassUtils.getDefaultClassLoader());
        try {
            context.setUseRelativeRedirects(false);
            context.setMapperContextRootRedirectEnabled(true);
        }
        catch (NoSuchMethodError ex) {
            // Tomcat is < 8.0.30. Continue
        }
        SkipPatternJarScanner.apply(context, this.tldSkip);
        WebappLoader loader = new WebappLoader(context.getParentClassLoader());
        loader.setLoaderClass(TomcatEmbeddedWebappClassLoader.class.getName());
        loader.setDelegate(true);
        context.setLoader(loader);
        if (isRegisterDefaultServlet()) {
            addDefaultServlet(context);
        }
        if (shouldRegisterJspServlet()) {
            addJspServlet(context);
            addJasperInitializer(context);
            context.addLifecycleListener(new StoreMergedWebXmlListener());
        }
        ServletContextInitializer[] initializersToUse = mergeInitializers(initializers);
        configureContext(context, initializersToUse);
        host.addChild(context);
        postProcessContext(context);
    }
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38

首先设置TomcatEmbeddedContext上下文,它为StandardContext子类,后续设置上下文的若干属性,例如上下文路径等,

执行configureContext

protected void configureContext(Context context,
            ServletContextInitializer[] initializers) {
        TomcatStarter starter = new TomcatStarter(initializers);
        if (context instanceof TomcatEmbeddedContext) {
            // Should be true
            ((TomcatEmbeddedContext) context).setStarter(starter);
        }
        context.addServletContainerInitializer(starter, NO_CLASSES);
        for (LifecycleListener lifecycleListener : this.contextLifecycleListeners) {
            context.addLifecycleListener(lifecycleListener);
        }
        for (Valve valve : this.contextValves) {
            context.getPipeline().addValve(valve);
        }
        for (ErrorPage errorPage : getErrorPages()) {
            new TomcatErrorPage(errorPage).addToContext(context);
        }
        for (MimeMappings.Mapping mapping : getMimeMappings()) {
            context.addMimeMapping(mapping.getExtension(), mapping.getMimeType());
        }
        configureSession(context);
        for (TomcatContextCustomizer customizer : this.tomcatContextCustomizers) {
            customizer.customize(context);
        }
    }
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25

执行TomcatStarter starter = new TomcatStarter(initializers);然后将其加入到contextcontext.addServletContainerInitializer(starter, NO_CLASSES);,则会在tomcat启动时会调用start中的onStartup方法

@Override
    public void onStartup(Set<Class<?>> classes, ServletContext servletContext)
            throws ServletException {
        try {
            for (ServletContextInitializer initializer : this.initializers) {
                initializer.onStartup(servletContext);
            }
        }
        catch (Exception ex) {
            this.startUpException = ex;
            // Prevent Tomcat from logging and re-throwing when we know we can
            // deal with it in the main thread, but log for information here.
            if (logger.isErrorEnabled()) {
                logger.error("Error starting Tomcat context. Exception: "
                        + ex.getClass().getName() + ". Message: " + ex.getMessage());
            }
        }
    }
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

调用了initializer.onStartup(servletContext); 则可以回到前面提到的`selfInitialize(servletContext);


private void selfInitialize(ServletContext servletContext) throws ServletException {
        prepareEmbeddedWebApplicationContext(servletContext);
        ConfigurableListableBeanFactory beanFactory = getBeanFactory();
        ExistingWebApplicationScopes existingScopes = new ExistingWebApplicationScopes(
                beanFactory);  //设置web scope
        WebApplicationContextUtils.registerWebApplicationScopes(beanFactory,
                getServletContext());
        existingScopes.restore();
        WebApplicationContextUtils.registerEnvironmentBeans(beanFactory,
                getServletContext());
        for (ServletContextInitializer beans : getServletContextInitializerBeans()) {  //核心方法
            beans.onStartup(servletContext);  //servlet、filter和listen都会注册到ServletContext上
        }
    }
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • registerWebApplicationScopes注册了各种属于webscope
  • registerEnvironmentBeans注册了web特定的contextParameters,contextAttributes

getServletContextInitializerBeans()实现为

protected Collection<ServletContextInitializer> getServletContextInitializerBeans() {
        return new ServletContextInitializerBeans(getBeanFactory());
    }
 
 
  • 1
  • 2
  • 3

ServletContextInitializerBeansCollection的子类,继承了AbstractCollection,调用构造方法

    public ServletContextInitializerBeans(ListableBeanFactory beanFactory) {
        this.initializers = new LinkedMultiValueMap<Class<?>, ServletContextInitializer>();
        addServletContextInitializerBeans(beanFactory);  //处理ServletContextInitializer
        addAdaptableBeans(beanFactory);  //核心方法,将所有申明的Servlet ,Filter等转换成对应的XxxRegistrationBean
        List<ServletContextInitializer> sortedInitializers = new ArrayList<ServletContextInitializer>();
        for (Map.Entry<?, List<ServletContextInitializer>> entry : this.initializers
                .entrySet()) {
            AnnotationAwareOrderComparator.sort(entry.getValue());
            sortedInitializers.addAll(entry.getValue());
        }
        this.sortedList = Collections.unmodifiableList(sortedInitializers);
    }
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

首先看this.initializers = new LinkedMultiValueMap<Class<?>, ServletContextInitializer>(); 其中的initializers为一个多值的map结构, 
简单来说就是map中的key对应多个value,其内部实现看LinkedMultiValueMap,利用Map<K, List<V>> targetMap内部属性来实现。

public class LinkedMultiValueMap<K, V> implements MultiValueMap<K, V>, Serializable {

    private static final long serialVersionUID = 3801124242820219131L;

    private final Map<K, List<V>> targetMap;
    @Override
    public void add(K key, V value) {
        List<V> values = this.targetMap.get(key);
        if (values == null) {
            values = new LinkedList<V>();
            this.targetMap.put(key, values);
        }
        values.add(value);
    }

}

...

 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

更多集合操作可以使用guava避免重复造轮子

addServletContextInitializerBeans()方法


private void addServletContextInitializerBeans(ListableBeanFactory beanFactory) {
        for (Entry<String, ServletContextInitializer> initializerBean : getOrderedBeansOfType(
                beanFactory, ServletContextInitializer.class)) {
            addServletContextInitializerBean(initializerBean.getKey(),
                    initializerBean.getValue(), beanFactory);
        }
    }
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

获取所有类型为ServletContextInitializer,进入如下处理


private void addServletContextInitializerBean(String beanName,
            ServletContextInitializer initializer, ListableBeanFactory beanFactory) {
        if (initializer instanceof ServletRegistrationBean) {
            Servlet source = ((ServletRegistrationBean) initializer).getServlet();
            addServletContextInitializerBean(Servlet.class, beanName, initializer,
                    beanFactory, source);
        }
        else if (initializer instanceof FilterRegistrationBean) {
            Filter source = ((FilterRegistrationBean) initializer).getFilter();
            addServletContextInitializerBean(Filter.class, beanName, initializer,
                    beanFactory, source);
        }
        else if (initializer instanceof DelegatingFilterProxyRegistrationBean) {
            String source = ((DelegatingFilterProxyRegistrationBean) initializer)
                    .getTargetBeanName();
            addServletContextInitializerBean(Filter.class, beanName, initializer,
                    beanFactory, source);
        }
        else if (initializer instanceof ServletListenerRegistrationBean) {
            EventListener source = ((ServletListenerRegistrationBean<?>) initializer)
                    .getListener();
            addServletContextInitializerBean(EventListener.class, beanName, initializer,
                    beanFactory, source);
        }
        else {
            addServletContextInitializerBean(ServletContextInitializer.class, beanName,
                    initializer, beanFactory, null);
        }
    }
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30

如果类型为FilterRegistrationBean,DelegatingFilterProxyRegistrationBean,ServletRegistrationBean,ServletListenerRegistrationBean分别对应到Filter,Filter,Servlet,EventListener,调用


private void addServletContextInitializerBean(Class<?> type, String beanName,
            ServletContextInitializer initializer, ListableBeanFactory beanFactory,
            Object source) {
        this.initializers.add(type, initializer);
        if (source != null) {
            // Mark the underlying source as seen in case it wraps an existing bean
            this.seen.add(source);
        }
        if (ServletContextInitializerBeans.logger.isDebugEnabled()) {
            String resourceDescription = getResourceDescription(beanName, beanFactory);
            int order = getOrder(initializer);
            ServletContextInitializerBeans.logger.debug("Added existing "
                    + type.getSimpleName() + " initializer bean '" + beanName
                    + "'; order=" + order + ", resource=" + resourceDescription);
        }
    }

 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

将其类型type作为key存储在initializers中,seen记录处理过的source避免重复处理。 
这里将spring boot中的XxxRegistrationBeanweb中的servlet,filter,listen等对应起来,因此后期处理web中的元素,只需要处理XxxRegistrationBean即可。

继续看addAdaptableBeans(beanFactory);方法


private void addAdaptableBeans(ListableBeanFactory beanFactory) {
        MultipartConfigElement multipartConfig = getMultipartConfig(beanFactory);
        addAsRegistrationBean(beanFactory, Servlet.class,
                new ServletRegistrationBeanAdapter(multipartConfig));  //将所有类型的Servlet对应bean转换成ServletRegistrationBean
        addAsRegistrationBean(beanFactory, Filter.class,
                new FilterRegistrationBeanAdapter());
        for (Class<?> listenerType : ServletListenerRegistrationBean
                .getSupportedTypes()) {  //处理servlet中支持的监听
            addAsRegistrationBean(beanFactory, EventListener.class,
                    (Class<EventListener>) listenerType,
                    new ServletListenerRegistrationBeanAdapter());
        }
    }
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

要看懂这块代码,首先要知道addAsRegistrationBean的作用


private <T, B extends T> void addAsRegistrationBean(ListableBeanFactory beanFactory,
            Class<T> type, Class<B> beanType, RegistrationBeanAdapter<T> adapter) {
        List<Map.Entry<String, B>> beans = getOrderedBeansOfType(beanFactory, beanType,
                this.seen);  //this.seen被排除掉,前面已处理
        for (Entry<String, B> bean : beans) {
            if (this.seen.add(bean.getValue())) {
                int order = getOrder(bean.getValue());
                String beanName = bean.getKey();
                // One that we haven't already seen
                RegistrationBean registration = adapter.createRegistrationBean(beanName,
                        bean.getValue(), beans.size());
                registration.setName(beanName);
                registration.setOrder(order);
                this.initializers.add(type, registration);
                if (ServletContextInitializerBeans.logger.isDebugEnabled()) {
                    ServletContextInitializerBeans.logger.debug(
                            "Created " + type.getSimpleName() + " initializer for bean '"
                                    + beanName + "'; order=" + order + ", resource="
                                    + getResourceDescription(beanName, beanFactory));
                }
            }
        }
    }
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24

FilterRegistration.Dynamic 
组合起来看,发现其功能:将所有的servlet,filter,listener对应的bean适配成XxxRegistrationBean,然后存入initializers集合中。

通过前面代码可以发现,在spring boot中可以直接申明的servlet,fiter或者listener,只要将其申明为beanspring boot自然识别, 
因此在spring boot中申明filter有两种方式(servlet,listener)一样

伪代码如下:

  • 方式一

@Component
public MyFilter implements Filter{
...
}

 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 方式二
@Bean
public FilterRegistrationBean myFilter(){
  FilterRegistrationBean bean = new FilterRegistrationBean();
  bean.setFilter(MyFilter.class);
  bean.addUrlPatterns("/*");
  return bean;  
}


这种将外部对象统一适配为内部对象后,只要处理内部对象即可完成对内部对象+外部对象的处理思路值得学习。

<hr>

继续来看前面的代码

```java

List<ServletContextInitializer> sortedInitializers = new ArrayList<ServletContextInitializer>();
        for (Map.Entry<?, List<ServletContextInitializer>> entry : this.initializers
                .entrySet()) {
            AnnotationAwareOrderComparator.sort(entry.getValue());
            sortedInitializers.addAll(entry.getValue());
        }
        this.sortedList = Collections.unmodifiableList(sortedInitializers);




<div class="se-preview-section-delimiter"></div>

 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30

这部分代码将initializers排序后赋值给sortedListsortedList为该集合ServletContextInitializerBeans核心属性,遍历集合时则遍历的为 
sortedList


    @Override
    public Iterator<ServletContextInitializer> iterator() {
        return this.sortedList.iterator();
    }  //迭代时遍历sortedList

    @Override
    public int size() {
        return this.sortedList.size();
    }





<div class="se-preview-section-delimiter"></div>

 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

至此处理完成ServletContextInitializerBeans,回到前面的


for (ServletContextInitializer beans : getServletContextInitializerBeans()) {  //核心方法
            beans.onStartup(servletContext);  //servlet、filter和listen都会注册到ServletContext上
        }




<div class="se-preview-section-delimiter"></div>

 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

调用onStartup方法

针对FilterRegistrationBean执行

public void onStartup(ServletContext servletContext) throws ServletException {
        Filter filter = getFilter();
        Assert.notNull(filter, "Filter must not be null");
        String name = getOrDeduceName(filter);
        if (!isEnabled()) {
            this.logger.info("Filter " + name + " was not registered (disabled)");
            return;
        }
        FilterRegistration.Dynamic added = servletContext.addFilter(name, filter);  //动态添加filter
        if (added == null) {
            this.logger.info("Filter " + name + " was not registered "
                    + "(possibly already registered?)");
            return;
        }
        configure(added);  //filter映射到/*
    }





<div class="se-preview-section-delimiter"></div>

 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23

通过FilterRegistration.Dynamic动态添加filter

ServletRegistrationBean,ServletListenerRegistrationBean代码逻辑和FilterRegistrationBean逻辑类似。

又要回到TomcatEmbeddedServletContainerFactory#getEmbeddedServletContainergetTomcatEmbeddedServletContainer(tomcat);


protected TomcatEmbeddedServletContainer getTomcatEmbeddedServletContainer(
            Tomcat tomcat) {
        return new TomcatEmbeddedServletContainer(tomcat, getPort() >= 0);
    }




<div class="se-preview-section-delimiter"></div>

 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

执行initialize方法

private synchronized void initialize() throws EmbeddedServletContainerException {
        TomcatEmbeddedServletContainer.logger
                .info("Tomcat initialized with port(s): " + getPortsDescription(false));
        try {
            addInstanceIdToEngineName();

            // Remove service connectors to that protocol binding doesn't happen yet
            removeServiceConnectors();

            // Start the server to trigger initialization listeners
            this.tomcat.start();

            // We can re-throw failure exception directly in the main thread
            rethrowDeferredStartupExceptions();

            Context context = findContext();
            try {
                ContextBindings.bindClassLoader(context, getNamingToken(context),
                        getClass().getClassLoader());
            }
            catch (NamingException ex) {
                // Naming is not enabled. Continue
            }

            // Unlike Jetty, all Tomcat threads are daemon threads. We create a
            // blocking non-daemon to stop immediate shutdown
            startDaemonAwaitThread();  //tomcat需要调用tomcat.getServer().await()阻塞
        }
        catch (Exception ex) {
            throw new EmbeddedServletContainerException("Unable to start embedded Tomcat",
                    ex);
        }
    }

 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34

调用this.tomcat.start()开启tomcat,然后通过startDaemonAwaitThread执行this.tomcat.getServer().await()阻塞当前线程。

至此内嵌tomcat分析完毕.

ok ~ it’s work ! more about is here


执行`initialize`方法

```java
private synchronized void initialize() throws EmbeddedServletContainerException {
        TomcatEmbeddedServletContainer.logger
                .info("Tomcat initialized with port(s): " + getPortsDescription(false));
        try {
            addInstanceIdToEngineName();

            // Remove service connectors to that protocol binding doesn't happen yet
            removeServiceConnectors();

            // Start the server to trigger initialization listeners
            this.tomcat.start();

            // We can re-throw failure exception directly in the main thread
            rethrowDeferredStartupExceptions();

            Context context = findContext();
            try {
                ContextBindings.bindClassLoader(context, getNamingToken(context),
                        getClass().getClassLoader());
            }
            catch (NamingException ex) {
                // Naming is not enabled. Continue
            }

            // Unlike Jetty, all Tomcat threads are daemon threads. We create a
            // blocking non-daemon to stop immediate shutdown
            startDaemonAwaitThread();  //tomcat需要调用tomcat.getServer().await()阻塞
        }
        catch (Exception ex) {
            throw new EmbeddedServletContainerException("Unable to start embedded Tomcat",
                    ex);
        }
    }

 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38

调用this.tomcat.start()开启tomcat,然后通过startDaemonAwaitThread执行this.tomcat.getServer().await()阻塞当前线程。

至此内嵌tomcat分析完毕.

ok ~ it’s work ! more about is here

本文转自http://blog.csdn.net/liaokailin/article/details/52269786

    原文作者:Spring Boot
    原文地址: https://blog.csdn.net/tongtong_use/article/details/78651813
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞