嵌入式Servlet容器
一、如何定制和修改Servlet容器的相关配置;
- 修改和server有关的配置(ServerProperties【也是EmbeddedServletContainerCustomizer】);
1 | 8081 = |
- 编写一个EmbeddedServletContainerCustomizer:嵌入式的Servlet容器的定制器;来修改Servlet容器的配置
1 | //一定要将这个定制器加入到容器中 |
二、如何定制和修改Servlet容器的相关配置;
- 修改和server有关的配置(ServerProperties【也是EmbeddedServletContainerCustomizer】);
1 | 8081 = |
- 编写一个EmbeddedServletContainerCustomizer:嵌入式的Servlet容器的定制器;来修改Servlet容器的配置
1 | //一定要将这个定制器加入到容器中 |
三、注册Servlet三大组件【Servlet、Filter、Listener】
-
由于SpringBoot默认是以jar包的方式启动嵌入式的Servlet容器来启动SpringBoot的web应用,没有web.xml文件。
-
注册三大组件用以下方式
-
ServletRegistrationBean
1 | //注册三大组件 |
- FilterRegistrationBean
1 |
|
- ServletListenerRegistrationBean
1 |
|
-
SpringBoot帮我们自动SpringMVC的时候,自动的注册SpringMVC的前端控制器;DIspatcherServlet;
-
DispatcherServletAutoConfiguration中:
1 | (name = DEFAULT_DISPATCHER_SERVLET_REGISTRATION_BEAN_NAME) |
四、替换为其他嵌入式Servlet容器
默认支持:
Tomcat(默认使用)
1 | <dependency> |
Jetty(常做长连接——聊天类)
1 | <!-- 引入web模块 --> |
Undertow(不支持JSP,高并发)
1 | <!-- 引入web模块 --> |
五、嵌入式Servlet容器自动配置原理;
- EmbeddedServletContainerAutoConfiguration:嵌入式的Servlet容器自动配置?
1 | (Ordered.HIGHEST_PRECEDENCE) |
1)、EmbeddedServletContainerFactory(嵌入式Servlet容器工厂)
1 | public interface EmbeddedServletContainerFactory { |
2)、EmbeddedServletContainer:(嵌入式的Servlet容器)
3)、以TomcatEmbeddedServletContainerFactory为例
1 |
|
4)、我们对嵌入式容器的配置修改是怎么生效?
1 | ServerProperties、EmbeddedServletContainerCustomizer |
EmbeddedServletContainerCustomizer:定制器帮我们修改了Servlet容器的配置?
- 怎么修改的原理:
5)、容器中导入了EmbeddedServletContainerCustomizerBeanPostProcessor
1 | //初始化之前 |
步骤:
1)、SpringBoot根据导入的依赖情况,给容器中添加相应的 EmbeddedServletContainerFactory【TomcatEmbeddedServletContainerFactory】
2)、容器中某个组件要创建对象就会惊动后置处理器;EmbeddedServletContainerCustomizerBeanPostProcessor;
- 只要是嵌入式的Servlet容器工厂,后置处理器就工作;
3)、后置处理器,从容器中获取所有的EmbeddedServletContainerCustomizer,调用定制器的定制方法
六、嵌入式Servlet容器启动原理;
- 什么时候创建嵌入式的Servlet容器工厂?什么时候获取嵌入式的Servlet容器并启动Tomcat;
获取嵌入式的Servlet容器工厂:
1)、SpringBoot应用启动运行run方法
2)、refreshContext(context);SpringBoot刷新IOC容器【创建IOC容器对象,并初始化容器,创建容器中的每一个组件】;如果是web应用创建AnnotationConfigEmbeddedWebApplicationContext,否则:AnnotationConfigApplicationContext
3)、refresh(context);刷新刚才创建好的ioc容器;
1 | public void refresh() throws BeansException, IllegalStateException { |
4)、 onRefresh(); web的ioc容器重写了onRefresh方法
5)、webioc容器会创建嵌入式的Servlet容器;createEmbeddedServletContainer();
6)、获取嵌入式的Servlet容器工厂:
-
EmbeddedServletContainerFactory containerFactory = getEmbeddedServletContainerFactory();
从ioc容器中获取EmbeddedServletContainerFactory 组件;TomcatEmbeddedServletContainerFactory创建对象,后置处理器一看是这个对象,就获取所有的定制器来先定制Servlet容器的相关配置;
7)、使用容器工厂获取嵌入式的Servlet容器:this.embeddedServletContainer = containerFactory .getEmbeddedServletContainer(getSelfInitializer());
8)、嵌入式的Servlet容器创建对象并启动Servlet容器;
-
先启动嵌入式的Servlet容器,再将ioc容器中剩下没有创建出的对象获取出来;
-
IOC容器启动创建嵌入式的Servlet容器
七、使用外置的Servlet容器
-
嵌入式Servlet容器:应用打成可执行的jar
优点:简单、便携; 缺点:默认不支持JSP、优化定制比较复杂(使用定制器【ServerProperties、自定义EmbeddedServletContainerCustomizer】,自己编写嵌入式Servlet容器的创建工厂【EmbeddedServletContainerFactory】);
-
外置的Servlet容器:外面安装Tomcat—应用war包的方式打包;
步骤
1)、必须创建一个war项目;(利用idea创建好目录结构)
2)、将嵌入式的Tomcat指定为provided;
1 | <dependency> |
3)、必须编写一个SpringBootServletInitializer的子类,并调用configure方法
1 | public class ServletInitializer extends SpringBootServletInitializer { |
4)、启动服务器就可以使用;
原理
jar包:执行SpringBoot主类的main方法,启动ioc容器,创建嵌入式的Servlet容器;
war包:启动服务器,服务器启动SpringBoot应用【SpringBootServletInitializer】,启动ioc容器;
servlet3.0(Spring注解版):
8.2.4 Shared libraries / runtimes pluggability:
规则:
1)、服务器启动(web应用启动)会创建当前web应用里面每一个jar包里面ServletContainerInitializer实例:
2)、ServletContainerInitializer的实现放在jar包的META-INF/services文件夹下,有一个名为javax.servlet.ServletContainerInitializer的文件,内容就是ServletContainerInitializer的实现类的全类名
3)、还可以使用@HandlesTypes,在应用启动的时候加载我们感兴趣的类;
流程:
1)、启动Tomcat
2)、org\springframework\spring-web\4.3.14.RELEASE\spring-web-4.3.14.RELEASE.jar!\META-INF\services\javax.servlet.ServletContainerInitializer:
- Spring的web模块里面有这个文件:org.springframework.web.SpringServletContainerInitializer
3)、SpringServletContainerInitializer将@HandlesTypes(WebApplicationInitializer.class)标注的所有这个类型的类都传入到onStartup方法的Set<Class<?>>;为这些WebApplicationInitializer类型的类创建实例;
4)、每一个WebApplicationInitializer都调用自己的onStartup;
5)、相当于我们的SpringBootServletInitializer的类会被创建对象,并执行onStartup方法
6)、SpringBootServletInitializer实例执行onStartup的时候会createRootApplicationContext;创建容器
1 | protected WebApplicationContext createRootApplicationContext( |
7)、Spring的应用就启动并且创建IOC容器
1 | public ConfigurableApplicationContext run(String... args) { |
启动Servlet容器,再启动SpringBoot应用