0.基礎知識
在idea中打開servlet的源碼:
可以看見servlet就是一個接口;接口就是規定了一些規范,使得一些具有某些共性的類都能實現這個接口,從而都遵循某些規范。
有的人往往以為就是servlet直接處理客戶端的http請求,其實並不是這樣,servlet並不會去監聽8080端口;直接與客戶端打交道是“容器”,比如常用的tomcat。
客戶端的請求直接打到tomcat,它監聽端口,請求過來后,根據url等信息,確定要將請求交給哪個servlet去處理,然后調用那個servlet的service方法,service方法返回一個response對象,tomcat再把這個response返回給客戶端。
1. Servlet的生命周期
從創建到毀滅:
- 調用
init()
方法初始化 - 調用
service()
方法來處理客戶端的請求 - 調用
destroy()
方法釋放資源,標記自身為可回收 - 被垃圾回收器回收
由上面可以看見,servlet的init方法和destroy方法,一般容器調用這兩個方法之間的過程,就叫做servlet的生命周期。
調用的整個過程就如上圖所示。
當請求來容器第一次調用某個servlet時,需要先初始化init(),
但當某個請求再次打到給servlet時,容器會起多個線程同時訪問一個servlet的service()方法。
由此可以看出,多個客戶訪問同一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類,不是一種技術,而是一種規范。大家針對這種規范,總結了很多開發技巧、工具函數。符合這種規范的類,可以被其它的程序員或者框架使用。它的方法命名,構造及行為必須符合特定的約定:
-
所有屬性為private。
-
這個類必須有一個公共的缺省構造函數。即是提供無參數的構造器。
-
這個類的屬性使用getter和setter來訪問,其他方法遵從標准命名規范。
-
這個類應是可序列化的。實現serializable接口。
因為這些要求主要是靠約定而不是靠實現接口,所以許多開發者把JavaBean看作遵從特定命名約定的POJO。
spring中,應用對西那個生存於spring容器中,spring 容器創建對象,裝配它們,管理它們的整個生命周期。spring容器通過依賴注入,管理構成應用的組件,它會創建相互協作的組件之間的關聯。
2) Bean的生命周期
Spring MVC
Spring MVC的運行流程: