Servlet詳解(與SpringMVC的聯繫)

Servlet的發展過程:

最先的服務器處理程序是CGI,其存在着每次須要對請求進行處理時新建一個CGI對象,因此在速度和內存方面都不是很讓人滿意;隨着JAVA語言的興起,其跨平臺的特性,使得Servlet逐漸流行起來,而且Servlet是可複用的,因此Servlet逐漸取代CGI。html

Servlet是如何處理d對應的HTTP請求的呢?

  1. 客戶端發起一個HTTP請求到服務器端;
  2. HTTP服務器收到HTTP請求,而後將請求轉給Web容器進行處理;
  3. Web容器對HTTP請求內容進行解析,並將信息存儲到HttpServletRequest中,並生成HttpResponse(用於存儲要返回給客戶端的信息),HttpSession(用於管理會話)等對象;
  4. Web容器根據請求的URL決定要轉發給哪個具體的Servlet程序進行處理;
  5. 先由HttpServlet的service方法分析HTTP請求是Get,Post,Put,Delete等方法,而後決定調用選擇的Servlet對應於每種請求對象的處理方法;
  6. Servlet處理完成後,將要返回的信息存儲到HttpServletResponse對象種並返回給Web容器進行解析轉換爲HTTP響應並傳回客戶端。

Web容器是如何找到對應於具體URL的Servlet處理程序的呢?

那首先看Servlet的建立過程:

  1. 在Servlet3.0及之後開始支持經過@WebServelt標註給Web容器提供此Servlet對應的信息,如urlPatterns,name(沒有定義時,默認值是Servlet的類名), loadOnStartup(用於表示該Servlet是預加載的,而不是等到須要用到再加載)等;使用web.xml配置同理;
  2. 用戶編寫的Servlet繼承自HttpServlet,而後覆蓋HttpServlet的doGet(),doPost()等該Servlet要覆蓋的方法完成建立;
  3. 而後Web容器即可以讀取這些註解提供的信息用於找到對應於具體URL的Servlet並進行加載用於處理。

如何經過HttpServlet的service方法進行HTTP方法的篩選呢?

用戶編寫的Servlet繼承自HttpServlet,繼承圖以下:java

HttpServlet的內部字段以下:

  1. 首先final字符串常量定義了8種HTTP方法以及是否被修改的標識;
  2. 而後提供了對8種HTTP方法對應處理程序的默認實現,這些若是要用到會被覆蓋;
  3. 因此着重看service方法,能夠看到其輸入參數爲ServletRequest, ServletResponse,而沒有Http的標識,這是由於在一開始設計Servlet時其面向的不止是處理HTTP請求,因此請求/相應對象的基本行爲規範是在ServletRequest(包是javax.servlet),與HTTP相關的行爲則由其子接口HttpServletRequest(包是javax.servlet,httpd)定義,因此在HttpServlet中要對該對象進行類型的強轉;
  4. 在service方法中經過調用HttpServletRequest.getMethod()方法用於獲得HTTP方法,並經過if語句進行相應處理方法的跳轉。

如何經過HttpServletResponse對象將處理完的信息傳回客戶端呢?

經過向Response對象中寫入HTML文檔信息進行信息傳輸。

Servlet是可複用的:

瞭解完Web容器對HTTP消息的處理流程後,以前提到Servlet是可複用的,那是否意味着是線程共享的,那是否會產生線程不安全呢?web

理清這個問題咱們首先要看Web容器時如何加載Servlet的:

  1. 首先要知道的一點是Web容器是一段Java程序,運行在JVM之上,是JVM的一個進程,能夠想一想是否是經過localhost:8080端口訪問的Tomcat容器呢?
  2. 而後與傳統的Java容器不一樣的是,Web容器不只持有對象,還負責對象的生命週期與相關服務的鏈接。
  3. Web容器會爲每個請求加載對應的Servlet實例(若是尚未加載過),並分配一個線程,因此可能存在多個線程共享一個Servlet實例的問題,能夠用ThreadLocal解決,或者將對URL請求的處理與對數據業務邏輯的處理分隔開,即便用MVC框架,而後在數據業務邏輯中使用鎖等機制保證數據的安全性。

使用Servlet實現MVC框架:

  1. 首先實現Model(即一個普通的POJO),而後提供get,set機制;
  2. Controller:一個Servlet
@WebServlet("/HelloController")
public class HelloController extends HttpServlet {
	private static final long serialVersionUID = 1L;
	private HelloModel model = new HelloModel();
     
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		// TODO Auto-generated method stub
		Cookie[] cookies = request.getCookies();
		if(cookies != null) {
			for(Cookie cookie : cookies) {
				String cookieName = cookie.getName();
				String cookieValue = cookie.getValue();
				request.setAttribute("name", cookieName);
				request.setAttribute("value", cookieValue);
			}
		}
		else {
			Cookie cookie = new Cookie("user", "cjc");
			cookie.setMaxAge(7 * 24 * 60 *60);
			response.addCookie(cookie);
		}
		String name = request.getParameter("user");
		String message = model.doHello(name);
		request.setAttribute("message", message);

		request.getRequestDispatcher("HelloServlet").forward(request, response);
	}
}
複製代碼

與SpringMVC一致,Controller處理完後須要返回model給View進行渲染,此處使用的是將model數據放入HttpServletRequest對象的屬性中,而後經過RequestDispatcher對象將該請求(forward)轉給HelloServlet進行處理,HelloServlet便是咱們的View; 3. View:一個Servlet,負責完善HttpServletResponse對象並返回給客戶端;安全

@WebServlet("/HelloServlet")
public class HelloServlet extends HttpServlet {
	private static final long serialVersionUID = 1L;

	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		// TODO Auto-generated method stub
		String user = request.getParameter("user");
		String message = (String) request.getAttribute("message");
		String cookieName = (String)request.getAttribute("name");
		String cookieValue = (String)request.getAttribute("value");
		
		response.setContentType("text/html;charset=UTF-8");
		PrintWriter out = response.getWriter();
		out.println("<html>");
		out.println("<head>");
		out.println("<title>Hello Servlet</title>");
		out.println("</head>");
		out.println("<body>");
		out.println("<h1> Hello!" + user + "!</h1>");
		out.println(message);
		out.println("<h1> cookieName" + cookieName + cookieValue + "!</h1>");
		out.println("</body>");
		out.println("</html>");
		
		out.close();
	}

}

複製代碼

至此,咱們經過Servlet實現了一個MVC框架,將處理URL的邏輯,業務邏輯和頁面渲染邏輯分離開來,本來這些是經過一個Servlet完成的,這樣可使系統解耦合,架構更加清晰,更容易維護。bash

相關文章
相關標籤/搜索