关键词:
SpringBoot中提供了自动配置功能,嵌入式Servlet容器也是通过自动配置完成配置的。默认使用tomcat。我们可以通过starter-web的依赖窥见。
一、EmbeddedServletContainerAutoConfiguration
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE)
@Configuration
@ConditionalOnWebApplication
@Import(BeanPostProcessorsRegistrar.class)
public class EmbeddedServletContainerAutoConfiguration
/**
* Nested configuration if Tomcat is being used.
*/
@Configuration
@ConditionalOnClass( Servlet.class, Tomcat.class )
@ConditionalOnMissingBean(value = EmbeddedServletContainerFactory.class, search = SearchStrategy.CURRENT)
public static class EmbeddedTomcat
@Bean
public TomcatEmbeddedServletContainerFactory tomcatEmbeddedServletContainerFactory()
return new TomcatEmbeddedServletContainerFactory();
@Configuration
@ConditionalOnClass( Servlet.class, Server.class, Loader.class,
WebAppContext.class )
@ConditionalOnMissingBean(value = EmbeddedServletContainerFactory.class, search = SearchStrategy.CURRENT)
public static class EmbeddedJetty
@Bean
public JettyEmbeddedServletContainerFactory jettyEmbeddedServletContainerFactory()
return new JettyEmbeddedServletContainerFactory();
@Configuration
@ConditionalOnClass( Servlet.class, Undertow.class, SslClientAuthMode.class )
@ConditionalOnMissingBean(value = EmbeddedServletContainerFactory.class, search = SearchStrategy.CURRENT)
public static class EmbeddedUndertow
@Bean
public UndertowEmbeddedServletContainerFactory undertowEmbeddedServletContainerFactory()
return new UndertowEmbeddedServletContainerFactory();
- 当满足web环境
@ConditionalOnWebApplication
的时候,该自动配置类生效,在内部定义了静态内部类EmbeddedTomcat
、EmbeddedUndertow
、EmbeddedJetty
,即SpringBoot默认支持三种嵌入式Servlet容器,分别在满足的时候自动配置。他们三者都是在容器中没有EmbeddedServletContainerFactory
的时候才配置,说明最多只会装配一种容器。以Tomcat为例,它往容器中添加了一个Bean(TomcatEmbeddedServletContainerFactory
),该类实现了EmbeddedServletContainerFactory
,它用于创建Servlet容器EmbeddedServletContainer
。EmbeddedServletContainerFactory
的作用后面再表。
如果我们想换一种容器,我们简单地排除tomcat依赖,引入其容器依赖即可。例如Jetty。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring‐boot‐starter‐web</artifactId>
<exclusions>
<exclusion>
<artifactId>spring‐boot‐starter‐tomcat</artifactId>
<groupId>org.springframework.boot</groupId>
</exclusion>
</exclusions>
</dependency>
<!‐‐引入其他的Servlet容器‐‐>
<dependency>
<artifactId>spring‐boot‐starter‐jetty</artifactId>
<groupId>org.springframework.boot</groupId>
</dependency>
public interface EmbeddedServletContainerFactory
/**
* Gets a new fully configured but paused @link EmbeddedServletContainer instance.
* Clients should not be able to connect to the returned server until
* @link EmbeddedServletContainer#start() is called (which happens when the
* @link ApplicationContext has been fully refreshed).
* @param initializers @link ServletContextInitializers that should be applied as
* the container starts
* @return a fully configured and started @link EmbeddedServletContainer
* @see EmbeddedServletContainer#stop()
*/
EmbeddedServletContainer getEmbeddedServletContainer(
ServletContextInitializer... initializers);
EmbeddedServletContainerAutoConfiguration
还通过@Import
导入了BeanPostProcessorsRegistrar
。它往容器中导入了两个Bean:EmbeddedServletContainerCustomizerBeanPostProcessor
和ErrorPageRegistrarBeanPostProcessor
。
public static class BeanPostProcessorsRegistrar
implements ImportBeanDefinitionRegistrar, BeanFactoryAware
private ConfigurableListableBeanFactory beanFactory;
@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;
registerSyntheticBeanIfMissing(registry,
"embeddedServletContainerCustomizerBeanPostProcessor",
EmbeddedServletContainerCustomizerBeanPostProcessor.class);
registerSyntheticBeanIfMissing(registry,
"errorPageRegistrarBeanPostProcessor",
ErrorPageRegistrarBeanPostProcessor.class);
private void registerSyntheticBeanIfMissing(BeanDefinitionRegistry registry,
String name, Class<?> beanClass)
if (ObjectUtils.isEmpty(
this.beanFactory.getBeanNamesForType(beanClass, true, false)))
RootBeanDefinition beanDefinition = new RootBeanDefinition(beanClass);
beanDefinition.setSynthetic(true);
registry.registerBeanDefinition(name, beanDefinition);
EmbeddedServletContainerCustomizerBeanPostProcessor
提供了对嵌入式容器自定义配置的功能,对ConfigurableEmbeddedServletContainer
这种类型的Bean进行定制化,而具体的容器工厂类TomcatEmbeddedServletContainerFactory
正好就是ConfigurableEmbeddedServletContainer
。- 具体是从容器中获取所有的
EmbeddedServletContainerCustomizer
,然后一一调用完成定制化。所以如果我们想定制容器,我们可以往容器中放入EmbeddedServletContainerCustomizer
即可。
public class EmbeddedServletContainerCustomizerBeanPostProcessor
implements BeanPostProcessor, BeanFactoryAware
private ListableBeanFactory beanFactory;
private List<EmbeddedServletContainerCustomizer> customizers;
@Override
public void setBeanFactory(BeanFactory beanFactory)
Assert.isInstanceOf(ListableBeanFactory.class, beanFactory,
"EmbeddedServletContainerCustomizerBeanPostProcessor can only be used "
+ "with a ListableBeanFactory");
this.beanFactory = (ListableBeanFactory) beanFactory;
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName)
throws BeansException
if (bean instanceof ConfigurableEmbeddedServletContainer)
postProcessBeforeInitialization((ConfigurableEmbeddedServletContainer) bean);
return bean;
@Override
public Object postProcessAfterInitialization(Object bean, String beanName)
throws BeansException
return bean;
private void postProcessBeforeInitialization(
ConfigurableEmbeddedServletContainer bean)
for (EmbeddedServletContainerCustomizer customizer : getCustomizers())
customizer.customize(bean);
private Collection<EmbeddedServletContainerCustomizer> getCustomizers()
if (this.customizers == null)
// Look up does not include the parent context
this.customizers = new ArrayList<EmbeddedServletContainerCustomizer>(
this.beanFactory
.getBeansOfType(EmbeddedServletContainerCustomizer.class,
false, false)
.values());
Collections.sort(this.customizers, AnnotationAwareOrderComparator.INSTANCE);
this.customizers = Collections.unmodifiableList(this.customizers);
return this.customizers;
ConfigurableEmbeddedServletContainer
提供了如下配置项
public interface ConfigurableEmbeddedServletContainer extends ErrorPageRegistry
/**
* Sets the context path for the embedded servlet container. The context should start
* with a "/" character but not end with a "/" character. The default context path can
* be specified using an empty string.
* @param contextPath the contextPath to set
*/
void setContextPath(String contextPath);
/**
* Sets the display name of the application deployed in the embedded servlet
* container.
* @param displayName the displayName to set
* @since 1.3.0
*/
void setDisplayName(String displayName);
/**
* Sets the port that the embedded servlet container should listen on. If not
* specified port '8080' will be used. Use port -1 to disable auto-start (i.e start
* the web application context but not have it listen to any port).
* @param port the port to set
*/
void setPort(int port);
/**
* The session timeout in seconds (default 30 minutes). If 0 or negative then sessions
* never expire.
* @param sessionTimeout the session timeout
*/
void setSessionTimeout(int sessionTimeout);
/**
* The session timeout in the specified @link TimeUnit (default 30 minutes). If 0 or
* negative then sessions never expire.
* @param sessionTimeout the session timeout
* @param timeUnit the time unit
*/
void setSessionTimeout(int sessionTimeout, TimeUnit timeUnit);
/**
* Sets if session data should be persisted between restarts.
* @param persistSession @code true if session data should be persisted
*/
void setPersistSession(boolean persistSession);
/**
* Set the directory used to store serialized session data.
* @param sessionStoreDir the directory or @code null to use a default location.
*/
void setSessionStoreDir(File sessionStoreDir);
/**
* Sets the specific network address that the server should bind to.
* @param address the address to set (defaults to @code null)
*/
void setAddress(InetAddress address);
/**
* Set if the DefaultServlet should be registered. Defaults to @code true so that
* files from the @link #setDocumentRoot(File) document root will be served.
* @param registerDefaultServlet if the default servlet should be registered
*/
void setRegisterDefaultServlet(boolean registerDefaultServlet);
/**
* Sets the error pages that will be used when handling exceptions.
* @param errorPages the error pages
*/
void setErrorPages(Set<? extends ErrorPage> errorPages);
/**
* Sets the mime-type mappings.
* @param mimeMappings the mime type mappings (defaults to
* @link MimeMappings#DEFAULT)
*/
void setMimeMappings(MimeMappings mimeMappings);
/**
* Sets the document root directory which will be used by the web context to serve
* static files.
* @param documentRoot the document root or @code null if not required
*/
void setDocumentRoot(File documentRoot);
/**
* Sets @link ServletContextInitializer that should be applied in addition to
* @link EmbeddedServletContainerFactory#getEmbeddedServletContainer(ServletContextInitializer...)
* parameters. This method will replace any previously set or added initializers.
* @param initializers the initializers to set
* @see #addInitializers
*/
void setInitializers(List<? extends ServletContextInitializer> initializers);
/**
* Add @link ServletContextInitializers to those that should be applied in addition
* to
* @link EmbeddedServletContainerFactory#getEmbeddedServletContainer(ServletContextInitializer...)
* parameters.
* @param initializers the initializers to add
* @see #setInitializers
*/
void addInitializers(ServletContextInitializer... initializers);
/**
* Sets the SSL configuration that will be applied to the container's default
* connector.
* @param ssl the SSL configuration
*/
void setSsl(Ssl ssl);
/**
* Sets a provider that will be used to obtain SSL stores.
* @param sslStoreProvider the SSL store provider
*/
void setSslStoreProvider(SslStoreProvider sslStoreProvider);
/**
* Sets the configuration that will be applied to the container's JSP servlet.
* @param jspServlet the JSP servlet configuration
*/
void setJspServlet(JspServlet jspServlet);
/**
* Sets the compression configuration that will be applied to the container's default
* connector.
* @param compression the compression configuration
*/
void setCompression(Compression compression);
/**
* Sets the server header value.
* @param serverHeader the server header value
*/
void setServerHeader(String serverHeader);
/**
* Sets the Locale to Charset mappings.
* @param localeCharsetMappings the Locale to Charset mappings
*/
void setLocaleCharsetMappings(Map<Locale, Charset> localeCharsetMappings);
ErrorPageRegistrarBeanPostProcessor
提供错误页面配置的功能,针对ErrorPageRegistry
,从容器中获取所有的ErrorPageRegistrar
,然后一一调用registerErrorPages。所以如果我们想注册error page,我们可以往容器中放入ErrorPageRegistrar
即可。
public class ErrorPageRegistrarBeanPostProcessor
implements BeanPostProcessor, BeanFactoryAware
private ListableBeanFactory beanFactory;
private List<ErrorPageRegistrar> registrars;
@Override
public void setBeanFactory(BeanFactory beanFactory)
Assert.isInstanceOf(ListableBeanFactory.class, beanFactory,
"ErrorPageRegistrarBeanPostProcessor can only be used "
+ "with a ListableBeanFactory");
this.beanFactory = (ListableBeanFactory) beanFactory;
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName)
throws BeansException
if (bean instanceof ErrorPageRegistry)
postProcessBeforeInitialization((ErrorPageRegistry) bean);
return bean;
@Override
public Object postProcessAfterInitialization(Object bean, String beanName)
throws BeansException
return bean;
private void postProcessBeforeInitialization(ErrorPageRegistry registry)
for (ErrorPageRegistrar registrar : getRegistrars())
registrar.registerErrorPages(registry);
private Collection<ErrorPageRegistrar> getRegistrars()
if (this.registrars == null)
// Look up does not include the parent context
this.registrars = new ArrayList<ErrorPageRegistrar>(this.beanFactory
.getBeansOfType(ErrorPageRegistrar.class, false, false).values());
Collections.sort(this.registrars, AnnotationAwareOrderComparator.INSTANCE);
this.registrars = Collections.unmodifiableList(this.registrars);
return this.registrars;
至此自动配置就完成了
二、容器是如何启动的
我们知道内嵌Servlet容器的情况下,我们启动SpringBoot的方式一般是SpringApplication.run()
方法,它使用的容器默认是AnnotationConfigEmbeddedWebApplicationContext
这种类型,它继承自EmbeddedWebApplicationContext
,这个类中的两个钩子方法完成容器的启动。
- createEmbeddedServletContainer
@Override
protected void onRefresh()
super.onRefresh();
try
createEmbeddedServletContainer();
catch (Throwable ex)
throw new ApplicationContextException("Unable to start embedded container",
ex);
@Override
protected void finishRefresh()
super.finishRefresh();
EmbeddedServletContainer localContainer = startEmbeddedServletContainer();
if (localContainer != null)
publishEvent(
new EmbeddedServletContainerInitializedEvent(this, localContainer));
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();
protected EmbeddedServletContainerFactory getEmbeddedServletContainerFactory()
// Use bean names so that we don't consider the hierarchy
String[] beanNames = getBeanFactory()
.getBeanNamesForType(EmbeddedServletContainerFactory.class);
if (beanNames.length == 0)
throw new ApplicationContextException(
"Unable to start EmbeddedWebApplicationContext due to missing "
+ "EmbeddedServletContainerFactory bean.");
if (beanNames.length > 1)
throw new ApplicationContextException(
"Unable to start EmbeddedWebApplicationContext due to multiple "
+ "EmbeddedServletContainerFactory beans : "
+ StringUtils.arrayToCommaDelimitedString(beanNames));
return getBeanFactory().getBean(beanNames[0],
EmbeddedServletContainerFactory.class);
private ServletContextInitializer getSelfInitializer()
return new ServletContextInitializer()
@Override
public void onStartup(ServletContext servletContext) throws ServletException
selfInitialize(servletContext);
;
private void selfInitialize(ServletContext servletContext) throws ServletException
prepareEmbeddedWebApplicationContext(servletContext);
Configurablspringboot嵌入式servlet容器自动配置原理和容器启动原理
1.嵌入式Servlet容器自动配置原理1.1在spring-boot-autoconfigure-1.5.9.RELEASE.jar=>springboot自动配置依赖jar包下,EmbeddedServletContainerAutoConfiguration=>嵌入式servlet容器自动配置类 @AutoConfigureOrder(Ordered.HIGHEST_P 查看详情
springboot使用嵌入式容器,自定义filter如何配置?
Listener、Filter和Servlet是JavaWeb开发过程中常用的三个组件,其中Filter组件的使用频率最高,经常被用来做简单的权限处理、请求头过滤和防止XSS***等。如果我们使用的是传统的SpringMVC进行开发,那么只需要在Tomcat的web.xml文件中进... 查看详情
springboot源码学习系列之嵌入式servlet容器
1、前言简单介绍SpringBoot的自动配置就是SpringBoot的精髓所在;对于SpringBoot项目是不需要配置Tomcat、jetty等等Servlet容器,直接启动application类既可,SpringBoot为什么能做到这么简捷?原因就是使用了内嵌的Servlet容器,默认是使用Tomc... 查看详情
springboot源码学习系列之嵌入式servlet容器
1、前言简单介绍SpringBoot的自动配置就是SpringBoot的精髓所在;对于SpringBoot项目是不需要配置Tomcat、jetty等等Servlet容器,直接启动application类既可,SpringBoot为什么能做到这么简捷?原因就是使用了内嵌的Servlet容器,默认是使用Tomc... 查看详情
springboot使用嵌入式容器,那怎么配置自定义filter呢
Listener、Filter和Servlet是JavaWeb开发过程中常用的三个组件,其中Filter组件的使用频率最高,经常被用来做简单的权限处理、请求头过滤和防止XSS攻击等。如果我们使用的是传统的SpringMVC进行开发,那么只需要在Tomcat的web.xml文件中... 查看详情
spring-boot使用嵌入式容器,那怎么配置自定义filter呢
Listener、Filter和Servlet是JavaWeb开发过程中常用的三个组件,其中Filter组件的使用频率最高,经常被用来做简单的权限处理、请求头过滤和防止XSS攻击等。如果我们使用的是传统的SpringMVC进行开发,那么只需要在Tomcat的web.xml文件中... 查看详情
springboot2-webrestfulcrud实验错误处理机制配置嵌入式servlet容器(代码片段)
springboot2-web、restfulCrud实验、错误处理机制、配置嵌入式Servlet容器、注册Servlet三大组件一、Web开发概略1.使用SpringBoot2.熟悉自动配置原理3.示例二、RestfulCRUD实验1.默认访问首页2.国际化3.链接切换页面语言4.CRUD-员工列表4.1实验要... 查看详情
配置嵌入式servlet容器(代码片段)
SpringBoot默认是用的是Tomcat作为嵌入式的Servlet容器;问题?1)、如何定制和修改Servlet容器的相关配置;1、修改和server有关的配置(ServerProperties):server.port=8081server.context-path=/crudserver.tomcat.uri-encoding=UTF-8//通用的Servlet容器设置se... 查看详情
springboot起飞系列-配置嵌入式servlet容器
一、前言springboot中默认使用的是tomcat容器,也叫做嵌入式的servlet容器。因为它和我们平常使用的tomcat容器不一样,这个tomcat直接嵌入到的springboot,平常我们使用tomcat容器是一个独立的应用,配置的时候需要在tomcat中的xml中配置... 查看详情
sprinhgboot2----自定义启动器(代码片段)
...在空项目创建两个模块,一个启动器模块,一个自动配置模块项目配置1:配置启动器依赖(启动器配置文件里面添加对自动配置模块项目的依赖)2:配置自动配置模块项目依赖3.编写自动配置模块里的业务逻辑4.创... 查看详情
springboot自动配置原理源码分析+自定义starter启动器+可视化监控+mybatisplus使用(代码片段)
一、springBoot自动化配置原理1.starter管理机制通过依赖了解SpringBoot管理了哪些starter通过依赖spring-boot-dependencies搜索starter-发现非常多的官方starter,并且已经帮助我们管理好了版本。项目中使用直接引入对应的starter即可,... 查看详情
面试题:springboot的自启动原理
...更加得心应手的去进行应用、开发。SpringBoot的精髓“自动配置原理”不仅仅是在面试过程中才用的上;在工作中如果能深入理解SpringBoot的自动配置原理,我们就可以根据自己的需求自定义一个started满足开发的需求,让开... 查看详情
springboot的工作原理
...ot的项目打包放到tomcat里运行,需要将启动类继承SpringBootServletInitializer因为SpringBootServletInitializer是继承WebApplicationInitializer的在springmvc中,WebApplicationInitializer就是启动类,原理是通过servlet的特性进行加载的,所以我们需要导入se... 查看详情
Spring Boot 为嵌入式服务器配置自定义 jsessionid
】SpringBoot为嵌入式服务器配置自定义jsessionid【英文标题】:Springbootconfigurecustomjsessionidforembeddedserver【发布时间】:2014-11-1303:24:03【问题描述】:我想配置我的servlet上下文,例如设置自定义jsessionId键(请参阅ChangingcookieJSESSIONIDn... 查看详情
servlet生命周期工作原理配置
Servlet生命周期分为三个阶段: 1,初始化阶段 调用init()方法 2,响应客户请求阶段 调用service()方法 3,终止阶段 调用destroy()方法Servlet工作原理每一个自定义的Servlet都必须实现Servlet的接口,Servlet接口中定... 查看详情
springboot配置嵌入式的servlet
SpringBoot默认使用Tomcat作为嵌入式的Servlet 问题?1)、如何定制和修改Servlet容器的相关配置;server.port=8081server.context-path=/crudserver.tomcat.uri-encoding=UTF-8//通用的Servlet容器设置server.xxx//Tomcat的设置server.tomcat.xxx 查看详情
重学springboot系列之嵌入式容器的配置与应用(代码片段)
重学SpringBoot系列之嵌入式容器的配置与应用嵌入式容器的运行参数配置调整SpringBoot应用容器的参数两种配置方法配置文件方式常用配置参数tomcat性能优化核心参数自定义配置类方式为Web容器配置HTTPS如何生成自签名证书将SSL应... 查看详情
servlet工作原理解析(代码片段)
...t对应一个Web工程。Servlet容器的启动过程Tomcat7也开始支持嵌入式功能,增加了一个启动类org.apache.catalina.startup.Tomcat。创建一个实例对象并调用start方法就可以很容易启动Tomcat,我们还可以通过 查看详情