Shiro源码学习(一)Filter的创建

一、从web.xml到Spring容器

我们在使用spring配置shiro时,有两处需要配置Filter相关的地方:

    
    
        shiroFilter
        org.springframework.web.filter.DelegatingFilterProxy
    
    
        shiroFilter
        /*
     
    
    
        
        
        
        
        
        
        
        
        
        
            
                
                    
                    
                    
                
            
        
        
        
            
                
                /common/**=anon
                /search/**=anon
                /static/superAdmin/**=roles[superadmin]
                /static/admin/**=roles[admin]
                /static/** = anon
            
        

    

其实真正发挥拦截器作用的只有Spring中配置的ShiroFilterFactoryBean,而web.xml中配置的拦截器DelegatingFilterProxy功能相当于是为Spring中的Filter做了一层包装, DelegatingFilterProxy相关的源码如下:

	@Override
	protected void initFilterBean() throws ServletException {
		synchronized (this.delegateMonitor) {
			if (this.delegate == null) {
				// If no target bean name specified, use filter name.
				if (this.targetBeanName == null) {
					//web.xml中配置的FilterName属性,当然也可以直接在web.xml中指定targetBeanName属性
					this.targetBeanName = getFilterName();
				}
				// Fetch Spring root application context and initialize the delegate early,
				// if possible. If the root application context will be started after this
				// filter proxy, we'll have to resort to lazy initialization.
				WebApplicationContext wac = findWebApplicationContext();//获取Spring容器的上下文对象(该方法调用由Spring提供的静态方法获取ApplicationContext容器对象)
				if (wac != null) {
					this.delegate = initDelegate(wac);//获取Spring配置文件中配置的拦截器,并作为其代理对象
				}
			}
		}
	}
	protected Filter initDelegate(WebApplicationContext wac) throws ServletException {
		//获取Spring容器中beanName=targetBeanName,类型为Filter的bean
		Filter delegate = wac.getBean(getTargetBeanName(), Filter.class);
		if (isTargetFilterLifecycle()) {
			delegate.init(getFilterConfig());
		}
		return delegate;
	}

该方法是在Filter的初始化阶段调用,功能是对delegate属性赋初值:在Spring容器中获取到bean名和filter-name属性值相同的bean,delegate声明如下:

private volatile Filter delegate;

可以看到,该属性也是一个Filter,然后看下DelegatingFilterProxy的拦截器doFilter实现:

	public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain)
			throws ServletException, IOException {

		// Lazily initialize the delegate if necessary.
		//如果代理的Filter还没加载,就按上面的流程加载一次,略。

		// Let the delegate perform the actual doFilter operation.
		//调用代理对象方法,完成拦截
		invokeDelegate(delegateToUse, request, response, filterChain);
	}
invokeDelegate实现如下:
	protected void invokeDelegate(
			Filter delegate, ServletRequest request, ServletResponse response, FilterChain filterChain)
			throws ServletException, IOException {

		delegate.doFilter(request, response, filterChain);//调用代理对象的Filter完成拦截
	}

二、Filter的真实实现

第一步中我们看到了真正执行拦截的Bean其实是在Spring中配置的ShiroFilterFactoryBean(但是从名字可以看出来,它其实也不是最后执行拦截的,只是一个FactoryBean,用来生产我们需要的拦截器实例),ShiroFilterFactoryBean的相关结构如下:

Shiro源码学习(一)Filter的创建_第1张图片

可以看到,ShiroFilterFactoryBean继承了FactoryBean, BeanPostProcessor。这两个接口是Spring中用作拓展的接口,关于FactoryBean的实现:

FactoryBean接口的主要功能就是在getObject方法中返回一个对象,并把这个对象加入到Spring容器中,这样就可以被Spring容器中的其他Bean访问到,同时也可以访问其他的Bean

    public Object getObject() throws Exception {
        if (instance == null) {
            instance = createInstance();//创建Bean
        }
        return instance;
    }
	//返回值是一个Filter,作为我们需要的拦截器
	protected AbstractShiroFilter createInstance() throws Exception {

        log.debug("Creating Shiro Filter instance.");

        SecurityManager securityManager = getSecurityManager();//我们在Spring配置文件中配置的SecurityManager
        if (securityManager == null) {
            String msg = "SecurityManager property must be set.";
            throw new BeanInitializationException(msg);
        }

        if (!(securityManager instanceof WebSecurityManager)) {	//保证是Web环境下的SecurityManager
            String msg = "The security manager does not implement the WebSecurityManager interface.";
            throw new BeanInitializationException(msg);
        }

        FilterChainManager manager = createFilterChainManager();//创建对我们配置的拦截信息进行管理的管理器

        //Expose the constructed FilterChainManager by first wrapping it in a
        // FilterChainResolver implementation. The AbstractShiroFilter implementations
        // do not know about FilterChainManagers - only resolvers:
        PathMatchingFilterChainResolver chainResolver = new PathMatchingFilterChainResolver();//负责匹配Url后调用符合的Filter
        chainResolver.setFilterChainManager(manager);

        //Now create a concrete ShiroFilter instance and apply the acquired SecurityManager and built
        //FilterChainResolver.  It doesn't matter that the instance is an anonymous inner class
        //here - we're just using it because it is a concrete AbstractShiroFilter instance that accepts
        //injection of the SecurityManager and FilterChainResolver:
        return new SpringShiroFilter((WebSecurityManager) securityManager, chainResolver);//负责执行拦截的Filter
    }
上面代码中有个很重要的属性就是
FilterChainManager

从名字可以明白,这个对象的作用就是管理拦截器链,下面是创建它的源码:

    protected FilterChainManager createFilterChainManager() {

        DefaultFilterChainManager manager = new DefaultFilterChainManager();//创建,并加入了Shiro默认的几个拦截器
        Map defaultFilters = manager.getFilters();
        //添加一些属性
        for (Filter filter : defaultFilters.values()) {
            applyGlobalPropertiesIfNecessary(filter);
        }

        //对我们自己配置的Filter进行处理:添加到Filter列表中,并设置一些属性
        Map filters = getFilters();
        if (!CollectionUtils.isEmpty(filters)) {
            for (Map.Entry entry : filters.entrySet()) {
                String name = entry.getKey();
                Filter filter = entry.getValue();
                applyGlobalPropertiesIfNecessary(filter);
                if (filter instanceof Nameable) {
                    ((Nameable) filter).setName(name);
                }
                //'init' argument is false, since Spring-configured filters should be initialized
                //in Spring (i.e. 'init-method=blah') or implement InitializingBean:
                manager.addFilter(name, filter, false);
            }
        }

        //build up the chains:
        Map chains = getFilterChainDefinitionMap();
        if (!CollectionUtils.isEmpty(chains)) {
            for (Map.Entry entry : chains.entrySet()) {
                String url = entry.getKey();
                String chainDefinition = entry.getValue();
                manager.createChain(url, chainDefinition);
            }
        }

        return manager;
    }

创建FilterChainManager实例:

Shiro源码学习(一)Filter的创建_第2张图片

上面代码可以看到,Shiro在初始阶段就已经添加了一些Filter类:

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

DefaultFilter是一个枚举类型,它的定义如下:

Shiro源码学习(一)Filter的创建_第3张图片

如下图中,我们在Shiro配置的拦截器链等号后面对应的处理Filter就是这上面的:

Shiro源码学习(一)Filter的创建_第4张图片


对Filter需要的属性进行填充

	//如果需要,就为Filter添加我们配置文件中配置的successUrl、loginUrl、unauthorizedUrl(都是直接通过set设置)
    private void applyGlobalPropertiesIfNecessary(Filter filter) {
        applyLoginUrlIfNecessary(filter);
        applySuccessUrlIfNecessary(filter);
        applyUnauthorizedUrlIfNecessary(filter);
    }

对自定义的Filter进行处理:

        Map filters = getFilters();		//获取我们在配置文件中配置的自定义Filter列表
        if (!CollectionUtils.isEmpty(filters)) {
            for (Map.Entry entry : filters.entrySet()) {
                String name = entry.getKey();
                Filter filter = entry.getValue();
                applyGlobalPropertiesIfNecessary(filter);		//如上文中一样,如果需要就设置相关的全局属性
                if (filter instanceof Nameable) {
                    ((Nameable) filter).setName(name);
                }
                //'init' argument is false, since Spring-configured filters should be initialized
                //in Spring (i.e. 'init-method=blah') or implement InitializingBean:
                manager.addFilter(name, filter, false);		//添加到Filte列表中
            }
        }

自定义的Filter例子如下:

//一个继承自Shiro AdviceFilter的拦截器



Shiro源码学习(一)Filter的创建_第5张图片


创建SpringShiroFilter返回

Shiro源码学习(一)Filter的创建_第6张图片


SpringShiroFilter是一个内部类,定义如下:

Shiro源码学习(一)Filter的创建_第7张图片

SpringShiroFilter的父类AbstractShiroFilter已经基本上实现了需要的功能,而SpringShiroFilter的功能主要就体现在传入的两个参数上:

securityManager:提供realm(密码比对、角色权限获取等)、sessionManager、cacheManager等

PathMatchingFilterChainResolver:实现对Url的比对,并根据结果选择合适的拦截器等

//Filter的创建就已经讲完了,因为ShiroFilterFactoryBean实现FactoryBean的原因,DelegatingFilterProxy获取到的Bean就是上面返回的SpringShiroFilter,并调用他的doFilter方法(这个方法在父类中,通过子类的覆写,最后完成拦截功能的方法是doFilterInternal方法,后面会讲到)






你可能感兴趣的:(源码,shiro,Shiro,源码,Filter,拦截器)