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

来源:互联网 发布:淘宝怎么联系店家客服 编辑:程序博客网 时间:2024/04/27 15:04

嵌入tomcat源码分析

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

# Auto Configureorg.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)一样

伪代码如下:

  • 方式一
@Componentpublic MyFilter implements Filter{...}
  • 方式二
@Beanpublic FilterRegistrationBean myFilter(){  FilterRegistrationBean bean = new FilterRegistrationBean();  bean.setFilter(MyFilter.class);  bean.addUrlPatterns("/*");  return bean;  }这种将外部对象统一适配为内部对象后,只要处理内部对象即可完成对内部对象+外部对象的处理思路值得学习。<hr>继续来看前面的代码```javaList<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

执行`initialize`方法```javaprivate 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

转载请注明
http://blog.csdn.net/liaokailin/article/details/52269786

欢迎关注,您的肯定是对我最大的支持

这里写图片描述

2 0