CAS源碼追蹤系列一:Filter的初始化
目錄
- 代碼跟蹤
- Spring-web:DelegatingFilterProxy
- CAS:AuthenticationFilter
- 總結
最近研究了一下SSO(Single Sign On:單點登錄)原理。
於是想借助CAS(基於SSO原理的實現框架)加深一下理解同時參考一下具體代碼實現,因此有了此系列文章。
先從CAS-CLIENT說起。
假設你已經掌握了如何在你的web項目中引入CAS。我們以AuthenticationFilter為例,說一說它是如何從初始化的。
代碼跟蹤
Spring-web:DelegatingFilterProxy
在web項目中的web.xml文件中我們通常通過如下方式進行spring和cas的整合:
<bean id="authenticationFilter" class="org.jasig.cas.client.authentication.AuthenticationFilter">
<property name="casServlerLoginUrl">xxx</property>
<property name="serverName">xxx</property>
</bean>
<filter> <filter-name>casAuthenticationFilter</filter-name> <filter-class> org.springframework.web.filter.DelegatingFilterProxy </filter-class> <init-param> <param-name>targetBeanName</param-name> <param-value>authenticationFilter</param-value> </init-param> </filter> <filter-mapping> <filter-name>casAuthenticationFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
可以看到引入了一個名為DelegatingFilterProxy的Filter。那我們來看一下該類的源碼:
public class DelegatingFilterProxy extends GenericFilterBean { private String contextAttribute;//上下文屬性,尋找WebApplicationContext private WebApplicationContext webApplicationContext;//web上下文 private String targetBeanName;//被委托的Filter的名字,如果沒有指定,則使用DelegatingFilterProxy對應的Filter的name,即上面的<filter-name>標簽的內容。 private boolean targetFilterLifecycle;//是否是目標Filter的生命周期,默認為false,即由Spring來管理Filter的生命周期,否則由Servlet來管理。 private Filter delegate;//被委托的過濾器 private final Object delegateMonitor;//監視器 ...
該類是實現了Filter接口並交由spring管理的servlet過濾器的代理類。
因為這個類也是實現了Filter接口,所以在tomcat容器初始化是會執行init(FilterConfig)方法。該方法來自其父類GenericFilterBean,來看代碼:
public final void init(FilterConfig filterConfig) throws ServletException {
...
this.filterConfig = filterConfig;
...
this.initFilterBean();
}
註意到this.initFilterBean(),該方法來自DelegatingFilterProxy,看源碼:
protected void initFilterBean() throws ServletException {
...
WebApplicationContext wac = this.findWebApplicationContext();//獲取應用上下文
if (wac != null) {
this.delegate = this.initDelegate(wac);//初始化委托
...
protected Filter initDelegate(WebApplicationContext wac) throws ServletException {
Filter delegate = (Filter)wac.getBean(this.getTargetBeanName(), Filter.class);//從應用上下文中獲取名為targetBeanName的bean,也就是被委托的Filter
if (this.isTargetFilterLifecycle()) {
delegate.init(this.getFilterConfig());//調用Filter的初始化方法
}
return delegate;
}
CAS:AuthenticationFilter
AuthenticationFilter繼承了AbstractCasFilter。
上面說到調用Filter自己的初始化方法。對於AuthenticationFilter,因為自己沒有重寫init(FilterConfig),則會調用從其父類AbstractCasFilter繼承來的init(FilterConfig)方法:
public final void init(FilterConfig filterConfig) throws ServletException {
if (!this.isIgnoreInitConfiguration()) {
...
this.initInternal(filterConfig);//內部初始化
}
this.init();//自定義初始化邏輯
}
註意:你會發現AuthenticationFilter和其父類都有initInternal(filterConfig)和init()方法,這裏進入的是AuthenticationFilter,所以回去調用AuthenticationFilter中對應的方法:
protected void initInternal(FilterConfig filterConfig) throws ServletException {//將filterConfig設置到WebXmlConfigurationStrategyImpl以及設置一些自己的屬性值
...
super.initInternal(filterConfig);//此時才去調用其父類的initInternal(filterConfig)
...
}
public void init() {
super.init();//此時才去調用其父類的init()
...
}
直觀的圖示(非專業,手動滑稽~):
總結
本文從web項目和spring的整合入手,以cas中的AuthenticationFilter為例(其他類型的Filter類似)跟蹤代碼分析如何走到他自己的初始化邏輯。後續會有初始化之後對請求的攔截、cas服務端的處理等分析。
碼字整理不易,如何你覺得寫的還能看的話請賞一個贊或者推薦吧,如果寫的不對請直接評論糾正,畢竟我還是一個在路上的小魯班呢~
歡迎關註我的公眾號,不定期更新學習筆記和視頻文檔學習資料哦~
CAS源碼追蹤系列一:Filter的初始化