天天看點

spring-session源碼解讀-1

servletcontainerinitializer 也是 servlet 3.0 新增的一個接口,主要用于在容器啟動階段通過程式設計風格注冊filter, servlet以及listener,以取代通過web.xml配置注冊。這樣就利于開發内聚的web應用架構。

例如spring,我們使用它的web功能時,需要在web.xml中依據spring的規範建立一堆配置。這樣就相當于将架構和容器緊耦合了。而在3.x後注冊的功能内聚到spring裡,spring-web就變成一個純粹的即插即用的元件,不用依據應用環境定義一套新的配置。

容器啟動階段依據java spi擷取到所有servletcontainerinitializer的實作類,然後執行ononstartup方法

實作類需要通過java spi聲明自己是servletcontainerinitializer 的provider。

可以通過@handlestypes注解定義希望處理類型,容器會将目前應用中所有這一類型(繼承或者實作)的類放在集合參數1中傳遞進來。如果不定義處理類型,或者應用中不存在相應的實作類,則集合參數1為空。

spring-web通過java spi聲明了springservletcontainerinitializer。參考spring-web.jar下的meta-inf/services

spring-session隻處理webapplicationinitializer類型,全部執行個體化後再依次調用webapplicationinitializer的onstartup接口。

該接口定義了一個onstartup的方法,是以實作類都需要自己實作。spring-session提供了一個抽象的公用基類–org.springframework.session.web.context.abstracthttpsessionapplicationinitializer,由它實作了接口的onstartup方法

這個方法的主要過程:

添加contextloaderlistener,使用過spring-mvc的肯定對這個listener不陌生,這個listener是整個spring-web的核心,由它來自動裝配spring的核心容器applicationcontext。第一步中的applicationcontext作為構造參數傳進了該listener。web容器啟動時會通知該listener,該listener就會啟動applicationcontext的生命周期。并将bean加載完畢。因為這是spring-web邊界内的,是以就不再展開,隻要知道大概做了什麼事情就行了。

通過insertsessionrepositoryfilter注冊了一個filter,從名字知道這個filter叫sessionrepositoryfilter,顧名思義,它肯定是通過一定方式做session持久化的。

這個方法主要是動态裝載了一個delegatingfilterproxy,構造函數的入參是個靜态變量,對應的值是“springsessionrepositoryfilter”。從“delegatingfilterproxy”這個名字就大概能猜到這個filter最終會把請求delegate給具體的filter,看下入參大概就可以猜到應該是委派給“springsessionrepositoryfilter”這個filter,并且這個filter應該是由spring容器管理的,在filter生命周期的某個階段會通過spring的依賴注入進來,并執行相關的攔截請求。

這裡有一點會比較容易疑惑,spring為什麼要通過一個代理類來做委派,直接注冊springsessionrepositoryfilter不是更好。

關于這個問題會在下一章”容器對springsessionrepositoryfilter的依賴管理“裡詳細展開,這裡繼續沿着處理流往下。

這個類繼承自genericfilterbean,genericfilterbean是spring抽象出來的一個filter公用接口。先看下genericfilterbean的init方法:

這裡隻抽出了其中的核心邏輯,最後調用子類的initfilterbean

delegatingfilterproxy覆寫了父類的initfilterbean方法

initfilterbean方法通過spring容器來取得具體的filter bean,而webapplicationcontext對象就是上文提到的annotationconfigwebapplicationcontext對象。contextloaderlistener在spring容器refresh完後會把對應的容器儲存進servletcontext裡,預設的key值為webapplicationcontext.class.getname() + “.root”。這裡擷取spring context的findwebapplicationcontext方法就是從servletcontext裡通過對應的key取得的。

至此delegatingfilterproxy初始化完成,裡面做實際處理的filter最終通過spring的依賴注入初始化并且注入進來。