一、如何定制和修改Servlet容器的相关配置


1、配置文件(ServerProperties);

优先级最高

server.port=8081
server.context‐path=/crud
server.tomcat.uri‐encoding=UTF‐8
//通用的Servlet容器设置
server.xxx
//Tomcat的设置
server.tomcat.xxx

2、java代码

2.1 Spring Boot 1.5.10 版本

@Bean //一定要将这个定制器加入到容器中 嵌入式的Servlet容器定制器
public EmbeddedServletContainerCustomizer embeddedServletContainerCustomizer(){
  return new EmbeddedServletContainerCustomizer() {
    //定制嵌入式的Servlet容器相关的规则
    @Override
    public void customize(ConfigurableEmbeddedServletContainer container) {
      container.setPort(8083);
    }
  };
}

2.2 Spring Boot 2.1.0版本

 2.2.1、 方式1  (优先级第二)

import org.springframework.boot.web.server.WebServerFactoryCustomizer;
import org.springframework.boot.web.servlet.server.ConfigurableServletWebServerFactory;
import org.springframework.stereotype.Component;
@Component
public class CustomizationBean implements WebServerFactoryCustomizer<ConfigurableServletWebServerFactory> {
@Override
public void customize(ConfigurableServletWebServerFactory server) {
server.setPort(9000);
}
}

  2.2.2、方式2 (优先级最低)

@Bean
public ConfigurableServletWebServerFactory webServerFactory() {
TomcatServletWebServerFactory factory = new TomcatServletWebServerFactory();
factory.setPort(9000);
// factory.setSessionTimeout(10, TimeUnit.MINUTES); 此方法没找到
factory.addErrorPages(new ErrorPage(HttpStatus.NOT_FOUND, "/notfound.html"));
return factory;
}

二、自定义Servlet容器


1、Spring Boot 支持的 Servlet容器类型

2、切换Tomcat容器为jetty容器

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions><!-- 排除掉默认的Tomcat web容器-->
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- 引入jetty容器。jetty 适合长连接的场景-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jetty</artifactId><!-- spring-boot-starter-undertow ,不支持JSP-->
</dependency>
undertow

包下:spring-boot-autoconfigure-2.1.0.RELEASE.jar

三、嵌入式Servlet容器自动配置原理Spring Boot 2.1.0版本示例: (注:1.5.10 和2.1.0版本有很大不同)


Servelt容器的自动配置类

@Configuration
@ConditionalOnWebApplication
@EnableConfigurationProperties(ServerProperties.class)
public class EmbeddedWebServerFactoryCustomizerAutoConfiguration { /**
* Nested configuration if Tomcat is being used.
*/
@Configuration
@ConditionalOnClass({ Tomcat.class, UpgradeProtocol.class })
public static class TomcatWebServerFactoryCustomizerConfiguration { @Bean
public TomcatWebServerFactoryCustomizer tomcatWebServerFactoryCustomizer(
Environment environment, ServerProperties serverProperties) {
return new TomcatWebServerFactoryCustomizer(environment, serverProperties);
} } /**
* Nested configuration if Jetty is being used.
*/
@Configuration
@ConditionalOnClass({ Server.class, Loader.class, WebAppContext.class })
public static class JettyWebServerFactoryCustomizerConfiguration { @Bean
public JettyWebServerFactoryCustomizer jettyWebServerFactoryCustomizer(
Environment environment, ServerProperties serverProperties) {
return new JettyWebServerFactoryCustomizer(environment, serverProperties);
} } /**
* Nested configuration if Undertow is being used.
*/
@Configuration
@ConditionalOnClass({ Undertow.class, SslClientAuthMode.class })
public static class UndertowWebServerFactoryCustomizerConfiguration { @Bean
public UndertowWebServerFactoryCustomizer undertowWebServerFactoryCustomizer(
Environment environment, ServerProperties serverProperties) {
return new UndertowWebServerFactoryCustomizer(environment, serverProperties);
} } /**
* Nested configuration if Netty is being used.
*/
@Configuration
@ConditionalOnClass(HttpServer.class)
public static class NettyWebServerFactoryCustomizerConfiguration { @Bean
public NettyWebServerFactoryCustomizer nettyWebServerFactoryCustomizer(
Environment environment, ServerProperties serverProperties) {
return new NettyWebServerFactoryCustomizer(environment, serverProperties);
} } }

Tomcat 的Server的定制(Jetty、Netty、Undertow 类似)

public class TomcatWebServerFactoryCustomizer implements
WebServerFactoryCustomizer<ConfigurableTomcatWebServerFactory>, Ordered { private final Environment environment; private final ServerProperties serverProperties; public TomcatWebServerFactoryCustomizer(Environment environment,
ServerProperties serverProperties) {
this.environment = environment;
this.serverProperties = serverProperties;
} @Override
public int getOrder() {
return ;
} @Override
public void customize(ConfigurableTomcatWebServerFactory factory) {
ServerProperties properties = this.serverProperties;
ServerProperties.Tomcat tomcatProperties = properties.getTomcat();
PropertyMapper propertyMapper = PropertyMapper.get();
propertyMapper.from(tomcatProperties::getBasedir).whenNonNull()
.to(factory::setBaseDirectory);
propertyMapper.from(tomcatProperties::getBackgroundProcessorDelay).whenNonNull()
.as(Duration::getSeconds).as(Long::intValue)
.to(factory::setBackgroundProcessorDelay);
customizeRemoteIpValve(factory);
propertyMapper.from(tomcatProperties::getMaxThreads).when(this::isPositive)
.to((maxThreads) -> customizeMaxThreads(factory,
tomcatProperties.getMaxThreads()));
propertyMapper.from(tomcatProperties::getMinSpareThreads).when(this::isPositive)
.to((minSpareThreads) -> customizeMinThreads(factory, minSpareThreads));
propertyMapper.from(this::determineMaxHttpHeaderSize).whenNonNull()
.asInt(DataSize::toBytes).when(this::isPositive)
.to((maxHttpHeaderSize) -> customizeMaxHttpHeaderSize(factory,
maxHttpHeaderSize));
propertyMapper.from(tomcatProperties::getMaxSwallowSize).whenNonNull()
.asInt(DataSize::toBytes)
.to((maxSwallowSize) -> customizeMaxSwallowSize(factory, maxSwallowSize));
propertyMapper.from(tomcatProperties::getMaxHttpPostSize).asInt(DataSize::toBytes)
.when((maxHttpPostSize) -> maxHttpPostSize != )
.to((maxHttpPostSize) -> customizeMaxHttpPostSize(factory,
maxHttpPostSize));
propertyMapper.from(tomcatProperties::getAccesslog)
.when(ServerProperties.Tomcat.Accesslog::isEnabled)
.to((enabled) -> customizeAccessLog(factory));
propertyMapper.from(tomcatProperties::getUriEncoding).whenNonNull()
.to(factory::setUriEncoding);
propertyMapper.from(properties::getConnectionTimeout).whenNonNull()
.to((connectionTimeout) -> customizeConnectionTimeout(factory,
connectionTimeout));
propertyMapper.from(tomcatProperties::getMaxConnections).when(this::isPositive)
.to((maxConnections) -> customizeMaxConnections(factory, maxConnections));
propertyMapper.from(tomcatProperties::getAcceptCount).when(this::isPositive)
.to((acceptCount) -> customizeAcceptCount(factory, acceptCount));
customizeStaticResources(factory);
customizeErrorReportValve(properties.getError(), factory);
}
。。。。。。
}

Spring Boot 2.1.0 版本的web容器启动流程 (Spring boot 1.5.10版本类似但不同)

1.Spring boot启动器

@SpringBootApplication
public class SpringBootDemo01Application { public static void main(String[] args) {
SpringApplication.run(SpringBootDemo01Application.class, args);
}
}

2.run方法启动过程源码分析

public class SpringApplication {
   //在createApplicationContext()中根据类型classforName()加载 不同类型的
public static final String DEFAULT_CONTEXT_CLASS = "org.springframework.context."
+ "annotation.AnnotationConfigApplicationContext"; public static final String DEFAULT_SERVLET_WEB_CONTEXT_CLASS = "org.springframework.boot."
+ "web.servlet.context.AnnotationConfigServletWebServerApplicationContext"; public static final String DEFAULT_REACTIVE_WEB_CONTEXT_CLASS = "org.springframework."
+ "boot.web.reactive.context.AnnotationConfigReactiveWebServerApplicationContext";

   //run1调用run2
public static ConfigurableApplicationContext run(Class<?> primarySource,String... args) {
return run(new Class<?>[] { primarySource }, args);
}
   //run2调用run3
public static ConfigurableApplicationContext run(Class<?>[] primarySources,String[] args) {
return new SpringApplication(primarySources).run(args);
}

   //run3启动Web服务器
public ConfigurableApplicationContext run(String... args) {
StopWatch stopWatch = new StopWatch();
stopWatch.start();
ConfigurableApplicationContext context = null;
Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
configureHeadlessProperty();
SpringApplicationRunListeners listeners = getRunListeners(args);
listeners.starting();
try {
ApplicationArguments applicationArguments = new DefaultApplicationArguments(
args);
ConfigurableEnvironment environment = prepareEnvironment(listeners,
applicationArguments);
configureIgnoreBeanInfo(environment);
Banner printedBanner = printBanner(environment);
context = createApplicationContext();
exceptionReporters = getSpringFactoriesInstances(
SpringBootExceptionReporter.class,
new Class[] { ConfigurableApplicationContext.class }, context);
prepareContext(context, environment, listeners, applicationArguments,
printedBanner);
refreshContext(context);
afterRefresh(context, applicationArguments);
stopWatch.stop();
if (this.logStartupInfo) {
new StartupInfoLogger(this.mainApplicationClass)
.logStarted(getApplicationLog(), stopWatch);
}
listeners.started(context);
callRunners(context, applicationArguments);
}
catch (Throwable ex) {
handleRunFailure(context, ex, exceptionReporters, listeners);
throw new IllegalStateException(ex);
} try {
listeners.running(context);
}
catch (Throwable ex) {
handleRunFailure(context, ex, exceptionReporters, null);
throw new IllegalStateException(ex);
}
return context;
} protected ConfigurableApplicationContext createApplicationContext() {
Class<?> contextClass = this.applicationContextClass;
if (contextClass == null) {
try {
switch (this.webApplicationType) {
case SERVLET:
contextClass = Class.forName(DEFAULT_SERVLET_WEB_CONTEXT_CLASS);
break;
case REACTIVE:
contextClass = Class.forName(DEFAULT_REACTIVE_WEB_CONTEXT_CLASS);
break;
default:
contextClass = Class.forName(DEFAULT_CONTEXT_CLASS);
}
}
catch (ClassNotFoundException ex) {
throw new IllegalStateException(
"Unable create a default ApplicationContext, "
+ "please specify an ApplicationContextClass",
ex);
}
}
return (ConfigurableApplicationContext) BeanUtils.instantiateClass(contextClass);
} private void refreshContext(ConfigurableApplicationContext context) {
refresh(context);
if (this.registerShutdownHook) {
try {
context.registerShutdownHook();
}
catch (AccessControlException ex) {
// Not allowed in some environments.
}
}
} protected void refresh(ApplicationContext applicationContext) {
Assert.isInstanceOf(AbstractApplicationContext.class, applicationContext);
((AbstractApplicationContext) applicationContext).refresh();
} }
public abstract class AbstractApplicationContext extends DefaultResourceLoader
implements ConfigurableApplicationContext { @Override
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); // Invoke factory processors registered as beans in the context.
invokeBeanFactoryPostProcessors(beanFactory); // 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();
}
}
}
protected void onRefresh() throws BeansException {
// For subclasses: do nothing by default.
} }

public class ServletWebServerApplicationContext extends GenericWebApplicationContext
implements ConfigurableWebServerApplicationContext { @Override
protected void onRefresh() {
super.onRefresh();
try {
createWebServer();
}
catch (Throwable ex) {
throw new ApplicationContextException("Unable to start web server", ex);
}
} private void createWebServer() {
WebServer webServer = this.webServer;
ServletContext servletContext = getServletContext();
if (webServer == null && servletContext == null) {
ServletWebServerFactory factory = getWebServerFactory();
this.webServer = factory.getWebServer(getSelfInitializer());
}
else if (servletContext != null) {
try {
getSelfInitializer().onStartup(servletContext);
}
catch (ServletException ex) {
throw new ApplicationContextException("Cannot initialize servlet context",
ex);
}
}
initPropertySources();
} }

spring-boot-2.1.0.RELEASE.jar

17. Spring Boot 配置嵌入式Servlet容器的更多相关文章

  1. 【串线篇】spring boot配置嵌入式servlet容器

    SpringBoot默认使用Tomcat作为嵌入式的Servlet容器 问题? 一.如何定制和修改Servlet容器的相关配置 1.方法1修改和server有关的配置(ServerProperties ...

  2. Spring boot 配置嵌入式Servlet容器

    SpringBoot默认使用Tomcat作为嵌入式的Servlet容器 1.修改和server有关的配置(ServerProperties[也是EmbeddedServletContainerCust ...

  3. 17、配置嵌入式servlet容器(1)

    SpringBoot默认使用Tomcat作为嵌入式的Servlet容器 1).如何定制和修改Servlet容器的相关配置         1.修改和server有关的配置            (Se ...

  4. (7)Spring Boot web开发 --- servlet容器

    文章目录 配置嵌入式 Servlet 容器 注册 三大组件 使用其他 servlet 容器 使用外置的 `Servlet` 容器 配置嵌入式 Servlet 容器 Spirng Boot 默认使用自带 ...

  5. 18、配置嵌入式servlet容器(2)

    使用其他Servlet容器 -Jetty(长连接) -Undertow(不支持jsp) 替换为其他嵌入式Servlet容器   默认支持: Tomcat(默认使用) Jetty: <depend ...

  6. SpringBoot配置嵌入式Servlet容器

    1).如何定制和修改Servlet容器的相关配置: 1.修改和server有关的配置(ServerProperties[也是EmbeddedServletContainerCustomizer]): ...

  7. 配置嵌入式Servlet容器

    SpringBoot默认是用的是Tomcat作为嵌入式的Servlet容器:问题?1).如何定制和修改Servlet容器的相关配置:1.修改和server有关的配置(ServerProperties) ...

  8. 19、配置嵌入式servlet容器(下)

    使用外置的Servlet   嵌入式Servlet容器:应用打成可执行的j ar 优点:简单.便携: 缺点:默认不支持JSP.优化定制比较复杂         使用定制器[ServerProperti ...

  9. SpringBoot起飞系列-配置嵌入式Servlet容器(八)

    一.前言 springboot中默认使用的是tomcat容器,也叫做嵌入式的servlet容器.因为它和我们平常使用的tomcat容器不一样,这个tomcat直接嵌入到的springboot,平常我们 ...

随机推荐

  1. [转帖] securebootthemes 挖矿病毒的说明 http://blog.netlab.360.com/msraminer-qian-fu-yi-jiu-de-wa-kuang-jiang-shi-wang-luo/ 原文为毛不给一个专杀工具呢.

    MsraMiner: 潜伏已久的挖矿僵尸网络 2017 年 11 月底,我们的 DNSMon 系统监测到几个疑似 DGA 产生的恶意域名活动有异常.经过我们深入分析,确认这背后是一个从 2017 年 ...

  2. 好文章之——PHP系列(一)

    注:最近实习的公司是一家做电商企业,后台主要是php开发,好久不怎么接触php的我看了几篇相关文章,提高下对它的认识与理解,发现里面的学习思路还是非常好的,当然也会重新拾一下基础知识啦! 其实自己心中 ...

  3. hive启动方式

  4. python对redis的常用操作 下 (无序集合,有序集合)

    无序集合: 首先介绍增加,删除和获得所有元素的方法.我将会用第二部分来讨论集合的特殊操作: In [136]: x.sadd("challenge", 1,2,3,4,5,6,7, ...

  5. Test Scenarios for image upload functionality (also applicable for other file upload functionality)

    1 check for uploaded image path2 check image upload and change functionality3 check image upload fun ...

  6. 洛谷P2397 yyy loves Maths VI (mode)

    P2397 yyy loves Maths VI (mode) 题目背景 自动上次redbag用加法好好的刁难过了yyy同学以后,yyy十分愤怒.他还击给了redbag一题,但是这题他惊讶的发现自己居 ...

  7. Centos7 Journald 指令

    Journald是为Linux服务器打造的新系统日志方式,它标志着文本日志文件的终结.现在日志信息写入到二进制文件,使用journalctl阅读,要获得这些信息,Linux管理员将需要一些实践. Re ...

  8. 如何在Anaconda中实现多版本python共存

    anaconda中Python版本是3.5,因为爬虫原因,需要Python2.7版本,因此,希望能在anaconda中Python3和Python2共存. 1. 打开Anaconda Prompt,可 ...

  9. HDU4288-STL模拟

    给你插入,删除的操作,维护一个降序排列的表,查询所有下标模5等于3的元素和. 2012年成都网络赛的一道签到题.但是还是搜了题解才做出来了,意志不坚定啊... 这道题给10s的时间,做法多种多样. 最 ...

  10. vs2017 C4996 错误

    严重性    代码    说明    项目    文件    行    禁止显示状态错误    C4996    'strcpy': This function or variable may be ...