CAS源碼追蹤系列一:Filter的初始化

最近研究了一下SSO(Single Sign On:單點登陸)原理。
因而想借助CAS(基於SSO原理的實現框架)加深一下理解同時參考一下具體代碼實現,所以有了此係列文章。
先從CAS-CLIENT提及。web

假設你已經掌握瞭如何在你的web項目中引入CAS。咱們以AuthenticationFilter爲例,說一說它是如何從初始化的。spring

代碼跟蹤

Spring-web:DelegatingFilterProxy

在web項目中的web.xml文件中咱們一般經過以下方式進行spring和cas的整合:tomcat

<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。那咱們來看一下該類的源碼:app

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。this

上面說到調用Filter本身的初始化方法。對於AuthenticationFilter,由於本身沒有重寫init(FilterConfig),則會調用從其父類AbstractCasFilter繼承來的init(FilterConfig)方法:url

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()
        ...
    }

直觀的圖示(非專業,手動滑稽~):
image

總結

本文從web項目和spring的整合入手,以cas中的AuthenticationFilter爲例(其餘類型的Filter相似)跟蹤代碼分析如何走到他本身的初始化邏輯。後續會有初始化以後對請求的攔截、cas服務端的處理等分析。

碼字整理不易,如何你以爲寫的還能看的話請賞一個贊或者推薦吧,若是寫的不對請直接評論糾正,畢竟我仍是一個在路上的小魯班呢~

歡迎關注個人公衆號,不按期更新學習筆記和視頻文檔學習資料哦~
image

相關文章
相關標籤/搜索