zoukankan      html  css  js  c++  java
  • Shiro切入Spring的方式

    在springMVC中要使用shiro,一般都遵循下面的配置:

    applicationContext-shiro.xml

    <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean"> 
        <property name="securityManager" ref="securityManager" />  
    .....
    
    </bean>

    web.xml

    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>
    
    
    <!-- Spring MVC Servlet -->
    <servlet>
        <servlet-name>springServlet</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath*:/spring/springmvc-common.xml</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>springServlet</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>
    
    
    <filter>
        <filter-name>shiroFilter</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>
    <filter-mapping>
        <filter-name>shiroFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

    看到这样的配置,难免有些疑问:
    1. 这三者是怎样融合到一起的
    2. 为什么那个bean的id和filter的name保持一样
    3. 为什么配置的bean是一个factoryBean而不是普通的bean

    带着这样的疑问,跟踪下启动过程。正向跟踪,即在refresh方法中开展,锁定getBean方法,通过name来追踪shiroFilter,发现关系比较乱,而且费时。于是锁定ShiroFilterFactoryBean的getObject方法,反向追踪,获得了下面的序列图:

    image

    重点就是:

    配置的监听器启动容器的初始化,完成上面ShiroFilterFactoryBean的创建和维护

    servlet触发过滤器Filter的init方法,在initDelegate方法中会getBean(),这个getBean最终会转移到ShiroFilterFactoryBean的getObject方法

    上面的问题第二个看源码很容易解决。

    在调用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) {
                    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();
                if (wac != null) {
                    this.delegate = initDelegate(wac);
                }
            }
        }
    }
    
    
    protected final String getFilterName() {
        return (this.filterConfig != null ? this.filterConfig.getFilterName() : this.beanName);
    }
    
    
    protected Filter initDelegate(WebApplicationContext wac) throws ServletException {
        Filter delegate = wac.getBean(getTargetBeanName(), Filter.class);
        if (isTargetFilterLifecycle()) {
            delegate.init(getFilterConfig());
        }
        return delegate;
    }

    获取的这个名字将用来追寻之前spring维护的那个bean,并且还要通过它来拿到一个Filter实例。

    那么为什么配置的那个bean是一个factoryBean而不是一个普通的bean?

    首先shiro是基于过滤器来实现的,配置一个filter是必要的。

    但是和spring在一起使用,就要让spirng来管理一些filter依赖的bean,例如安全管理器,还有自己实现的认证和鉴权服务之类。如果shiro直接写一个过滤器,那spring的容器早就启动完了,你这些东西怎么注入。

    所以只有提前初始化那些过滤器需要的东西,让他们依附于某个特定类,通过约定来在过滤器的初始化中获取(这个就是前面提到的相同的name)。

    那么这个bean可以是普通的bean吗?答案是不可以,毕竟shiro要的这个bean得是一个filter。普通的bean只能获取到它本身的实例,要获取filter那么它必须实现Filter接口。但是创建filter的方法你掌控不了了,spring会通过反射来创建对象,怎么创建是它说了算,自定义的创建是不可能了。

    这时候你就只能使用FactoyBean了。

    这个FactoryBean当然得交给shiro实现。不过filter的创建方式自由了,我们可以通过getBean来获取这个filter,另一边的filter配置还有必要吗?

    当然必要。因为这个filter怎么创建不重要,切入web的生命周期才重要,这个配置是一个规范。所以spring引入了这么一个类: DelegatingFilterProxy。就是一个代理类,自定义的实现转移到factoryBean了,这里就是公共类,主要操作是在容器中追踪并获取之前的factoryBean,并在初始化方法中获取需要的filter。

    Spring容器的启动依靠监听器,而filter是在监听器之后,依靠servlet规范,在listener,filter和servlet三者之间寻找契机,并形成一个共荣圈,Spring把这种关系处理得非常妙!

  • 相关阅读:
    C++学习9 this指针详解
    福建省第八届 Triangles
    UVA 11584 Partitioning by Palindromes
    POJ 2752 Seek the Name, Seek the Fame
    UVA 11437 Triangle Fun
    UVA 11488 Hyper Prefix Sets (字典树)
    HDU 2988 Dark roads(kruskal模板题)
    HDU 1385 Minimum Transport Cost
    HDU 2112 HDU Today
    HDU 1548 A strange lift(最短路&&bfs)
  • 原文地址:https://www.cnblogs.com/lucare/p/8679131.html
Copyright © 2011-2022 走看看