一,當Http服務器接收請求后,如何知道調用哪些java類來處理請求呢?
有些類可能就是用來封裝變量的,有些類才是用來處理請求的。為了識別出那些具有處理請求的類,定義了一個接口,這個接口就叫Servlet接口,如果想要讓業務類具備處理請求的能力,都必須實現這個接口,實現了接口的業務類叫做Servlet。
二,對於特定的請求,Http服務器如何知道由哪個Servlet來處理?Servlet又是由誰來實例化呢
1,於是又有了Servlet容器。Http服務器把請求交給Servlet容器去處理,Servlet容器會將請求轉發到具體的Servlet,如果這個Servlet還沒創建,就加載並實例化這個Servlet,然后調用這個Servlet的接口方法。
Servlet接口其實是Servlet容器和具體業務類之間的接口:
Http服務器不直接調用業務類,而是把請求交給容器來處理,容器通過Servlet接口調用業務類。因此Servlet接口和Servlet容器的出現,使Http服務器和業務類解耦。
Servlet規范:Servlet接口 + Servlet容器。Tomcat按照Servlet規范的要求實現了Servlet容器,同時它也具有Http服務器的功能。(如果我們要實現新的業務功能,只需要實現一個 Servlet,然后把它注冊到Tomcat(Servlet容器)中,剩下的事情由Tomcat幫我們來處理)。
三,Servlet接口
1,Servlet接口定義了五個方法:
public interface Servlet { void init(ServletConfig config) throws ServletException; ServletConfig getServletConfig(); void service(ServletRequest req, ServletResponse res)throws ServletException, IOException; String getServletInfo(); void destroy(); }
1.1,init(ServletConfig config):
和生命周期有關的方法,Servlet容器在加載Servlet類的時候會調用init方法。可能會在init方法里初始化一些資源。比如Springmvc中的DispatcherServlet,在init方法中創建了自己的spring容器。
1.2,ServletConfig getServletConfig():
· ServletConfig就是封裝Servlet的初始化參數。可以在web.xml給Servlet配置參數,然后在程序中通過getServletConfig方法拿到這些參數。
1.3,service(ServletRequest req, ServletResponse res):
業務類在這個方法里實現處理邏輯。ServletRequest用來封裝請求信息,ServletResponse用來封裝響應信息。本質上這兩個類是對通信協議的封裝。
Http協議中的請求和響應就是對應了HttpServletRequest和HttpServletResponse這兩個類。我們可以通過HttpServletRequest來獲取所有請求相關的信息,包括請求路徑,Cookie,Http頭,請求參數等。
1.4,String getServletInfo()
1.5,destroy():
和生命周期有關的方法,Servlet容器在卸載Servlet類的時候會調用destory方法。在destory方法里釋放這些資源。
四,Servlet容器
1,Servlet容器工作流程
當客戶請求某一個資源時,Http服務器會用一個ServletRequest對象把客戶的請求信息封裝起來,然后調用Servlet容器的service方法,Servlet容器拿到請求后,根據請求的URL和Servlet的映射關系,找到相應的Servlet,如果Servlet還沒有被加載,就用反射機制創建這個Servlet,並調用Servlet的init方法來完成初始化,接着調用Servlet的service方法來處理請求,把ServletResponse對象返回給Http服務器,Http服務器會把響應發送給客戶端。
2,Web應用
2.1,Servlet容器負責實例化和調用Servlet,那么Servlet是怎么注冊到Servlet容器的呢?
我們一般以Web應用程序的方式來部署Servlet的。根據Servlet規范,Web應用程序有一定的目錄結構:
| - MyWebApp | - WEB-INF/web.xml -- 配置文件,用來配置 Servlet 等 | - WEB-INF/lib/ -- 存放 Web 應用所需各種 JAR 包 | - WEB-INF/classes/ -- 存放你的應用類,比如 Servlet 類 | - META-INF/ -- 目錄存放工程的一些信息
在這個目錄下分別放置了Servlet的類文件,配置文件,靜態資源文件,Servlet容器通過讀取配置文件,就可以找到並加載Servlet。
2.2,Servlet規范中定義了ServletContext這個接口來對應一個Web應用。
Web應用部署好以后,Servlet容器在啟動時會加載Web應用,並為每個Web應用創建唯一的ServletContext對象。你可以把ServletContext看成是一個全局對象,一個Web應用可能有多個Servlet,這些Servlet可以通過全局的ServletContext來共享數據,這些數據包括Web應用的初始化參數,Web應用目錄下的文件資源等。因為ServletContext持有所有Servlet實例,還可以通過它來實現Servlet請求的轉發。
2.3,擴展機制:Filter和Listener
Filter:過濾器,這個接口允許對請求和響應做一些統一的定制化處理,比如可以根據請求的頻率來限制訪問,根據國家地區的不同來修改響應的內容。
過濾器原理:Web應用部署完以后,Servlet容器需要實例化Filter並把Filter鏈接成一個FilterChain。當請求進來時,獲取第一個Filter並調用doFilter方法,doFilter方法負責調用 FilterChain的下一個Filter。
Listener:監聽器,當Web應用在Servlet容器中運行時,Servlet容器內部會不斷發生各種事件,比如Web應用的啟動和停止,用戶請求到達等。Servlet容器提供了一些默認的監聽器來監聽這些事件,當事件發生時,Servlet容器會負責調用監聽器的方法。自定義監聽器需要把監聽器配置在web.xml中。比如:Spring就實現了自己的監聽器,用來監聽ServletContext的啟動事件,目的是當Servlet容器啟動時,創建並初始化全局的Spring容器。
五,各種容器(Web容器,Servlet容器,Spring容器,SpringMvc容器)
1,Tomcat在啟動時給每個Web應用創建一個全局的上下文環境,這個上下文就是ServletContext,為后面的Spring容器提供宿主環境。
2,Tomcat在啟動過程中觸發容器初始化事件,Spring的ContextLoaderListener會監聽到這個事件,它的contextInitialized方法會被調用,然后Spring會初始化全局的Spring根容器,這個就是Spring的Ioc容器,Ioc容器初始化完畢后,Spring將其存儲到ServletContext中,便於以后獲取。
3,Tomcat啟動時還會掃描Servlet,一個Web應用中的Servlet可以有多個,以SpringMvc中的DispatcherServet為例,這個Servlet實際上是一個標准的前端控制器,用來轉發,匹配,處理每個Servlet請求。
4,Servlet一般會延遲加載,當第一個請求到達時,Tomcat發現DispatcherServet還沒有被實例化,就調用DispatcherServet的init方法,DispatcherServet在初始化的時候會建立自己的容器,叫做SpringMvc容器,用來持有SpringMvc相關的Bean。同時,SpringMvc還會通過ServletContext拿到Spring根容器,並把Spring根容器設置為SpringMvc容器的父容器,Spring容器可以訪問父容器中的Bean,但是父容器不能訪問子容器中的Bean(Spring容器不能訪問SpringMvc容器里的Bean --->Controller里可以訪問Service對象,但是在Service里不可以訪問Controller對象)。
web容器中有servlet容器,spring項目部署后存在spring容器和springmvc容器。其中spring控制service層和dao層的bean對象。springmvc容器控制controller層bean對象。servlet容器控制servlet對象。項目啟動是,首先 servlet初始化,初始化過程中通過web.xml中spring的配置加載spring配置,初始化spring容器和springmvc容器。待容器加載完成。servlet初始化完成,則完成啟動。
HTTP請求到達web容器后,會到達Servlet容器,容器通過分發器分發到具體的spring的Controller層。執行業務操作后返回結果。
---------------------
參考連接:https://blog.csdn.net/zhanglf02/article/details/89791797
Spring MVC 中的 DispatcherServl...
極客時間版權所有: https://time.geekbang.or