天天看點

詳解Servlet、Tomcat和Spring 之間的關系

作者:文渡

0.基礎知識

在idea中打開servlet的源碼:

詳解Servlet、Tomcat和Spring 之間的關系

可以看見servlet就是一個接口;接口就是規定了一些規範,使得一些具有某些共性的類都能實作這個接口,進而都遵循某些規範。

有的人往往以為就是servlet直接處理用戶端的http請求,其實并不是這樣,servlet并不會去監聽8080端口;直接與用戶端打交道是“容器”,比如常用的tomcat。

用戶端的請求直接打到tomcat,它監聽端口,請求過來後,根據url等資訊,确定要将請求交給哪個servlet去處理,然後調用那個servlet的service方法,service方法傳回一個response對象,tomcat再把這個response傳回給用戶端。

詳解Servlet、Tomcat和Spring 之間的關系

1. Servlet的生命周期

從建立到毀滅:

  1. 調用 init() 方法初始化
  2. 調用 service() 方法來處理用戶端的請求
  3. 調用 destroy() 方法釋放資源,标記自身為可回收
  4. 被垃圾回收器回收

由上面可以看見,servlet的init方法和destroy方法,一般容器調用這兩個方法之間的過程,就叫做servlet的生命周期。

調用的整個過程就如上圖所示。

當請求來容器第一次調用某個servlet時,需要先初始化init(),

但當某個請求再次打到給servlet時,容器會起多個線程同時通路一個servlet的service()方法。

詳解Servlet、Tomcat和Spring 之間的關系

由此可以看出,多個客戶通路同一service()方法,會涉及線程安全的問題。

如果service()方法沒有通路Servlet的成員變量也沒有通路全局的資源比如靜态變量、檔案、資料庫連接配接等,而是隻使用了目前線程自己的資源,比如非指向全局資源的臨時變量、request和response對象等。該方法本身就是線程安全的,不必進行任何的同步控制。

如果service()方法通路了Servlet的成員變量,但是對該變量的操作是隻讀操作,該方法本身就是線程安全的,不必進行任何的同步控制。

如果service()方法通路了Servlet的成員變量,并且對該變量的操作既有讀又有寫,通常需要加上同步控制語句。

如果service()方法通路了全局的靜态變量,如果同一時刻系統中也可能有其它線程通路該靜态變量,如果既有讀也有寫的操作,通常需要加上同步控制語句。

如果service()方法通路了全局的資源,比如檔案、資料庫連接配接等,通常需要加上同步控制語句。

面試問題:Servlet如何同時處理多個請求通路?

**單執行個體多線程: **主要是請求來時,會由線程排程者從線程池李取出來一個線程,來作為響應線程。這個線程可能是已經執行個體化的,也可能是新建立的。

Servlet容器預設是采用單執行個體多線程的方式處理多個請求的:

1.當web伺服器啟動的時候(或用戶端發送請求到伺服器時),Servlet就被加載并執行個體化(隻存在一個Servlet執行個體);

2.容器初始化化Servlet主要就是讀取配置檔案(例如tomcat,可以通過servlet.xml的設定線程池中線程數目,初始化線程池通過web.xml,初始化每個參數值等等。

3.當請求到達時,Servlet容器通過排程線程(Dispatchaer Thread) 排程它管理下線程池中等待執行的線程(Worker Thread)給請求者;

4.線程執行Servlet的service方法;

5.請求結束,放回線程池,等待被調用;

(注意:避免使用執行個體變量(成員變量),因為如果存在成員變量,可能發生多線程同時通路該資源時,都來操作它,照成資料的不一緻,是以産生線程安全問題)

從上面可以看出:

第一:Servlet單執行個體,減少了産生servlet的開銷;

第二:通過線程池來響應多個請求,提高了請求的響應時間;

第三:Servlet容器并不關心到達的Servlet請求通路的是否是同一個Servlet還是另一個Servlet,直接配置設定給它一個新的線程;如果是同一個Servlet的多個請求,那麼Servlet的service方法将在多線程中并發的執行;

第四:每一個請求由ServletRequest對象來接受請求,由ServletResponse對象來響應該請求;

** 2. Spring **

任何Spring Web的entry point,都是servlet。

大名頂頂的spring架構已經風靡多時,一個事物的出現和流行都是會有原因的,那麼為什麼spring 架構會出現呢?原因就是為了簡化java開發。

spring的核心就是通過依賴注入、面向切面程式設計aop、和模版技術,解耦業務與系統服務,消除重複代碼。借助aop,可以将遍布應用的關注點(如事物和安全)從它們的應用對象中解耦出來。

** Spring 中的Bean**

  1. POJO和JavaBean的差別 :

"Plain Ordinary Java Object",簡單普通的java對象。主要用來指代那些沒有遵循特定的java對象模型,約定或者架構的對象。

POJO的内在含義是指那些:

有一些private的參數作為對象的屬性,然後針對每一個參數定義get和set方法通路的接口。

沒有從任何類繼承、也沒有實作任何接口,更沒有被其它架構侵入的java對象。

JavaBean 是一種JAVA語言寫成的可重用元件。JavaBean符合一定規範編寫的Java類,不是一種技術,而是一種規範。大家針對這種規範,總結了很多開發技巧、工具函數。符合這種規範的類,可以被其它的程式員或者架構使用。它的方法命名,構造及行為必須符合特定的約定:

  1. 所有屬性為private。
  2. 這個類必須有一個公共的預設構造函數。即是提供無參數的構造器。
  3. 這個類的屬性使用getter和setter來通路,其他方法遵從标準命名規範。
  4. 這個類應是可序列化的。實作serializable接口。

因為這些要求主要是靠約定而不是靠實作接口,是以許多開發者把JavaBean看作遵從特定命名約定的POJO。

spring中,應用對西那個生存于spring容器中,spring 容器建立對象,裝配它們,管理它們的整個生命周期。spring容器通過依賴注入,管理構成應用的元件,它會建立互相協作的元件之間的關聯。

  1. Bean的生命周期

Spring MVC

詳解Servlet、Tomcat和Spring 之間的關系

Spring MVC的運作流程:

詳解Servlet、Tomcat和Spring 之間的關系
詳解Servlet、Tomcat和Spring 之間的關系