组件注册整合Servlet三大组件
在Spring Boot中,使用组件注册方式整合内嵌Servlet容器的Servlet、Filter、Listener三大组件时,只需将这些自定义组件通过ServletRegistrationBean、FilterRegistrationBean、ServletListenerRegistrationBean类注册到容器中即可,这些类相当于将组件配置在web.xml中。
1. 使用组件注册方式整合Servlet
(1)创建自定义Servlet类。在chapter05项目中创建名为com.itheima.servletComponent的包,并在该包下创建一个自定义Servlet类MyServlet,内容如文件1所示。
文件1 MyServlet.java
1 import org.springframework.stereotype.Component;
2 import javax.servlet.ServletException;
3 import javax.servlet.http.*;
4 import java.io.IOException;
5 /**
6 * 自定义Servlet类
7 */
8 @Component
9 public class MyServlet extends HttpServlet {
10 @Override
11 protected void doGet(HttpServletRequest req, HttpServletResponse resp)
12 throws ServletException, IOException {
13 this.doPost(req, resp);
14 }
15 @Override
16 protected void doPost(HttpServletRequest req, HttpServletResponse resp)
17 throws ServletException, IOException {
18 resp.getWriter().write("hello MyServlet");
19 }
20 }
文件1中,使用@Component注解将MyServlet类作为组件注入Spring容器。MyServlet类继承自HttpServlet,通过HttpServletResponse对象向页面输出“hello MyServlet”。
(2)创建Servlet组件配置类。在项目com.itheima.config包下创建一个Servlet组件配置类ServletConfig,用来对Servlet相关组件进行注册,内容如文件2所示。
文件2 ServletConfig.java
1 import com.itheima.servletComponent.MyServlet;
2 import org.springframework.boot.web.servlet.ServletRegistrationBean;
3 import org.springframework.context.annotation.Bean;
4 import org.springframework.context.annotation.Configuration;
5 /**
6 * 嵌入式Servlet容器三大组件配置
7 */
8 @Configuration
9 public class ServletConfig {
10 // 注册Servlet组件
11 @Bean
12 public ServletRegistrationBean getServlet(MyServlet myServlet){
13 ServletRegistrationBean registrationBean =
14 new ServletRegistrationBean(myServlet,"/myServlet");
15 return registrationBean;
16 }
17 }
文件2中,使用@Configuration注解定义了一个Servlet组件配置类ServletConfig,并添加了一个getServlet(MyServlet myServlet)方法,通过组件注册的方式注册自定义的MyServlet组件。在注册自定义的MyServlet组件时,指定了匹配路径为“/myServlet”,并使用@Bean注解将重新组装的ServletRegistrationBean类对象作为Bean组件返回。
启动项目进行测试。项目启动成功后,在浏览器上访问“http://localhost:8080/myServlet
”,效果如图1所示。
图1 自定义Servlet组件访问效果
从图1中可以看出,浏览器能够访问myServlet并正常显示数据,说明Spring Boot成功整合了Servlet组件。
1. 使用组件注册方式整合Filter
(1) 创建自定义Filter类。在com.itheima.servletComponent包下创建一个类MyFilter,内容如文件3所示。
文件3 MyFilter.java
1 import org.springframework.stereotype.Component;
2 import javax.servlet.*;
3 import java.io.IOException;
4 /**
5 * 自定义Filter类
6 */
7 @Component
8 public class MyFilter implements Filter {
9 @Override
10 public void init(FilterConfig filterConfig) throws ServletException { }
11 @Override
12 public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse,
13 FilterChain filterChain) throws IOException, ServletException {
14 System.out.println("hello MyFilter");
15 filterChain.doFilter(servletRequest,servletResponse);
16 }
17 @Override
18 public void destroy() { }
19 }
文件3中,使用@Component注解将当前MyFilter类作为组件注入到Spring容器中。MyFilter类实现Filter接口,并重写了init()、doFilter()和destroy()方法,在doFilter()方法中向控制台打印了“hello MyFilter”字符串。
(1) 向Servlet组件配置类注册自定义Filter类。打开之前创建的Servlet组件配置类ServletConfig,将该自定义Filter类使用组件注册方式进行注册,示例代码如下。
// 注册Filter组件
@Bean
public FilterRegistrationBean getFilter(MyFilter filter){
FilterRegistrationBean registrationBean = new FilterRegistrationBean(filter);
registrationBean.setUrlPatterns(Arrays.asList("/toLoginPage","/myFilter"));
return registrationBean;
}
上述代码中,使用组件注册方式注册自定义的MyFilter类。在getFilter(MyFilter filter)方法中,使用setUrlPatterns(Arrays.asList("/toLoginPage","/myFilter"))方法定义了过滤的请求路径为“/toLoginPage”和“/myFilter”,同时使用@Bean注解将当前组装好的FilterRegistrationBean对象作为Bean组件返回。
完成Filter的自定义配置后启动项目,项目启动成功后,在浏览器上访问“http://localhost:8080/myFilter
”查看控制台打印效果(由于没有编写对应路径的请求处理方法,所以浏览器会出现404错误页面,这里重点关注控制台即可),具体如图2所示。
图2 自定义Filter组件访问效果
在图2中,浏览器访问“http://localhost:8080/myFilter
”时控制台打印出了自定义Filter中定义的输出语句“hello MyFilter”,这也就说明Spring Boot整合自定义Filter组件成功。
1. 使用组件注册方式整合Listener
(1)创建自定义Listener类。在com.itheima.servletComponent包下创建一个类MyListener,内容如文件4所示。
文件4 MyListener.java
1 import org.springframework.stereotype.Component;
2 import javax.servlet.ServletContextEvent;
3 import javax.servlet.ServletContextListener;
4 /**
5 * 自定义Listener类
6 */
7 @Component
8 public class MyListener implements ServletContextListener {
9 @Override
10 public void contextInitialized(ServletContextEvent servletContextEvent) {
11 System.out.println("contextInitialized ...");
12 }
13 @Override
14 public void contextDestroyed(ServletContextEvent servletContextEvent) {
15 System.out.println("contextDestroyed ...");
16 }
17 }
文件4中,使用@Component注解将MyListener类作为组件注册到Spring容器中。Listener类实现了ServletContextListener接口,并重写了contextInitialized()和contextDestroyed()方法。
需要说明的是,Servlet容器提供了很多Listener接口,例如ServletRequestListener、HttpSessionListener、ServletContextListener等,我们在自定义Listener类时要根据自身需求选择实现这些接口,这里为了方便演示,直接实现了ServletContextListener接口。
(2)向Servlet组件配置类注册自定义Listener类。打开之前创建的Servlet组件配置类ServletConfig,将该自定义Listener类使用组件注册方式进行注册,示例代码如下。
// 注册Listener组件
@Bean
public ServletListenerRegistrationBean getServletListener(MyListener myListener){
ServletListenerRegistrationBean registrationBean =
new ServletListenerRegistrationBean(myListener);
return registrationBean;
}
上述代码中,使用组件注册方式注册了一个自定义的MyListener类,在getServletListener()方法中,使用了@Bean注解将当前组装好的FilterRegistrationBean对象作为Bean组件返回。
完成自定义Listener组件注册后启动项目,项目启动成功后查看控制台打印效果,效果如图3所示。
图3 自定义Listener组件初始化效果
程序启动成功后,控制台会打印出自定义Listener组件中定义的输出语句“contextInitialized ...”。单击图中的【Exit】按钮关闭当前项目(注意,如果直接单击红色按钮会强制关闭程序,浏览器就无法打印关闭监听信息),再次查看控制台打印效果,效果如图4所示。
图4 自定义Listener组件关闭效果
程序成功关闭后,控制台打印出了自定义Listener组件中定义的输出语句“contextDestroyed ...”。通过效果演示,说明了Spring Boot整合自定义Listener组件成功。
细心的读者可能发现,将自定义的Servlet组件配置类ServletConfig全部注释并重启项目后,自定义的Servlet、Filter、Listener组件仍然生效。出现这种情况的主要原因是:嵌入式Servlet容器对Servlet、Filter、Listener组件进行了自动化识别和配置,而自定义的Servlet、Filter、Listener都继承/实现了对应的类/接口,同时自定义的Servlet、Filter、Listener组件都使用了@Component注解,这些组件会被自动扫描为Spring组件。
使用ServletRegistrationBean、FilterRegistrationBean、ServletListenerRegistrationBean组件组装配置的根本目的是对一些请求路径和参数进行初始化设置和组装。假设没有组件注册类,那么自定义Servlet虽然生效,但无法确定生效哪个访问路径。自定义的Filter会对所有的请求都进行过滤,不会出现选择性过滤的情况。而自定义的Listener则没有太大影响,因为定制该组件基本不需要设置什么参数。