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();
交由子类实现EmbeddedWebApplicationContext
(public 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 {}
覆写postProcessBeforeInitialization
和postProcessAfterInitialization
方法,其大概的调用顺序可以简单理解为:
调用顺序 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);
然后将其加入到context
中context.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
注册了各种属于web
的scope
registerEnvironmentBeans
注册了web
特定的contextParameters
,contextAttributes
等
getServletContextInitializerBeans()
实现为
protected Collection<ServletContextInitializer> getServletContextInitializerBeans() { return new ServletContextInitializerBeans(getBeanFactory()); }
ServletContextInitializerBeans
为Collection
的子类,继承了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
中的XxxRegistrationBean
与web
中的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
,只要将其申明为bean
后spring 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
排序后赋值给sortedList
,sortedList
为该集合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#getEmbeddedServletContainer
中getTomcatEmbeddedServletContainer(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
欢迎关注,您的肯定是对我最大的支持
- spring boot实战(第十五篇)嵌入tomcat源码分析
- spring boot实战(第十五篇)嵌入tomcat源码分析
- spring boot实战(第三篇)事件监听源码分析
- spring boot实战(第九篇)Application创建源码分析
- spring boot实战(第十四篇)整合RabbitMQ源码分析前言
- spring boot实战(第三篇)事件监听源码分析
- spring boot实战(第三篇)事件监听源码分析
- spring boot实战(第九篇)Application创建源码分析
- spring boot实战(第十四篇)整合RabbitMQ源码分析前言
- spring boot实战(第十篇)Spring boot Bean加载源码分析
- spring boot实战(第十篇)Spring boot Bean加载源码分析
- javaweb——嵌入tomcat(spring-boot)
- Spring boot 嵌入的tomcat不启动
- Spring Boot 源码分析
- spring boot实战(第六篇)加载application资源文件源码分析
- spring boot实战(第六篇)加载application资源文件源码分析
- spring boot实战(第七篇)内嵌容器tomcat配置
- spring boot实战(第七篇)内嵌容器tomcat配置
- pyqt4文档阅读(6):QGridLayout
- virtualBox安装增强功能转载
- opengl 矩阵
- 第一行代码:向下一个活动传递数据
- ssh用法及命令
- spring boot实战(第十五篇)嵌入tomcat源码分析
- POJ-1006 Biorhythms 【中国剩余定理模板】
- Node.js基于浏览器聊天室
- 数据排列
- poj3349(Hash)
- jQuery中json对象与json字符串互换
- 完全搬家了
- 浏览器跨域通信
- 限制一个UITextField的输入长度