1. 程式人生 > 實用技巧 >Spring容器和Web容器相關知識

Spring容器和Web容器相關知識

Spring容器與Web容器

Spring和SpringMVC容器

容器就是存放物件,管理物件的地方,容器管理Bean的整個生命週期。在一個專案中,容器可能不止有一個,而且容器存在上下級的關係,常見的一種場景是一個專案中引入Spring和SpringMVC框架,這兩個框架其實就是兩個容器,Spring容器管理dao和service層相關的BeanSpringMVC容器管理controller(web)相關的bean,它兩都是容器,都是存放管理bean的地方,只不過管理的域不同。

容器配置不當,可能會導致Bean多次載入,controller方法無法攔截等問題。

例如,spring-mvc.xml檔案配置SpringMVC相關的掃描到controller層

<context:component-scan base-package="cn.wonkey.**.controller"/>

spring-service.xml掃描包載入service

<context:component-scan base-package="cn.wonkey.**.service"/>

Spring容器和SpringMVC容器是父子容器的關係。Spring容器是父容器,SpringMVC容器是子容器,子容器可以訪問父容器中的物件,但是父容器中不可以訪問子容器中的物件,程式設計的具體表現就是controller可以直接訪問service物件,但是在service中確不能訪問controller物件。但就好比繼承的特點那樣,子類可以呼叫父類的任何方法,而父類只能呼叫其本身的方法。

在Spring的具體實現上,子容器和父容器都是通過ServletContext的setAttribute方法放到ServletContext中的。但是,ContextLoaderListener會先於DispatcherServlet建立ApplicationContext,DispatcherServlet在建立ApplicationContext時會先找到由ContextLoaderListener所建立的ApplicationContext,再將後者的ApplicationContext作為引數傳給DispatcherServlet的ApplicationContext的setParent()方法。也就是說,子容器的建立依賴於父容器的建立,父容器先於子容器建立

Web容器

Web容器是管理Servlet,以及監聽器(Listener)和過濾器(Filter)的。比如Tomcat、Undertow、Jetty等,當然他們也被稱為Servlet容器,大多數Servlet容器同時提供了web容器的功能,Tomcat可以看做是一個”HTTP伺服器 + Servlet容器”,也就是說Servlet容器可以獨立執行web應用。Apache僅僅是一個web容器,不包含servlet容器,不能處理servlet請求。web容器管理的Servlet,監聽器和過濾器不在Spring和SpringMVC掌控範圍內。因此,我們無法在這些類中直接使用Spring註解的方式來注入我們需要的物件,是無效的,web容器是無法識別的。

假若專案中有一驗證碼的功能,是由Servlet實現的一個類(KaptchaServlet),如果我們把它交給spring IOC管理,那麼web容器是如何獲得這個Servlet呢?web容器在找這個驗證碼相關的servlet類時,因為不能直接注入,所以要依賴於ContextLoaderListener這一個類,通常我們會在整合SSM時在web.xml中新增ContextLoaderListener監聽器類。通過ContextLoaderListener,Servlet容器就可以和Spring容器和SprngMVC容器進行通訊。

三者的具體關係如下圖:

容器的啟動流程

(1)Tomcat在啟動時給每個web應用建立一個全域性的上下文環境,這個上下文就是ServletContext,並且為後面的Spring容器提供宿主環境

(2)在web.xml中提供有ContextLoaderListener監聽器,在容器啟動時,會觸發容器的初始化事件,Spring的ContextLoaderListener會監聽到這個事件,它的contextInitialized方法會被呼叫,在這個方法中,spring會初始化一個啟動上下文WebApplicationContext,它就是spring的IoC容器。在這個IoC容器初始化完畢後,Spring以WebApplicationContext.ROOTWEBAPPLICATIONCONTEXTATTRIBUTE為屬性Key,將其儲存到ServletContext中,便於獲取。

(3)ContextLoaderListener初始化完畢之後,開始初始化web.xml中配置的servlet,servlet可以有多個。以DispatcherServlet為例,這個Servlet是一個標準的前端控制器,用於轉發、匹配、處理每一個Servlet請求。Servlet採用延遲載入策略,當第一個請求到達時,Tomcat發現DispatcherServlet沒有例項化就會呼叫DispatcherServlet的init方法,它會建立自己的容器,這個 就是SpringMVC容器,用來管理持有Spring MVC相關的Bean。特別地,在建立DispatcherServlet自己的容器時,會利用WebApplicationContext.ROOTWEBAPPLICATIONCONTEXTATTRIBUTE先從ServletContext中獲取之前的根上下文(即WebApplicationContext)作為自己上下文的parent上下文。有了這個parent上下文之後,再初始化自己持有的上下文。SpringMVC的建立是依賴於Spring容器的

參考: