springboot配置嵌入式的servlet容器的原理(一)
使用IDEA打开pom文件,单击右键,如图所示:我么可以发现,springboot给我们内置了tomcat9.xx如此,我们就不需要再把springboot项目打包放到tomcat中发布了。因为它内置了嵌入式的tomcat;如何修改springboot的servlet容器设置在springboot2.0之前,我们通过编写一个EmbeddedServletContainerCustomizer:嵌入
本笔记源码地址:https://github.com/pshdhx/springbootcurd
使用IDEA打开pom文件,单击右键,如图所示:
我么可以发现,springboot给我们内置了tomcat9.xx
如此,我们就不需要再把springboot项目打包放到tomcat中发布了。因为它内置了嵌入式的tomcat;
如何修改springboot的servlet容器设置
在springboot2.0之前,我们通过编写一个EmbeddedServletContainerCustomizer:嵌入式的Servlet容器的定制器;来修改Servlet容器的配置
@Bean //一定要将这个定制器加入到容器中
public EmbeddedServletContainerCustomizer embeddedServletContainerCustomizer(){
return new EmbeddedServletContainerCustomizer() {
//定制嵌入式的Servlet容器相关的规则
@Override
public void customize(ConfigurableEmbeddedServletContainer container) {
container.setPort(8083);
}
};
}
但是2.0之后这个类被取消了,使用了
WebServerFactoryCustomizer这个类来代替;
package com.pshdhx.config;
import org.springframework.boot.web.server.ConfigurableWebServerFactory;
import org.springframework.boot.web.server.WebServerFactory;
import org.springframework.boot.web.server.WebServerFactoryCustomizer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
/**
* @Authtor pshdhx
* @Date 2020/11/3020:46
* @Version 1.0
*/
@Configuration
public class MyServletConfiguration extends WebMvcConfigurerAdapter {
@Bean
public WebServerFactoryCustomizer<ConfigurableWebServerFactory> webServerFactoryCustomizer(){
return new WebServerFactoryCustomizer<ConfigurableWebServerFactory>() {
@Override
public void customize(ConfigurableWebServerFactory factory) {
factory.setPort(8083);
}
};
}
}
重启之后,tomcat生效;
1、springboot在自动配置很多组件的时候,先看容器中有没有用户自己配置的(@Bean,@Component),如果有,就用用户自己配置的,如果没有,才自动配置。有些组件可以有多个,如(ViewResolver)可以将用户配置的和自动配置的结合起来。
2、在springboot中会有很多的xxConfigurer帮助我们进行扩展配置
3、在springboot中会有很多的xxxCustomizer帮助我们进行定制配置。==>
custmize:定制
customizer:定制器
2)、注册Servlet三大组件【Servlet、Filter、Listener】
由于SpringBoot默认是以jar包的方式启动嵌入式的Servlet容器来启动SpringBoot的web应用,没有web.xml文件。
注册三大组件用以下方式
ServletRegistrationBean:servlet注册器
FilterRegistrationBean :过滤器注册器
ServletListenerRegistrationBean :监听器注册器
servlet配置
package com.pshdhx.servlet;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* @Authtor pshdhx
* @Date 2020/11/3021:16
* @Version 1.0
* 自定义servlet
*/
public class MyServlet extends HttpServlet {
//处理get请求
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doPost(req, resp);
}
//处理post请求
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.getWriter().write("Hello MyServlet");
}
}
Filter配置
package com.pshdhx.filter;
import javax.servlet.*;
import java.io.IOException;
/**
* @Authtor pshdhx
* @Date 2020/11/3021:37
* @Version 1.0
*/
public class MyFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println("filter 初始化");
}
@Override
public void destroy() {
System.out.println("filter 销毁");
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
System.out.println("filter 进行中");
}
}
Listener配置
package com.pshdhx.listener;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
/**
* @Authtor pshdhx
* @Date 2020/11/3021:45
* @Version 1.0
*/
public class MyListener implements ServletContextListener {
@Override
public void contextInitialized(ServletContextEvent sce) {
System.out.println("web应用启动");
}
@Override
public void contextDestroyed(ServletContextEvent sce) {
System.out.println("当前web应用销毁");
}
}
servlet注册器
package com.pshdhx.config;
import com.pshdhx.filter.MyFilter;
import com.pshdhx.listener.MyListener;
import com.pshdhx.servlet.MyServlet;
import org.springframework.boot.web.server.ConfigurableWebServerFactory;
import org.springframework.boot.web.server.WebServerFactory;
import org.springframework.boot.web.server.WebServerFactoryCustomizer;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.boot.web.servlet.ServletListenerRegistrationBean;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
import java.util.Arrays;
/**
* @Authtor pshdhx
* @Date 2020/11/3020:46
* @Version 1.0
*/
@Configuration
public class MyServletConfiguration extends WebMvcConfigurerAdapter {
//对嵌入式的tomcat容器进行设置,加入到容器中
@Bean
public WebServerFactoryCustomizer<ConfigurableWebServerFactory> webServerFactoryCustomizer(){
return new WebServerFactoryCustomizer<ConfigurableWebServerFactory>() {
@Override
public void customize(ConfigurableWebServerFactory factory) {
factory.setPort(8083);
}
};
}
//把Servlet注册到容器中
@Bean
public ServletRegistrationBean myServlet(){
ServletRegistrationBean registrationBean = new ServletRegistrationBean(new MyServlet(),"/myServlet");
//设置启动顺序
registrationBean.setLoadOnStartup(1);
return registrationBean;
}
//把Filter注册到容器中
@Bean
public FilterRegistrationBean myFilter(){
FilterRegistrationBean registrationBean = new FilterRegistrationBean();
registrationBean.setFilter(new MyFilter());
registrationBean.setUrlPatterns(Arrays.asList("/hello","/myServlet"));
return registrationBean;
}
//注册Listener监听组件到容器
@Bean
public ServletListenerRegistrationBean myListener(){
ServletListenerRegistrationBean<MyListener> registrationBean = new ServletListenerRegistrationBean<>(new MyListener());
return registrationBean;
}
}
使用Jetty服务器和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-jetty</artifactId>
<groupId>org.springframework.boot</groupId>
</dependency>
<!-- 引入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>
启动之后,即为Jeety和undertow服务器;
原理:
嵌入式Servlet容器自动配置原理
这是最新版的源码
@Configuration(proxyBeanMethods = false)
@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 {
导入的BeanPostProcessorsRegistrar.class是后置处理器,就是在组件初始化之后,再给组件进行配置。
后置处理器:bean初始化前后(创建完对象,还没赋值赋值)执行初始化工作
如果引入了tomcat,那么就是tomcat进行工厂类定制操作:
@Bean
@ConditionalOnClass(name = "org.apache.catalina.startup.Tomcat")
public TomcatServletWebServerFactoryCustomizer tomcatServletWebServerFactoryCustomizer(
ServerProperties serverProperties) {
return new TomcatServletWebServerFactoryCustomizer(serverProperties);
}
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass({ Servlet.class, Tomcat.class, UpgradeProtocol.class })
@ConditionalOnMissingBean(value = ServletWebServerFactory.class, search = SearchStrategy.CURRENT)
static class EmbeddedTomcat {
@Bean
TomcatServletWebServerFactory tomcatServletWebServerFactory(
ObjectProvider<TomcatConnectorCustomizer> connectorCustomizers,
ObjectProvider<TomcatContextCustomizer> contextCustomizers,
ObjectProvider<TomcatProtocolHandlerCustomizer<?>> protocolHandlerCustomizers) {
TomcatServletWebServerFactory factory = new TomcatServletWebServerFactory();
factory.getTomcatConnectorCustomizers()
.addAll(connectorCustomizers.orderedStream().collect(Collectors.toList()));
factory.getTomcatContextCustomizers()
.addAll(contextCustomizers.orderedStream().collect(Collectors.toList()));
factory.getTomcatProtocolHandlerCustomizers()
.addAll(protocolHandlerCustomizers.orderedStream().collect(Collectors.toList()));
return factory;
}
}
如果引入了jetty,那么就对其进行初始化操作org\springframework\boot\autoconfigure\web\servlet\ServletWebServerFactoryConfiguration.java
/**
* Nested configuration if Jetty is being used.
*/
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass({ Servlet.class, Server.class, Loader.class, WebAppContext.class })
@ConditionalOnMissingBean(value = ServletWebServerFactory.class, search = SearchStrategy.CURRENT)
static class EmbeddedJetty {
@Bean
JettyServletWebServerFactory JettyServletWebServerFactory(
ObjectProvider<JettyServerCustomizer> serverCustomizers) {
JettyServletWebServerFactory factory = new JettyServletWebServerFactory();
factory.getServerCustomizers().addAll(serverCustomizers.orderedStream().collect(Collectors.toList()));
return factory;
}
}
如果引入了undertow,那么就对其进行初始化操作
/**
* Nested configuration if Undertow is being used.
*/
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass({ Servlet.class, Undertow.class, SslClientAuthMode.class })
@ConditionalOnMissingBean(value = ServletWebServerFactory.class, search = SearchStrategy.CURRENT)
static class EmbeddedUndertow {
@Bean
UndertowServletWebServerFactory undertowServletWebServerFactory(
ObjectProvider<UndertowDeploymentInfoCustomizer> deploymentInfoCustomizers,
ObjectProvider<UndertowBuilderCustomizer> builderCustomizers) {
UndertowServletWebServerFactory factory = new UndertowServletWebServerFactory();
factory.getDeploymentInfoCustomizers()
.addAll(deploymentInfoCustomizers.orderedStream().collect(Collectors.toList()));
factory.getBuilderCustomizers().addAll(builderCustomizers.orderedStream().collect(Collectors.toList()));
return factory;
}
}
定制器帮我们修改了Servlet容器的配置?
怎么修改的原理?
--这个没找到到
//初始化之前
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName)
throws BeansException {
//如果当前初始化的是一个ConfigurableEmbeddedServletContainer类型的组件
if (bean instanceof ConfigurableEmbeddedServletContainer) {
//
postProcessBeforeInitialization((ConfigurableEmbeddedServletContainer) bean);
}
return bean;
}
private void postProcessBeforeInitialization(
ConfigurableEmbeddedServletContainer bean) {
//获取所有的定制器,调用每一个定制器的customize方法来给Servlet容器进行属性赋值;
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
//从容器中获取所有这葛类型的组件:EmbeddedServletContainerCustomizer
//定制Servlet容器,给容器中可以添加一个EmbeddedServletContainerCustomizer类型的组件
.getBeansOfType(EmbeddedServletContainerCustomizer.class,
false, false)
.values());
Collections.sort(this.customizers, AnnotationAwareOrderComparator.INSTANCE);
this.customizers = Collections.unmodifiableList(this.customizers);
}
return this.customizers;
}
org\springframework\boot\autoconfigure\web\ServerProperties.java也是定制器
步骤:
1)、SpringBoot根据导入的依赖情况,给容器中添加相应的EmbeddedServletContainerFactory【TomcatEmbeddedServletContainerFactory】
2)、容器中某个组件要创建对象就会惊动后置处理器;EmbeddedServletContainerCustomizerBeanPostProcessor;
只要是嵌入式的Servlet容器工厂,后置处理器就工作;
3)、后置处理器,从容器中获取所有的EmbeddedServletContainerCustomizer,调用定制器的定制方法
难点:
因为是看视频资料是以前的,很多类都过时了,或者找不到了,需要找到最新的类去读源码,费时费力。
像是
WebServerFactoryCustomizer这个类即是2.0之后出的,之前的EmbeddedServletContainerCustomizer这个类就不用了,诸如此类的。
更多推荐
所有评论(0)