1. 程式人生 > >熵增學院-Anders-劍走偏鋒,瞭解Spring Boot內部Servlet容器

熵增學院-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

所有ServletFilter或Servlet *Listener例項,只要是Spring bean,都會註冊到內嵌容器中。如果想在配置期間引用application.properties的屬性,這是非常方便的。預設情況下,如果上下文只包含單個Servlet,那它將被對映到/。如果存在多個Servlet beans,那麼bean的名稱將被用作路徑的字首,過濾器將對映到/*

如果基於約定(convention-based)的對映不夠靈活,你可以使用ServletRegistrationBean

FilterRegistrationBeanServletListenerRegistrationBean實現完全的控制。

 

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檢視。

本文相關視訊