码迷,mamicode.com
首页 > 编程语言 > 详细

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

时间:2016-08-25 21:43:18      阅读:424      评论:0      收藏:0      [点我收藏+]

标签:

嵌入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

其中EmbeddedServletContainerAutoConfiguration被加载


@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE)
@Configuration
@ConditionalOnWebApplication
@Import(BeanPostProcessorsRegistrar.class)
public class EmbeddedServletContainerAutoConfiguration {
  ...
}

@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();
        }

    }

优先创建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();  //释放缓存
            }
        }
    }

其中的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);
        }
    }

调用方法

 /**
     * 创建内嵌容器
     */
    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();
    }

getEmbeddedServletContainerFactory 获取容器工厂,通过

containerFactory.getEmbeddedServletContainer(getSelfInitializer());

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

return new ServletContextInitializer() {
            @Override
  prepareContext(tomcat.getHost(), initializers);           public void onStartup(ServletContext servletContext) throws ServletException {
                selfInitialize(servletContext);
            }
        }; customizer.customize(bean)

其中的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);
    }

首先构造一个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));

            }
        }

    }

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


public class EmbeddedServletContainerCustomizerBeanPostProcessor
        implements BeanPostProcessor, ApplicationContextAware {
}

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

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

@Override
    public Object postProcessBeforeInitialization(Object bean, String beanName)
            throws BeansException {
        if (bean instanceof ConfigurableEmbeddedServletContainer) {
            postProcessBeforeInitialization((ConfigurableEmbeddedServletContainer) bean);
        }
        return bean;
    }

调用postProcessBeforeInitialization方法


private void postProcessBeforeInitialization(
            ConfigurableEmbeddedServletContainer bean) {
        for (EmbeddedServletContainerCustomizer customizer : getCustomizers()) {  //
            customizer.customize(bean);
        }
    }

需要获取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;
    }

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

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

}

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()));
    }

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);
    }

首先设置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);
        }
    }

执行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());
            }
        }
    }

调用了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上
        }
    }
  • registerWebApplicationScopes注册了各种属于webscope
  • registerEnvironmentBeans注册了web特定的contextParameters,contextAttributes

getServletContextInitializerBeans()实现为

protected Collection<ServletContextInitializer> getServletContextInitializerBeans() {
        return new ServletContextInitializerBeans(getBeanFactory());
    }

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);
    }

首先看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);
    }

}

...

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

addServletContextInitializerBeans()方法


private void addServletContextInitializerBeans(ListableBeanFactory beanFactory) {
        for (Entry<String, ServletContextInitializer> initializerBean : getOrderedBeansOfType(
                beanFactory, ServletContextInitializer.class)) {
            addServletContextInitializerBean(initializerBean.getKey(),
                    initializerBean.getValue(), beanFactory);
        }
    }

获取所有类型为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);
        }
    }

如果类型为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);
        }
    }

将其类型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());
        }
    }

要看懂这块代码,首先要知道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));
                }
            }
        }
    }

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{
...
}
  • 方式二
@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>

这部分代码将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>

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


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




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

调用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>

通过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>

执行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);
        }
    }

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

至此内嵌tomcat分析完毕.


ok ~ it’s work ! more about is here

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

标签:

原文地址:http://blog.csdn.net/liaokailin/article/details/52269786

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!