Shiro源碼分析之ShiroFilterFactoryBean

1、Spring 的DelegatingFilterProxy如何發現 Shiro 的ShiroFilterFactoryBean

簡單的回顧一下,web.xml配置中的Spring DelegatingFilterProxy 的這個Filter是如何找到WebApplicationcontext 配置(Spring.xml配置文件)中的ShiroFilterFactoryBean。web

web.xml配置:spring

<filter>
        <filter-name>securityFilter</filter-name>
        <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
        <init-param>
            <param-name>targetFilterLifecycle</param-name>
            <param-value>true</param-value>
        </init-param>
</filter>

其實際是經過上面web.xml文件中的<filter-name>securityFilter</filter-name>,securityFilter去找到spring-context.xml配置文件中類型爲Filter,id爲securityFilter的Bean。apache

spring-context.xml配置文件:app

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
	xsi:schemaLocation="
		http://www.springframework.org/schema/beans
		http://www.springframework.org/schema/beans/spring-beans-4.0.xsd">
    <!-- 此處省略部分配置-->
	<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
		<!-- 此處省略部分配置-->
		<property name="securityManager" ref="securityManager" />
		<property name="unauthorizedUrl" value="/" />
		<property name="filters">
			<map>
				<entry key="formAuthc" value-ref="formAuthc" />
			</map>
		</property>
		<property name="filterChainDefinitions">
			<value>
				/static/** = anon
				/login = formAuthc
				/logout = logout
			</value>
		</property>
	</bean>
</beans>

詳解的源碼分析可見http://my.oschina.net/u/1421030/blog/729706函數

2、Shiro 的ShiroFilterFactoryBean源碼分析

前一節說到Spring的DelegatingFilterProxy是經過在Spring的配置文件中找到類型爲Filter且id與web.xml文件其filter-name一致的Bean來發現ShiroFilterFactoryBean的。 但咱們會發現ShiroFilterFactoryBean好像沒有實現Filter接口,是否是有什麼問題呢??源碼分析

ShiroFilterFactoryBean 聲明代碼:this

public class ShiroFilterFactoryBean implements FactoryBean, BeanPostProcessor...

其實ShiroFilterFactoryBean 實現了FactoryBean接口正式在這裏有咱們想要的。 ApplicationContext的對待FactoryBean類型的Bean,經過配置文件的中Bean的id獲得的實際上是FactoryBean#getObject方法對應類型的Bean詳細可見http://my.oschina.net/u/1421030/blog/729908。 如今來看看ShiroFilterFactoryBean 的getObject方法的具體實現吧。url

ShiroFilterFactoryBean #getObject代碼:.net

public Object getObject() throws Exception {
        if (instance == null) {
            instance = createInstance();
        }
        return instance;
    }

再看看debug

ShiroFilterFactoryBean #createInstance代碼:

protected AbstractShiroFilter createInstance() throws Exception {
        logdebug("Creating Shiro Filter instance.");
        SecurityManager securityManager = getSecurityManager();
        //省略部分代碼
        //建立FilterChain管理器,會將Shiro默認的Filter加入進來,同時將配置文件中的Filter加進來
        FilterChainManager manager = createFilterChainManager();
        PathMatchingFilterChainResolver chainResolver = new PathMatchingFilterChainResolver();
        chainResolver.setFilterChainManager(manager);
        return new SpringShiroFilter((WebSecurityManager) securityManager, chainResolver);
    }

能夠看到createInstance方法返回的是一個AbstractShiroFilter 類對象,而該類的父類實際實現了Filter接口。 再來看看createInstance方法中最重要的createFilterChainManager

ShiroFilterFactoryBean #createFilterChainManager代碼:

protected FilterChainManager createFilterChainManager() {
        /*建立默認的FilterChainManager,建立時會將anon, authc, authcBasic等Filter加入*/
        DefaultFilterChainManager manager = new DefaultFilterChainManager();
        Map<String, Filter> defaultFilters = manager.getFilters();
        //apply global settings if necessary:
        for (Filter filter : defaultFilters.values()) {
            applyGlobalPropertiesIfNecessary(filter);
        }
       //獲得Spring配置文件中設置給ShiroFilterFactoryBean 的Filter
        Map<String, Filter> filters = getFilters();
        /*省略部分代碼,此處將Spring設置給ShiroFilterFactoryBean 的Filter
         加入DefaultFilterChainManager 
        */
        /*獲得配置文件中ShiroFilterFactoryBean 對應的filterChainDefinitions屬性設置的鍵值對
         最終能根據vaule找到其對應的其實類Filter的全名與對應的FilterConfig信息
        */
        Map<String, String> chains = getFilterChainDefinitionMap();
        if (!CollectionUtils.isEmpty(chains)) {
            for (Map.Entry<String, String> entry : chains.entrySet()) {
                String url = entry.getKey();
                String chainDefinition = entry.getValue();
                manager.createChain(url, chainDefinition);
            }
        }
        return manager;
    }

先看看 DefaultFilterChainManager manager = new DefaultFilterChainManager()

DefaultFilterChainManager構造函數代碼

public DefaultFilterChainManager() {
        this.filters = new LinkedHashMap<String, Filter>();
        this.filterChains = new LinkedHashMap<String, NamedFilterList>();
       //加入Shiro中默認的Filter
       addDefaultFilters(false);
    }

DefaultFilterChainManager#addDefaultFilters代碼

protected void addDefaultFilters(boolean init) {
        for (DefaultFilter defaultFilter : DefaultFilter.values()) {
            addFilter(defaultFilter.name(), defaultFilter.newInstance(), init, false);
        }
    }

DefaultFilter代碼

public enum DefaultFilter {
    anon(AnonymousFilter.class),
    authc(FormAuthenticationFilter.class),
    authcBasic(BasicHttpAuthenticationFilter.class),
    logout(LogoutFilter.class),
    //省略部分代碼
}

到這裏終於看到了爲何咱們可在spring-context.xml中的ShiroFilterFactoryBean定義中使用anon, authc,authcBasic等去設置filterChainDefinitions啦。 spring-context.xml配置文件:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
	xsi:schemaLocation="
		http://www.springframework.org/schema/beans
		http://www.springframework.org/schema/beans/spring-beans-4.0.xsd">
    <!-- 此處省略部分配置-->
	<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
		<!-- 此處省略部分配置-->
		<property name="securityManager" ref="securityManager" />
		<property name="unauthorizedUrl" value="/" />
		<property name="filters">
			<map>
				<entry key="formAuthc" value-ref="formAuthc" />
			</map>
		</property>
		<property name="filterChainDefinitions">
			<value>
				/static/** = anon
				/login = formAuthc
				/logout = logout
			</value>
		</property>
	</bean>
</beans>

下面一些過程後面的文章分析。

相關文章
相關標籤/搜索