更新時間:2021年07月05日17時00分 來源:傳智教育 瀏覽次數(shù):
在Spring Boot中,使用組件注冊方式整合內(nèi)嵌Servlet容器的Servlet、Filter、Listener三大組件時,只需將這些自定義組件通過ServletRegistrationBean、FilterRegistrationBean、ServletListenerRegistrationBean類注冊到容器中即可,這些類相當(dāng)于將組件配置在web.xml中。
1. 使用組件注冊方式整合Servlet
(1)創(chuàng)建自定義Servlet類。在chapter05項目中創(chuàng)建名為com.itheima.servletComponent的包,并在該包下創(chuàng)建一個自定義Servlet類MyServlet,內(nèi)容如文件1所示。
文件1 MyServlet.java
import org.springframework.stereotype.Component; import javax.servlet.ServletException; import javax.servlet.http.*; import java.io.IOException; /** * 自定義Servlet類 */ @Component public class MyServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { this.doPost(req, resp); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { resp.getWriter().write("hello MyServlet"); } }文件1中,使用@Component注解將MyServlet類作為組件注入Spring容器。MyServlet類繼承自HttpServlet,通過HttpServletResponse對象向頁面輸出“hello MyServlet”。
(2)創(chuàng)建Servlet組件配置類。在項目com.itheima.config包下創(chuàng)建一個Servlet組件配置類ServletConfig,用來對Servlet相關(guān)組件進行注冊,內(nèi)容如文件2所示。
文件2 ServletConfig.java
import com.itheima.servletComponent.MyServlet; import org.springframework.boot.web.servlet.ServletRegistrationBean; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; /** * 嵌入式Servlet容器三大組件配置 */ @Configuration public class ServletConfig { // 注冊Servlet組件 @Bean public ServletRegistrationBean getServlet(MyServlet myServlet){ ServletRegistrationBean registrationBean = new ServletRegistrationBean(myServlet,"/myServlet"); return registrationBean; } }
文件2中,使用@Configuration注解定義了一個Servlet組件配置類ServletConfig,并添加了一個getServlet(MyServlet myServlet)方法,通過組件注冊的方式注冊自定義的MyServlet組件。在注冊自定義的MyServlet組件時,指定了匹配路徑為“/myServlet”,并使用@Bean注解將重新組裝的ServletRegistrationBean類對象作為Bean組件返回。
啟動項目進行測試。項目啟動成功后,在瀏覽器上訪問“http://localhost:8080/myServlet”,效果如圖1所示。
圖1 自定義Servlet組件訪問效果
從圖1中可以看出,瀏覽器能夠訪問myServlet并正常顯示數(shù)據(jù),說明Spring Boot成功整合了Servlet組件。
1. 使用組件注冊方式整合Filter
(1) 創(chuàng)建自定義Filter類。在com.itheima.servletComponent包下創(chuàng)建一個類MyFilter,內(nèi)容如文件3所示。
文件3 MyFilter.java
import org.springframework.stereotype.Component; import javax.servlet.*; import java.io.IOException; /** * 自定義Filter類 */ @Component public class MyFilter implements Filter { @Override public void init(FilterConfig filterConfig) throws ServletException { } @Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { System.out.println("hello MyFilter"); filterChain.doFilter(servletRequest,servletResponse); } @Override public void destroy() { } }
文件3中,使用@Component注解將當(dāng)前MyFilter類作為組件注入到Spring容器中。MyFilter類實現(xiàn)Filter接口,并重寫了init()、doFilter()和destroy()方法,在doFilter()方法中向控制臺打印了“hello MyFilter”字符串。
(1) 向Servlet組件配置類注冊自定義Filter類。打開之前創(chuàng)建的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注解將當(dāng)前組裝好的FilterRegistrationBean對象作為Bean組件返回。
完成Filter的自定義配置后啟動項目,項目啟動成功后,在瀏覽器上訪問“http://localhost:8080/myFilter”查看控制臺打印效果(由于沒有編寫對應(yīng)路徑的請求處理方法,所以瀏覽器會出現(xiàn)404錯誤頁面,這里重點關(guān)注控制臺即可),具體如圖2所示。
圖2 自定義Filter組件訪問效果
在圖2中,瀏覽器訪問“http://localhost:8080/myFilter”時控制臺打印出了自定義Filter中定義的輸出語句“hello MyFilter”,這也就說明Spring Boot整合自定義Filter組件成功。
1. 使用組件注冊方式整合Listener
(1)創(chuàng)建自定義Listener類。在com.itheima.servletComponent包下創(chuàng)建一個類MyListener,內(nèi)容如文件4所示。
文件4 MyListener.java
import org.springframework.stereotype.Component; import javax.servlet.ServletContextEvent; import javax.servlet.ServletContextListener; /** * 自定義Listener類 */ @Component public class MyListener implements ServletContextListener { @Override public void contextInitialized(ServletContextEvent servletContextEvent) { System.out.println("contextInitialized ..."); } @Override public void contextDestroyed(ServletContextEvent servletContextEvent) { System.out.println("contextDestroyed ..."); } }
文件4中,使用@Component注解將MyListener類作為組件注冊到Spring容器中。Listener類實現(xiàn)了ServletContextListener接口,并重寫了contextInitialized()和contextDestroyed()方法。
需要說明的是,Servlet容器提供了很多Listener接口,例如ServletRequestListener、HttpSessionListener、ServletContextListener等,我們在自定義Listener類時要根據(jù)自身需求選擇實現(xiàn)這些接口,這里為了方便演示,直接實現(xiàn)了ServletContextListener接口。
(2)向Servlet組件配置類注冊自定義Listener類。打開之前創(chuàng)建的Servlet組件配置類ServletConfig,將該自定義Listener類使用組件注冊方式進行注冊,示例代碼如下。
// 注冊Listener組件 @Bean public ServletListenerRegistrationBean getServletListener(MyListener myListener){ ServletListenerRegistrationBean registrationBean = new ServletListenerRegistrationBean(myListener); return registrationBean; }
上述代碼中,使用組件注冊方式注冊了一個自定義的MyListener類,在getServletListener()方法中,使用了@Bean注解將當(dāng)前組裝好的FilterRegistrationBean對象作為Bean組件返回。
完成自定義Listener組件注冊后啟動項目,項目啟動成功后查看控制臺打印效果,效果如圖3所示。
圖3 自定義Listener組件初始化效果
程序啟動成功后,控制臺會打印出自定義Listener組件中定義的輸出語句“contextInitialized ...”。單擊圖中的【Exit】按鈕關(guān)閉當(dāng)前項目(注意,如果直接單擊紅色按鈕會強制關(guān)閉程序,瀏覽器就無法打印關(guān)閉監(jiān)聽信息),再次查看控制臺打印效果,效果如圖4所示。
圖4 自定義Listener組件關(guān)閉效果
程序成功關(guān)閉后,控制臺打印出了自定義Listener組件中定義的輸出語句“contextDestroyed ...”。通過效果演示,說明了Spring Boot整合自定義Listener組件成功。
細心的讀者可能發(fā)現(xiàn),將自定義的Servlet組件配置類ServletConfig全部注釋并重啟項目后,自定義的Servlet、Filter、Listener組件仍然生效。出現(xiàn)這種情況的主要原因是:嵌入式Servlet容器對Servlet、Filter、Listener組件進行了自動化識別和配置,而自定義的Servlet、Filter、Listener都繼承/實現(xiàn)了對應(yīng)的類/接口,同時自定義的Servlet、Filter、Listener組件都使用了@Component注解,這些組件會被自動掃描為Spring組件。
使用ServletRegistrationBean、FilterRegistrationBean、ServletListenerRegistrationBean組件組裝配置的根本目的是對一些請求路徑和參數(shù)進行初始化設(shè)置和組裝。假設(shè)沒有組件注冊類,那么自定義Servlet雖然生效,但無法確定生效哪個訪問路徑。自定義的Filter會對所有的請求都進行過濾,不會出現(xiàn)選擇性過濾的情況。而自定義的Listener則沒有太大影響,因為定制該組件基本不需要設(shè)置什么參數(shù)。
Spring Boot框架和傳統(tǒng)Spring框架相比有哪些優(yōu)勢?
Spring AOP實現(xiàn)原理和常見代理的區(qū)別