shiro切入方式

来源:互联网 发布:ubuntu cd显示不存在 编辑:程序博客网 时间:2024/05/22 01:47

在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初始化方法时:

@Overrideprotected 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是在监听器之后,而且listerner、filter和servlet相当于同级的东西,spring把这种关系处理得非常妙!

阅读全文
'); })();
0 0
原创粉丝点击
热门IT博客
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 中青旅旅行社 小旅馆 情侣宾馆 旅行社网站 小旅店 情侣旅馆 青年旅馆 家庭宾馆 出境游旅行社 北美旅行社 找宾馆 中旅行社 住宾馆 城市客栈 商务酒店预订 旅店价格 春秋国际旅行社 机场宾馆 家庭客栈 酒店预定网站 旅馆英语 家旅馆 旅馆网站 商务酒店预定 旅馆英文 京东宾馆 旅行社招聘 旅游旅馆 武道旅程 温暖的旅程 勇士的旅程 人生旅程 旅程 爱的旅程 一段旅程 奇幻旅程 危险旅程 旅程作文 真爱旅程 旅程英文 旅程的英文