SpringBoot_配置嵌入式Servlet容器
SpringBoot
- 前言:
- 修改嵌入式Servlet容器的相关配置:
- 注册Servlet三大组件:
- 替换为其他嵌入式Servlet容器:
- 嵌入式Servlet容器自动配置原理:
- 修改嵌入式Servlet容器配置的原理:
- 嵌入式Servlet容器启动原理:
前言:
以前部署web项目,需要把web项目打包成war包,然后放在外部配置好的中间件环境中,比如Tomcat容器,将web项目war包放在 \Tomcat_Home\webapps目录下,然后运行 \Tomcat_Home\bin目录下的startup.bat或者startup.sh来启动项目;
在SpringBoot中,默认使用Tomcat作为嵌入式的Servlet容器;
修改嵌入式Servlet容器的相关配置:
方式一:在配置文件中修改和server有关的配置:
server.port=8083 server.context‐path=/Restful server.tomcat.uri‐encoding=UTF‐8 //通用的Servlet容器设置 server.xxx //Tomcat的设置 server.tomcat.xxx
方式二:在自定义配置类中,编写嵌入式的Servlet容器的定制器,来修改Servlet容器配置:
SpringBoot1.5.x 版本: EmbeddedServletContainerCustomizer
@Bean //要将这个定制器加入到容器中 public EmbeddedServletContainerCustomizer embeddedServletContainerCustomizer(){ return new EmbeddedServletContainerCustomizer() { //定制嵌入式的Servlet容器相关的规则 @Override public void customize(ConfigurableEmbeddedServletContainer container) { container.setPort(8083); } }; }
SpringBoot2.x.x 版本: WebServerFactoryCustomizer
@Bean //要将这个定制器加入到容器中 public WebServerFactoryCustomizer webServerFactoryCustomizer() { return new WebServerFactoryCustomizer<ConfigurableServletWebServerFactory>() { //定制嵌入式Servlet容器的相关规则 @Override public void customize(ConfigurableServletWebServerFactory factory) { factory.setPort(8083); } }; }
注册Servlet三大组件:
SpringBoot默认以jar包的方式启动嵌入式Servlet容器来启动SpringBoot的web应用,没有web.xml文件,所以我们在自定义配置类中注册三大组件;
注册 Servlet:ServletRegistrationBean
@Bean public ServletRegistrationBean myServlet(){ ServletRegistrationBean registrationBean = new ServletRegistrationBean(new MyServlet(),"/MyServlet"); registrationBean.setLoadOnStartup(1); return registrationBean; }
注册 Filter:FilterRegistrationBean
@Bean public FilterRegistrationBean myFilter(){ FilterRegistrationBean registrationBean = new FilterRegistrationBean(); registrationBean.setFilter(new MyFilter()); //设置拦截 registrationBean.setUrlPatterns(Arrays.asList("/HELLO/hello","/MyServlet")); return registrationBean; }
注册 Listener:ServletListenerRegistrationBean
@Bean public ServletListenerRegistrationBean myListener(){ ServletListenerRegistrationBean<MyListener> registrationBean = new ServletListenerRegistrationBean<>(new MyListener()); return registrationBean; }
举例:
SpringBoot自动配置SpringMVC的时候,自动注册SpringMVC前端控制器:DIspatcherServlet;
在DispatcherServletAutoConfiguration中:
@Bean(name = {"dispatcherServletRegistration"}) @ConditionalOnBean(value = {DispatcherServlet.class},name = {"dispatcherServlet"}) public DispatcherServletRegistrationBean dispatcherServletRegistration(DispatcherServlet dispatcherServlet, WebMvcProperties webMvcProperties, ObjectProvider<MultipartConfigElement> multipartConfig) { DispatcherServletRegistrationBean registration = new DispatcherServletRegistrationBean(dispatcherServlet, webMvcProperties.getServlet().getPath()); //默认拦截: / 所有请求;包静态资源,但是不拦截jsp请求; /*会拦截jsp //可以通过server.servletPath来修改SpringMVC前端控制器默认拦截的请求路径 registration.setName("dispatcherServlet"); registration.setLoadOnStartup(webMvcProperties.getServlet().getLoadOnStartup()); multipartConfig.ifAvailable(registration::setMultipartConfig); return registration; }
替换为其他嵌入式Servlet容器:
Tomcat: 默认使用
<!--引入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> <!‐‐引入其他的Servlet容器‐‐> <dependency> <artifactId>spring‐boot‐starter‐jetty</artifactId> <groupId>org.springframework.boot</groupId> </dependency>
Undertow: 高性能,非阻塞, 不支持JSP
<!‐‐ 引入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> <!‐‐引入其他的Servlet容器‐‐> <dependency> <artifactId>spring‐boot‐starter‐undertow</artifactId> <groupId>org.springframework.boot</groupId> </dependency>
嵌入式Servlet容器自动配置原理:
SpringBoot1.5.x 版本: EmbeddedServletContainerAutoConfiguration:
SpringBoot2.x.x 版本: ServletWebServerFactoryConfiguration:
@Configuration(proxyBeanMethods = false) class ServletWebServerFactoryConfiguration { ServletWebServerFactoryConfiguration() {} @Configuration(proxyBeanMethods = false) // 判断classpath下有没有Servlet, Undertow, SslClientAuthMode这三个类,即看maven有没有引入对应的依赖 @ConditionalOnClass({Servlet.class, Undertow.class, SslClientAuthMode.class}) //容器中没有ServletWebServerFactory这个组件,下面的配置就生效 @ConditionalOnMissingBean(value = {ServletWebServerFactory.class},search = SearchStrategy.CURRENT) static class EmbeddedUndertow { //Undertow配置类 EmbeddedUndertow() { } @Bean UndertowServletWebServerFactory undertowServletWebServerFactory(ObjectProvider<UndertowDeploymentInfoCustomizer> deploymentInfoCustomizers, ObjectProvider<UndertowBuilderCustomizer> builderCustomizers) { UndertowServletWebServerFactory factory = new UndertowServletWebServerFactory(); factory.getDeploymentInfoCustomizers().addAll((Collection)deploymentInfoCustomizers.orderedStream().collect(Collectors.toList())); factory.getBuilderCustomizers().addAll((Collection)builderCustomizers.orderedStream().collect(Collectors.toList())); return factory; } } @Configuration(proxyBeanMethods = false) // 判断classpath下有没有Servlet, Server, Loader,WebAppContext这四个类,即看maven有没有引入对应的依赖 @ConditionalOnClass({Servlet.class, Server.class, Loader.class, WebAppContext.class}) //容器中没有ServletWebServerFactory这个组件,下面的配置就生效 @ConditionalOnMissingBean(value = {ServletWebServerFactory.class},search = SearchStrategy.CURRENT) static class EmbeddedJetty { //Jetty配置类 EmbeddedJetty() { } @Bean JettyServletWebServerFactory JettyServletWebServerFactory(ObjectProvider<JettyServerCustomizer> serverCustomizers) { JettyServletWebServerFactory factory = new JettyServletWebServerFactory(); factory.getServerCustomizers().addAll((Collection)serverCustomizers.orderedStream().collect(Collectors.toList())); return factory; } } @Configuration(proxyBeanMethods = false) // 判断classpath下有没有Servlet, Tomcat, UpgradeProtocol这三个类,即看maven有没有引入对应的依赖 @ConditionalOnClass({Servlet.class, Tomcat.class, UpgradeProtocol.class}) //容器中没有ServletWebServerFactory这个组件,下面的配置就生效 @ConditionalOnMissingBean(value = {ServletWebServerFactory.class},search = SearchStrategy.CURRENT) static class EmbeddedTomcat { //Tomcat配置类 EmbeddedTomcat() { } @Bean TomcatServletWebServerFactory tomcatServletWebServerFactory(ObjectProvider<TomcatConnectorCustomizer> connectorCustomizers, ObjectProvider<TomcatContextCustomizer> contextCustomizers, ObjectProvider<TomcatProtocolHandlerCustomizer<?>> protocolHandlerCustomizers) { TomcatServletWebServerFactory factory = new TomcatServletWebServerFactory(); factory.getTomcatConnectorCustomizers().addAll((Collection)connectorCustomizers.orderedStream().collect(Collectors.toList())); factory.getTomcatContextCustomizers().addAll((Collection)contextCustomizers.orderedStream().collect(Collectors.toList())); factory.getTomcatProtocolHandlerCustomizers().addAll((Collection)protocolHandlerCustomizers.orderedStream().collect(Collectors.toList())); return factory; } } }
以TomcatServletWebServerFactory为例:类中有 getWebServer 方法;
public WebServer getWebServer(ServletContextInitializer... initializers) { if (this.disableMBeanRegistry) { Registry.disableRegistry(); } //创建一个Tomcat Tomcat tomcat = new Tomcat(); //配置Tomcat的基本环节 File baseDir = this.baseDirectory != null ? this.baseDirectory : this.createTempDir("tomcat"); tomcat.setBaseDir(baseDir.getAbsolutePath()); Connector connector = new Connector(this.protocol); connector.setThrowOnFailure(true); 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); //将配置好的Tomcat传入进去,返回一个TomcatWebServer;并且启动Tomcat服务器 return this.getTomcatWebServer(tomcat); }
在getTomcatWebServer方法中,返回TomcatWebServer构造方法;
protected TomcatWebServer getTomcatWebServer(Tomcat tomcat) { return new TomcatWebServer(tomcat, this.getPort() >= 0); }
进入构造方法TomcatWebServer,在构造方法中又调用了this.initialize() 方法;
public TomcatWebServer(Tomcat tomcat, boolean autoStart) { this.monitor = new Object(); this.serviceConnectors = new HashMap(); Assert.notNull(tomcat, "Tomcat Server must not be null"); this.tomcat = tomcat; this.autoStart = autoStart; this.initialize(); }
进入initialize方法,该方法就会启动tomcat ;
private void initialize() throws WebServerException { logger.info("Tomcat initialized with port(s): " + this.getPortsDescription(false)); ... //启动Tomcat this.tomcat.start(); ... }
修改嵌入式Servlet容器配置的原理:
SpringBoot2.x.x 版本: ServletWebServerFactoryAutoConfiguration:
//把ServerProperties注册到容器中,并读取全局配置文件中的数据赋值给类中的属性 @EnableConfigurationProperties({ServerProperties.class}) ////使用@Import注解将对应组件加载到容器 @Import({ServletWebServerFactoryAutoConfiguration.BeanPostProcessorsRegistrar.class,//后置处理类 EmbeddedTomcat.class, //Tomcat配置类 EmbeddedJetty.class, //Jetty配置类 EmbeddedUndertow.class}) //Undertow配置类 public class ServletWebServerFactoryAutoConfiguration { public ServletWebServerFactoryAutoConfiguration() { } }
BeanPostProcessorsRegistrar:
/** * 后置处理器:Bean初始化前后(创建好对象,还没赋值)执行初始化工作 * 容器中某个组件要创建bean,就会惊动后置处理器,容器中要创建bean这个才会触发,下面的方法才会被调用 * 当前这个bean就是嵌入式的Servlet容器 */ public static class BeanPostProcessorsRegistrar implements ImportBeanDefinitionRegistrar, BeanFactoryAware { private ConfigurableListableBeanFactory beanFactory; public BeanPostProcessorsRegistrar() { } //设置BeanFactory public void setBeanFactory(BeanFactory beanFactory) throws BeansException { if (beanFactory instanceof ConfigurableListableBeanFactory) { this.beanFactory = (ConfigurableListableBeanFactory)beanFactory; } } //注册bean的定义 public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) { if (this.beanFactory != null) { //注意 WebServerFactoryCustomizerBeanPostProcessor类 this.registerSyntheticBeanIfMissing(registry, "webServerFactoryCustomizerBeanPostProcessor", WebServerFactoryCustomizerBeanPostProcessor.class); this.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); } } }
WebServerFactoryCustomizerBeanPostProcessor:postProcessBeforeInitialization 方法;
//如果当前初始化的是一个WebServerFactory类型的组件,就调用postProcessBeforeInitialization方法 public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { if (bean instanceof WebServerFactory) { this.postProcessBeforeInitialization((WebServerFactory)bean); } return bean; } // 获得所有的定制器,然后遍历,调用每个定制器的customize方法,并把嵌入式的Servlet容器传进去 private void postProcessBeforeInitialization(WebServerFactory webServerFactory) { ((Callbacks)LambdaSafe.callbacks(WebServerFactoryCustomizer.class, this.getCustomizers(), webServerFactory, new Object[0]).withLogger(WebServerFactoryCustomizerBeanPostProcessor.class)).invoke((customizer) -> { customizer.customize(webServerFactory); }); } private Collection<WebServerFactoryCustomizer<?>> getCustomizers() { if (this.customizers == null) { //从容器中获取所有这种类型的组件:WebServerFactoryCustomizer this.customizers = new ArrayList(this.getWebServerFactoryCustomizerBeans()); this.customizers.sort(AnnotationAwareOrderComparator.INSTANCE); this.customizers = Collections.unmodifiableList(this.customizers); } return this.customizers; } ////定制Servlet容器,给容器中可以添加一个WebServerFactoryCustomizer类型的组件 private Collection<WebServerFactoryCustomizer<?>> getWebServerFactoryCustomizerBeans() { return this.beanFactory.getBeansOfType(WebServerFactoryCustomizer.class, false, false).values(); }
步骤:
1,SpringBoot根据导入的依赖情况,给容器中添加相应的ServletWebServerFactory(嵌入式Servlet容器工厂);
2,容器中某个组件要创建对象就会惊动后置处理器 BeanPostProcessorsRegistrar,只要是嵌入式的Servlet容器工厂,后置处理器就工作;
3,后置处理器,从容器中获取所有的 WebServerFactoryCustomizer,调用定制器的定制方法;
嵌入式Servlet容器启动原理:
1,SpringBoot应用启动运行run方法;
2,this.refreshContext(context):SpringBoot刷新IOC容器:创建IOC容器对象,并初始化容器,创建容器中的每一个组件;如果是Web应用,创建AnnotationConfigServletWebServerApplicationContext
或者 AnnotationConfigReactiveWebServerApplicationContext ,
否则创建 AnnotationConfigApplicationContext;
protected ConfigurableApplicationContext createApplicationContext() { Class<?> contextClass = this.applicationContextClass; if (contextClass == null) { try { switch(this.webApplicationType) { case SERVLET: contextClass = Class.forName("org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext"); break; case REACTIVE: contextClass = Class.forName("org.springframework.boot.web.reactive.context.AnnotationConfigReactiveWebServerApplicationContext"); break; default: contextClass = Class.forName("org.springframework.context.annotation.AnnotationConfigApplicationContext"); } } catch (ClassNotFoundException var3) { throw new IllegalStateException("Unable create a default ApplicationContext, please specify an ApplicationContextClass", var3); } } return (ConfigurableApplicationContext)BeanUtils.instantiateClass(contextClass); }
3, this.refresh(context):刷新刚才创建好的ioc容器;
public void refresh() throws BeansException, IllegalStateException { Object var1 = this.startupShutdownMonitor; synchronized(this.startupShutdownMonitor) { this.prepareRefresh(); ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory(); this.prepareBeanFactory(beanFactory); try { this.postProcessBeanFactory(beanFactory); this.invokeBeanFactoryPostProcessors(beanFactory); this.registerBeanPostProcessors(beanFactory); this.initMessageSource(); this.initApplicationEventMulticaster(); this.onRefresh(); this.registerListeners(); this.finishBeanFactoryInitialization(beanFactory); this.finishRefresh(); } catch (BeansException var9) { if (this.logger.isWarnEnabled()) { this.logger.warn("Exception encountered during context initialization - cancelling refresh attempt: " + var9); } this.destroyBeans(); this.cancelRefresh(var9); throw var9; } finally { this.resetCommonCaches(); } } }
4,onRefresh():Web的IOC容器重写了onRefresh方法;
protected void onRefresh() { super.onRefresh(); try { this.createWebServer(); } catch (Throwable var2) { throw new ApplicationContextException("Unable to start web server", var2); } }
5,createWebServer():Web的IOC容器会创建嵌入式的Servlet容器;
private void createWebServer() { WebServer webServer = this.webServer; ServletContext servletContext = this.getServletContext(); if (webServer == null && servletContext == null) { ServletWebServerFactory factory = this.getWebServerFactory(); this.webServer = factory.getWebServer(new ServletContextInitializer[]{this.getSelfInitializer()}); } else if (servletContext != null) { try { this.getSelfInitializer().onStartup(servletContext); } catch (ServletException var4) { throw new ApplicationContextException("Cannot initialize servlet context", var4); } } this.initPropertySources(); }
6,获取嵌入式的Servlet容器工厂:从IOC容器中获取ServletWebServerFactory组件;例如:TomcatServletWebServerFactory 创建对象,后置处理器发现是这个对象,就获取所有的定制器来先定制Servlet容器的相关配置;
ServletWebServerFactory factory = this.getWebServerFactory();
7,使用容器工厂获取嵌入式的Servlet容器;
this.webServer = factory.getWebServer(new ServletContextInitializer[]{this.getSelfInitializer()});
8,嵌入式的Servlet容器创建对象并启动Servlet容器:先启动嵌入式的Servlet容器,再将ioc容器中剩下没有创建出的对象获取出来;
- 点赞
- 收藏
- 分享
- 文章举报
- SpringBoot基础——SpringBoot配置嵌入式Servlet容器
- SpringBoot中配置嵌入式Servlet容器
- 【spring-boot】spring-boot-配置嵌入式Servlet容器学习
- SpringBoot之配置嵌入式Servlet容器
- Spring Boot 学习笔记(五) 配置Servlet容器
- SpringBoot-2.2.5 对java jdk maven Servlet容器版本配置要求
- SpringBoot中嵌入式Servlet容器启动原理;
- 十、SpringBoot——Servlet容器配置&相关原理(tomcat)
- Spring-Boot使用嵌入式容器,那怎么配置自定义Filter呢
- Spring实现原理分析(二十六).Spring Boot关于嵌入式servlet容器
- 如何定制和修改Servlet容器的相关配置--spring boot
- SpringBoot初始教程之Servlet、Filter、Listener配置(七)
- IntelliJ IDEA 配置Gradle运行SpringBoot Web项目(tomcat容器)
- spring boot 如何添加配置到ioc容器中
- IntelliJ IDEA 配置Gradle运行SpringBoot Web项目(tomcat容器)
- 嵌入式Servlet容器自定义配置
- SpringBoot 源码解析 (六)----- Spring Boot的核心能力 - 内置Servlet容器源码分析(Tomcat)
- servlet调用spring容器中的bean,的两种方式一种注解一种xml配置
- 在部署到Servlet容器之前,如何生成包含SpringBoot的War文件
- SpringBoot入门-12(springboot配置servlet,利用代码实现)