熵增學院-Anders-劍走偏鋒,瞭解Spring Boot內部Servlet容器
還記得大明湖畔的servlet嗎?其實Spring Boot支援內嵌的Tomcat, Jetty和Undertow伺服器,多數開發者只需要使用合適的'Starter'來獲取一個完全配置好的例項即可,內嵌伺服器預設監聽8080埠的HTTP請求。
這樣子是不是覺得很簡單,很方便,有種開發nodejs的感覺.....
1. 在SpringBoot中還有Servlets, Filters和listeners嗎?
使用內嵌servlet容器時,你可以通過使用Spring beans或掃描Servlet元件的方式註冊Servlets,Filters及特定Servlet相關的所有listeners(比如HttpSessionListener
將Servlets,Filters和listeners註冊為Spring beans
所有Servlet
,Filter
或Servlet *Listener
例項,只要是Spring bean,都會註冊到內嵌容器中。如果想在配置期間引用application.properties
的屬性,這是非常方便的。預設情況下,如果上下文只包含單個Servlet,那它將被對映到/
。如果存在多個Servlet beans,那麼bean的名稱將被用作路徑的字首,過濾器將對映到/*
。
如果基於約定(convention-based)的對映不夠靈活,你可以使用ServletRegistrationBean
FilterRegistrationBean
,ServletListenerRegistrationBean
實現完全的控制。
1 建立servlet
package com.gala.servlet; import java.io.IOException; import java.io.PrintWriter; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; public class TestServlet extends HttpServlet { private static final long serialVersionUID = -2646554587718007415L; @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { // 設定返回型別為json resp.setContentType("application/json"); // 設定返回字符集 resp.setCharacterEncoding("UTF-8"); // 輸出物件 PrintWriter writer = resp.getWriter(); // 輸出error訊息 writer.write("成功執行doGet方法"); writer.close(); } }
2 使用Bean註冊Servlet(單個Servlet)
package com.gala.servlet.conf; import org.springframework.boot.web.servlet.ServletRegistrationBean; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import com.gala.servlet.TestServlet; @Configuration public class ServletConfiguration { @Bean public ServletRegistrationBean<TestServlet> servletRegistrationBean() { return new ServletRegistrationBean<TestServlet>(new TestServlet(), "/test"); } }
SpringBoot自動裝配Servlet(多個Servlet)
SpringBoot內部提供了註解@ServletComponentScan,這個註解的作用就是自動掃描我們SpringBoot專案內的有關Servlet配置,自動裝配到我們的專案中。
TestServlet需要與ServletConfiguration同目錄或在其子目錄中
修改ServletConfiguration,增加@ServletComponentScan
package com.gala.servlet.conf; import org.springframework.boot.web.servlet.ServletComponentScan; import org.springframework.context.annotation.Configuration; @Configuration @ServletComponentScan public class ServletConfiguration { }
修改TestServlet,增加@WebServlet(urlPatterns = "/test2")
package com.gala.servlet; import java.io.IOException; import java.io.PrintWriter; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @WebServlet(urlPatterns = "/test2") public class TestServlet extends HttpServlet { private static final long serialVersionUID = -2646554587718007415L; @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { // 設定返回型別為json resp.setContentType("application/json"); // 設定返回字符集 resp.setCharacterEncoding("UTF-8"); // 輸出物件 PrintWriter writer = resp.getWriter(); // 輸出error訊息 writer.write("成功執行doGet方法"); writer.close(); } }
2. 在Filters和listeners怎麼使用
內嵌servlet容器不會直接執行Servlet 3.0+的javax.servlet.ServletContainerInitializer介面,或Spring的org.springframework.web.WebApplicationInitializer介面,這樣設計的目的是降低war包內執行的第三方庫破壞Spring Boot應用的風險。
如果需要在Spring Boot應用中執行servlet上下文初始化,你需要註冊一個實現org.springframework.boot.context.embedded.ServletContextInitializer介面的bean。onStartup方法可以獲取ServletContext,如果需要的話可以輕鬆用來適配一個已存在的WebApplicationInitializer。
掃描Servlets, Filters和listeners
當使用一個內嵌容器時,通過@ServletComponentScan可以啟用對註解@WebServlet,@WebFilter和@WebListener類的自動註冊。
注 在獨立的容器(非內嵌)中@ServletComponentScan不起作用,取為代之的是容器內建的discovery機制。
3. 自定義配置servlet容器
常見的Servlet容器配置可以通過Spring Environment進行設定,通常將這些屬性定義到application.properties檔案中。
常見的伺服器配置包括:
網路設定:監聽進入Http請求的埠(server.port),介面繫結地址server.address等。
Session設定:session是否持久化(server.session.persistence),session超時時間(server.session.timeout),session資料存放位置(server.session.store-dir),session-cookie配置(server.session.cookie.*)。
Error管理:錯誤頁面的位置(server.error.path)等。
SSL。
HTTP壓縮
Spring Boot會盡量暴露常用設定,但這並不總是可能的。對於不可能的情況,可以使用專用的名稱空間提供server-specific配置(檢視server.tomcat,server.undertow)。例如,可以根據內嵌servlet容器的特性對access logs進行不同的設定。
注 具體參考ServerProperties。
4. 老生常談的JSP
當使用內嵌servlet容器執行Spring Boot應用時(並打包成一個可執行的存檔archive),容器對JSP的支援有一些限制
Tomcat只支援war的打包方式,不支援可執行jar。
Jetty只支援war的打包方式。
Undertow不支援JSPs。
建立的自定義error.jsp頁面不會覆蓋預設的error handling檢視。