CAS源码追踪系列一:Filter的初始化

最近研究了一下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()
        ...
    }

直观的图示(非专业,手动滑稽~):
image

总结

本文从web项目和spring的整合入手,以cas中的AuthenticationFilter为例(其他类型的Filter类似)跟踪代码分析如何走到他自己的初始化逻辑。后续会有初始化之后对请求的拦截、cas服务端的处理等分析。

码字整理不易,如何你觉得写的还能看的话请赏一个赞或者推荐吧,如果写的不对请直接评论纠正,毕竟我还是一个在路上的小鲁班呢~

欢迎关注我的公众号,不定期更新学习笔记和视频文档学习资料哦~
image

posted @ 2018-10-20 17:37 墨、鱼的blog 阅读(...) 评论(...) 编辑 收藏