声明:以下的所有方法、原理、源码全部是建立在Spring Boot 2.1.7版本。
1、 修改SpringBoot对嵌入式Server容器的默认配置
Spring Boot默认使用Tomcat作为嵌入式的Servlet容器。实际应用中我们需要对他进行专门的定制。定制的方式不外乎两种:在配置文件中配置或在配置类中注册组件的方式配置

1.1 直接在application.properties/application.xml文件中配置和server有关的属性
配置方式是server.属性名=值
,下面是ServerProperties
类中定义的绝大多数可以配置的属性
server配置
server.address 指定server绑定的地址
server.compression.enabled 是否开启压缩,默认为false.
server.compression.excluded-user-agents 指定不压缩的user-agent,多个以逗号分隔,默认值为:text/html,text/xml,text/plain,text/css
server.compression.mime-types 指定要压缩的MIME type,多个以逗号分隔.
server.compression.min-response-size 执行压缩的阈值,默认为2048
server.context-parameters.[param name] 设置servlet context 参数
server.context-path 设定应用的context-path.
server.display-name 设定应用的展示名称,默认: application
server.jsp-servlet.class-name 设定编译JSP用的servlet,默认: org.apache.jasper
servlet.JspServlet)
server.jsp-servlet.init-parameters.[param name] 设置JSP servlet 初始化参数.
server.jsp-servlet.registered 设定JSP servlet是否注册到内嵌的servlet容器,默认true
server.port 设定http监听端口
server.servlet-path 设定dispatcher servlet的监听路径,默认为: /
cookie、session配置
server.session.cookie.comment 指定session cookie的comment
server.session.cookie.domain 指定session cookie的domain
server.session.cookie.http-only 是否开启HttpOnly.
server.session.cookie.max-age 设定session cookie的最大age.
server.session.cookie.name 设定Session cookie 的名称.
server.session.cookie.path 设定session cookie的路径.
server.session.cookie.secure 设定session cookie的“Secure” flag.
server.session.persistent 重启时是否持久化session,默认false
server.session.timeout session的超时时间
server.session.tracking-modes 设定Session的追踪模式(cookie, url, ssl).
ssl配置
server.ssl.ciphers 是否支持SSL ciphers.
server.ssl.client-auth 设定client authentication是wanted 还是 needed.
server.ssl.enabled 是否开启ssl,默认: true
server.ssl.key-alias 设定key store中key的别名.
server.ssl.key-password 访问key store中key的密码.
server.ssl.key-store 设定持有SSL certificate的key store的路径,通常是一个.jks文件.
server.ssl.key-store-password 设定访问key store的密码.
server.ssl.key-store-provider 设定key store的提供者.
server.ssl.key-store-type 设定key store的类型.
server.ssl.protocol 使用的SSL协议,默认: TLS
server.ssl.trust-store 持有SSL certificates的Trust store.
server.ssl.trust-store-password 访问trust store的密码.
server.ssl.trust-store-provider 设定trust store的提供者.
server.ssl.trust-store-type 指定trust store的类型.
tomcat配置
server.tomcat.access-log-enabled 是否开启access log ,默认: false)
server.tomcat.access-log-pattern 设定access logs的格式,默认: common
server.tomcat.accesslog.directory 设定log的目录,默认: logs
server.tomcat.accesslog.enabled 是否开启access log,默认: false
server.tomcat.accesslog.pattern 设定access logs的格式,默认: common
server.tomcat.accesslog.prefix 设定Log 文件的前缀,默认: access_log
server.tomcat.accesslog.suffix 设定Log 文件的后缀,默认: .log
server.tomcat.background-processor-delay 后台线程方法的Delay大小: 30
server.tomcat.basedir 设定Tomcat的base 目录,如果没有指定则使用临时目录.
server.tomcat.internal-proxies 设定信任的正则表达式,默认:“10\.\d{1,3}\.\d{1,3}\.\d{1,3}| 192\.168\.\d{1,3}\.\d{1,3}| 169\.254\.\d{1,3}\.\d{1,3}| 127\.\d{1,3}\.\d{1,3}\.\d{1,3}| 172\.1[6-9]{1}\.\d{1,3}\.\d{1,3}| 172\.2[0-9]{1}\.\d{1,3}\.\d{1,3}|172\.3[0-1]{1}\.\d{1,3}\.\d{1,3}”
server.tomcat.max-http-header-size 设定http header的最小值,默认: 0
server.tomcat.max-threads 设定tomcat的最大工作线程数,默认为: 0
server.tomcat.port-header 设定http header使用的,用来覆盖原来port的value.
server.tomcat.protocol-header 设定Header包含的协议,通常是 X-Forwarded-Proto,如果remoteIpHeader有值,则将设置为RemoteIpValve.
server.tomcat.protocol-header-https-value 设定使用SSL的header的值,默认https.
server.tomcat.remote-ip-header 设定remote IP的header,如果remoteIpHeader有值,则设置为RemoteIpValve
server.tomcat.uri-encoding 设定URI的解码字符集.
undertow配置
server.undertow.access-log-dir 设定Undertow access log 的目录,默认: logs
server.undertow.access-log-enabled 是否开启access log,默认: false
server.undertow.access-log-pattern 设定access logs的格式,默认: common
server.undertow.accesslog.dir 设定access log 的目录.
server.undertow.buffer-size 设定buffer的大小.
server.undertow.buffers-per-region 设定每个region的buffer数
server.undertow.direct-buffers 设定堆外内存
server.undertow.io-threads 设定I/O线程数.
server.undertow.worker-threads 设定工作线程数
server:
port: 80 #端口
servlet:
context-path: /crud #项目的context-path
tomcat:
uri-encoding: UTF-8 #tomcat URI的字符编码
basedir: localhost/crud #tomcat基路径
compression: #是否开启压缩文件
enabled: true #true是开启
mime-types: text/html,text/css,text/javascript #压缩的文件类型
1.2 向IoC容器中添加servlet容器工厂定制器 WebServerFactoryCustomizer
@Configuration
public class ServerConfig {
@Bean //注册到IOC容器中
public WebServerFactoryCustomizer<TomcatServletWebServerFactory> webServerFactoryCustomizer(){
return factory -> {
//在这里设置server有关对属性
factory.setPort(8085);
factory.setContextPath("/crud");
factory.setUriEncoding(Charset.forName("utf-8"));
Compression compression = new Compression();
compression.setEnabled(true);
String []mimes={"text/html","text/css"};
compression.setMimeTypes(mimes);
factory.setCompression(compression);
};
}
}
运行结果:

如果使用的是Spring Boot 1.x版本可以参考下面的方法来使用配置
public class ServerConfig extends WebMvcConfigurerAdapter {
public EmbeddedServletContainerCustomizer embeddedServletContainerCustomizer() {
return new EmbeddedServletContainerCustomizer() {
@Override
public void customize(ConfigurableEmbeddedServletContainer container) {
//配置server属性
container.setPort(8083);
...
}
};
}
}
1.3 向IoC容器中添加可配置的servlet容器工厂 ConfigurableServletWebServerFactory
@Configuration
public class ServerConfig {
@Bean
public ConfigurableServletWebServerFactory configurableServletWebServerFactory() {
TomcatServletWebServerFactory factory = new TomcatServletWebServerFactory();
//设置属性
factory.setPort(8089);
factory.setContextPath("/springboot");
factory.setUriEncoding(Charset.forName("utf-8"));
Compression compression = new Compression();
compression.setEnabled(true);
String[] mimes = {"text/html", "text/css"};
compression.setMimeTypes(mimes);
factory.setCompression(compression);
return factory;
}
}
运行自然是没有什么问题,在地址栏输入http://localhost:8089/springboot/也来到了目标页面:

1.4 在Spring Boot中注册Servlet三大组件【Servlet、Filter、Listener
以前注册这些组件都是在web.xml中配置,由于SpringBoot默认是以jar包的方式启动嵌入式的Servlet容器来启动SpringBoot的web应用,没有web.xml文件。
注册三大组件用以下方式:
①、借助ServletRegistrationBean
注册自定义Servlet组件; 自定义【MyServlet】:
public class MyServlet extends HttpServlet {
//重写service方法
@Override
protected void service(HttpServletRequest req,HttpServletResponse resp){
resp.getWriter().write("Hello Spring Boot!");
}
}
定义【ServletRegistrationBean】并放入容器中:
@Bean
public ServletRegistrationBean myServlet(){
ServletRegistrationBean registrationBean = new ServletRegistrationBean(new MyServlet(),"/myServlet");
return registrationBean;
}
②、借助FilterRegistrationBean注册自定义Filter组件;(自定义的MyFilter忽略)
@Bean
public FilterRegistrationBean myFilter(){
FilterRegistrationBean registrationBean = new FilterRegistrationBean();
registrationBean.setFilter(new MyFilter());
registrationBean.setUrlPatterns(Arrays.asList("/hello","/myServlet"));
return registrationBean;
}
③、借助ServletListenerRegistrationBean注册自定义Listener组件;(自定义的MyListener忽略)
@Bean
public ServletListenerRegistrationBean myListener(){
ServletListenerRegistrationBean<MyListener> registrationBean = new ServletListenerRegistrationBean<>(new MyListener());
return registrationBean;
}
2、 嵌入式Servlet容器切换
2.1 三大容器比较
容器 | 优点 | 缺点 | 默认 |
tomcat | 功能齐全 | 庞大,荣泽 | true |
jetty | 轻量 | 功能不全 | false |
undertow | 异步,高效 | 不支持jsp | false |
2.2 容器切换
Tomcat
Spring Boot引入web模块默认就是使用嵌入式的Tomcat作为Servlet容器。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
- `Jetty
<!-- 引入web模块 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<!--排除tomcat-->
<exclusions>
<exclusion>
<artifactId>spring-boot-starter-tomcat</artifactId>
<groupId>org.springframework.boot</groupId>
</exclusion>
</exclusions>
</dependency>
<!--引入jetty容器-->
<dependency>
<artifactId>spring-boot-starter-jetty</artifactId>
<groupId>org.springframework.boot</groupId>
</dependency>

undertow
<!-- 引入web模块 -->
<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-undertow</artifactId>
<groupId>org.springframework.boot</groupId>
</dependency>

3、 嵌入式Servlet容器自动配置原理
主要看三个类: * ServletWebServerFactoryConfiguration
* ServletWebServerFactoryAutoConfiguration
* ServletWebServerFactoryCustomizer
3.1 ServletWebServerFactoryConfiguration
有三个:EmbeddedUndertow ,EmbeddedJetty,EmbeddedTomcat @Conditionalxxx 标注的类;条件满足才向容器中添加组件。
@Configuration
class ServletWebServerFactoryConfiguration {
//默认配置的就是Tomcat
@Configuration
//容器中存在servlet.class(存在servlet依赖) tomcat.class(tomcat依赖) 才会执行向容器中添加组件
@ConditionalOnClass({ Servlet.class, Tomcat.class, UpgradeProtocol.class })
//判断容器中没有用户自定义的ServletWeServerbFactory
@ConditionalOnMissingBean(value = ServletWebServerFactory.class, search = SearchStrategy.CURRENT)
public static class EmbeddedTomcat {
//向IOC容器中添加tomcat
@Bean
public TomcatServletWebServerFactory tomcatServletWebServerFactory() {
return new TomcatServletWebServerFactory();
}
}
/**
* 如果配置了Jetty就会自动配置jetty
*/
@Configuration
@ConditionalOnClass({ Servlet.class, Server.class, Loader.class, WebAppContext.class })
@ConditionalOnMissingBean(value = ServletWebServerFactory.class, search = SearchStrategy.CURRENT)
public static class EmbeddedJetty {
@Bean
public JettyServletWebServerFactory JettyServletWebServerFactory() {
return new JettyServletWebServerFactory();
}
}
/**
* 如果配置了Undertow就会自动配置Undertow
*/
@Configuration
@ConditionalOnClass({ Servlet.class, Undertow.class, SslClientAuthMode.class })
@ConditionalOnMissingBean(value = ServletWebServerFactory.class, search = SearchStrategy.CURRENT)
public static class EmbeddedUndertow {
@Bean
public UndertowServletWebServerFactory undertowServletWebServerFactory() {
return new UndertowServletWebServerFactory();
}
}
}
}
- ServletWebServerFactory:嵌入式Servlet工厂。作用:创建嵌入式Servlet容器

@FunctionalInterface
public interface ServletWebServerFactory {
//只有一个接口方法getWebServer
WebServer getWebServer(ServletContextInitializer... initializers);
}
在判断@ConditionalOnClass({Servlet.class, Tomcat.class, UpgradeProtocol.class})是否导入依赖,满足条件后return new TomcatServletWebServerFactory(); 添加对应的Servlet容器工厂;通过工厂的唯一方法getWebServer 获取对应的Servlet容器TomcatServer.
- TomcatServletWebServerFactory
public class TomcatServletWebServerFactory extends AbstractServletWebServerFactory
implements ConfigurableTomcatWebServerFactory, ResourceLoaderAware {
public WebServer getWebServer(ServletContextInitializer... initializers) {
1. 创建Tomcat对象
Tomcat tomcat = new Tomcat();
File baseDir = this.baseDirectory != null ? this.baseDirectory : this.createTempDir("tomcat");
tomcat.setBaseDir(baseDir.getAbsolutePath());
2.完成tomct 配置的基本操作
Connector connector = new Connector(this.protocol);
tomcat.getService().addConnector(connector);
this.customizeConnector(connector);
tomcat.setConnector(connector);
tomcat.getHost().setAutoDeploy(false);
this.configureEngine(tomcat.getEngine());
Iterator var5 = this.additionalTomcatConnectors.iterator();
while(var5.hasNext()) {
Connector additionalConnector = (Connector)var5.next();
tomcat.getService().addConnector(additionalConnector);
}
this.prepareContext(tomcat.getHost(), initializers);
3.将tomcat 传入方法:getTomcatWebServer()
return this.getTomcatWebServer(tomcat);
}
}
- TomcatWebServer
public class TomcatWebServer implements WebServer {
//对应的构造函数:在TomcatWebServer 中
public TomcatWebServer(Tomcat tomcat, boolean autoStart) {
Assert.notNull(tomcat, "Tomcat Server must not be null");
this.tomcat = tomcat;
this.autoStart = autoStart;
initialize();
}
//initialize方法执行初始化
private void initialize() throws WebServerException {
logger.info("Tomcat initialized with port(s): " + getPortsDescription(false));
synchronized (this.monitor) {
try {
addInstanceIdToEngineName();
Context context = findContext();
context.addLifecycleListener((event) -> {
if (context.equals(event.getSource()) && Lifecycle.START_EVENT.equals(event.getType())) {
// Remove service connectors so that protocol binding doesn't
//服务启动的时候执行
removeServiceConnectors();
}
});
//启动tomcat
this.tomcat.start();
// We can re-throw failure exception directly in the main thread
rethrowDeferredStartupExceptions();
try {
ContextBindings.bindClassLoader(context, context.getNamingToken(), 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();
}
catch (Exception ex) {
stopSilently();
destroySilently();
throw new WebServerException("Unable to start embedded Tomcat", ex);
}
}
}
}
3.2 ServletWebServerFactoryAutoConfiguration
修改定制Servlet 容器的方法: 1、配置文件
中添加配置。 2、ServerProperties 绑定/修改定制组件 WebServerFactoryCustomizer
他们的本质是一样的:在ServletWebServerFactoryAutoConfiguration
配置类中@EnableConfigurationProperties({ServerProperties.class})。 导入了BeanPostProcessorsRegistrar
,在这个类的方法中添加了组件WebServerFactoryCustomizerBeanPostProcessor
(定制器后置处理器)。也就是说一旦容器中添加任何组件都会启动定制后置处理器,进行Servlet的赋值。 后置处理器起作用的过程:
@Configuration
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE)
@ConditionalOnClass(ServletRequest.class)
@ConditionalOnWebApplication(type = Type.SERVLET)
@EnableConfigurationProperties(ServerProperties.class)
@Import({ ServletWebServerFactoryAutoConfiguration.BeanPostProcessorsRegistrar.class,
ServletWebServerFactoryConfiguration.EmbeddedTomcat.class,
ServletWebServerFactoryConfiguration.EmbeddedJetty.class,
ServletWebServerFactoryConfiguration.EmbeddedUndertow.class })
public class ServletWebServerFactoryAutoConfiguration {
}
3.3 ServletWebServerFactoryCustomizer
在这个配置类中使用customize(ConfigurableServletWebServerFactory factory)
这个方法 完成了Tomcat的各项配置的修改和定制
public class ServletWebServerFactoryCustomizer
implements WebServerFactoryCustomizer<ConfigurableServletWebServerFactory>, Ordered {
//具体对Tomcat的配置细节
@Override
public void customize(ConfigurableServletWebServerFactory factory) {
PropertyMapper map = PropertyMapper.get().alwaysApplyingWhenNonNull();
map.from(this.serverProperties::getPort).to(factory::setPort);
map.from(this.serverProperties::getAddress).to(factory::setAddress);
map.from(this.serverProperties.getServlet()::getContextPath).to(factory::setContextPath); map.from(this.serverProperties.getServlet()::getApplicationDisplayName).to(factory::setDisplayName); map.from(this.serverProperties.getServlet()::getSession).to(factory::setSession);
map.from(this.serverProperties::getSsl).to(factory::setSsl); map.from(this.serverProperties.getServlet()::getJsp).to(factory::setJsp); map.from(this.serverProperties::getCompression).to(factory::setCompression);
map.from(this.serverProperties::getHttp2).to(factory::setHttp2);
map.from(this.serverProperties::getServerHeader).to(factory::setServerHeader);
map.from(this.serverProperties.getServlet()::getContextParameters).to(factory::setInitParameters);
}
}
总结配置修改定制原理:以tomcat为例总结配置修改定制原理:以tomcat为例
1、Spring Boot根据根据导入依赖的情况,给容器中添加相应的ServletWebServerFactory
(比如tomcat就会添加TomcatServletWebServerFactory)
2、如果使用的是通过application.propertoes 修改配置,那么server 相关的配置修改是与ServerProperties 类绑定的,所以相关的修改会直接通过Serverproperties 的方法实现【相关的配置类:ServletWebServerFactoryCustomizer
】
3、如果使用的是修改定制器 WebServerFactoryCustomizer
的方法来配置server,那么定制器会创建ConfigurableWebServerFactory
对象,这样一来就会触发WebServerFactoryCustomizerBeanPostProcessor
后置处理器,判断是否为WebServerFactory 类型;满足条件后,就会获取容器中的所有定制器(customizer.cutomize(bean)),为Servlet容器修改和定制配置【相关的配置类ServletWebServerFactoryAutoConfiguration
,导入了定制处理器】