嵌入式 servlet 容器
在 spring boot 之前的web开发,我们都是把我们的应用部署到 Tomcat 等servelt容器,这些容器一般都会在我们的应用服务器上安装好环境,但是 spring boot 中并不需要外部应用服务器安装这些servlet容器,spring boot自带了嵌入式的servlet容器。
如何修改和定制嵌入式servlet容器
- 在application.yaml文件中配置修改
#修改服务端口号
server.port=8081
#配置统一请求路径
server.context‐path=/crud#配置tomcat相关
server.tomcat.uri‐encoding=UTF‐8
这些配置相关的属性都定义在org.springframework.boot.autoconfigure.web.ServerProperties
类中
- 编写一个嵌入式的servlet容器的定制器来修改相关的配置
@Component
public class CustomizationBean implements WebServerFactoryCustomizer<ConfigurableServletWebServerFactory> {@Overridepublic void customize(ConfigurableServletWebServerFactory server) {server.setPort(9000);}
}
- 直接定制具体的servlet容器配置,比如 tomcat 容器
@Configuration
public class ApplicationConfig implements WebMvcConfigurer {@Beanpublic ConfigurableServletWebServerFactory configurableServletWebServerFactory() {TomcatServletWebServerFactory factory = new TomcatServletWebServerFactory();factory.setPort(8585);return factory;}
}
注册 Servlet、Filter、Listener
spring boot默认是以 jar 包的方式启动嵌入式的 servlet 容器来启动web应用,应用中并没有 web.xml 文件,我们注册 servlet, filter, 和 listener
三大组件可以使用以下方式
-
利用
ServletRegistrationBean
注册servlet
- 定义自己的
servlet
public class MyServlet extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp)throws ServletException, IOException {resp.getWriter().print("servlet doGet");} }
- 给容器中注册自己的
servlet
@Configuration public class ApplicationConfig implements WebMvcConfigurer {@Beanpublic ServletRegistrationBean myServlet() {ServletRegistrationBean servletRegistrationBean =new ServletRegistrationBean(new MyServlet(), "/hello/servlet");return servletRegistrationBean;} }
- 定义自己的
-
利用
FilterRegistrationBean
注册filter
- 定义
filter
`
public class MyFilter implements Filter {@Overridepublic void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)throws IOException, ServletException {System.out.println("do myFilter");chain.doFilter(request, response);} }
- 容器中注册
filter
@Configuration public class ApplicationConfig implements WebMvcConfigurer {@Beanpublic FilterRegistrationBean myFilter() {FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();//注册自己的 filterfilterRegistrationBean.setFilter(new MyFilter());//注册拦截路径filterRegistrationBean.setUrlPatterns(Arrays.asList("/hello", "/hello/servlet"));return filterRegistrationBean;} }
访问
"/hello", "/hello/servlet"
请求时拦截器就会起作用。 - 定义
-
利用
ServletListenerRegistrationBean
注册listener
- 定义一个
listener
public class MyListener implements ServletContextListener {@Overridepublic void contextInitialized(ServletContextEvent sce) {System.out.println("contextInitialized ... web应用启动");}@Overridepublic void contextDestroyed(ServletContextEvent sce) {System.out.println("contextDestroyed ... web应用销毁");} }
- 容器中注册
listener
@Configuration public class ApplicationConfig implements WebMvcConfigurer {@Beanpublic ServletListenerRegistrationBean myListener() {ServletListenerRegistrationBean<MyListener> listenerRegistrationBean =new ServletListenerRegistrationBean(new MyListener());return listenerRegistrationBean;} }
- 定义一个
切换其他 servlet 容器
spring boot 中默认使用的是 tomcat 容器,那么如何切换使用其他容器呢,比如 jetty。那么如何切换成其他的呢?只需要修改 pom.xml 文件
<!‐‐ 引入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>
使用外部 servlet 容器
部署项目的服务器安装 servlet 容器,比如 tomcat、jetty 容器,然后项目打成 war 包的形式进行部署
如何创建一个 war 包启动的 spring boot 项目呢?
- 创建一个war打包形式的web项目,其目录结构如下
-
修改 pom.xml 文件
-
修改打包方式
pom.xml 文件中的打包方式设置成 war 即可, ```<packaging>war</packaging>```
-
修改嵌入的 servlet 容器
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-tomcat</artifactId><scope>provided</scope> </dependency>
-
- 编写一个类继承
SpringBootServletInitializer
类
public class ServletInitializer extends SpringBootServletInitializer {@Overrideprotected SpringApplicationBuilder configure(SpringApplicationBuilder application) {return application.sources(SpringBootWarApplication.class);}
}
使用外部 servlet 容器原理
jar包和war的启动过程
- jar包: 执行spring boot 主类的main方法,启动ioc容器,然后创建嵌入式的servlet容器
- war包: 启动tomcat服务器,服务器启动spring boot应用,通过
SpringBootServletInitializer
实现,启动ioc容器
spring boot使用外部servlet过程
servlet3.0标准中规定
- web应用启动会创建当前web应用里面每一个jar包里面
ServletContainerInitializer
类型的实例 -
ServletContainerInitializer
的实现放在jar包的META-INF/services文件夹下,有一个名为javax.servlet.ServletContainerInitializer
的文件,文件内容就是ServletContainerInitializer
实现类的全类名 - 使用@HandlesTypes注解在应用启动的时候加载我们需要的类
spring boot使用war启动原理
- 重写
SpringBootServletInitializer
的configure(SpringApplicationBuilder application)
方法,调用SpringApplicationBuilder
的sources(Class<?>... sources)
方法 -
启动原理
- Servlet3.0标准ServletContainerInitializer扫描所有jar包中
META- INF/services/javax.servlet.ServletContainerInitializer
文件指定的类并加载 - 加载spring web包下的
org.springframework.web.SpringServletContainerInitializer
- 扫描
@HandleType(WebApplicationInitializer)
`,即扫描WebApplicationInitializer
的所有实现类 - 加载
SpringBootServletInitializer
并运行onStartup
方法 - 加载
@SpringBootApplication
主类,启动容器
- Servlet3.0标准ServletContainerInitializer扫描所有jar包中