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>看到這樣的配置,難免有些疑問(wèn):
1. 這三者是怎樣融合到一起的
2. 為什么那個(gè)bean的id和filter的name保持一樣
3. 為什么配置的bean是一個(gè)factoryBean而不是普通的bean
帶著這樣的疑問(wèn),跟蹤下啟動(dòng)過(guò)程。正向跟蹤,即在refresh方法中開(kāi)展,鎖定getBean方法,通過(guò)name來(lái)追蹤shiroFilter,發(fā)現(xiàn)關(guān)系比較亂,而且費(fèi)時(shí)。于是鎖定ShiroFilterFactoryBean的getObject方法,反向追蹤,獲得了下面的序列圖:
重點(diǎn)就是:
配置的監(jiān)聽(tīng)器啟動(dòng)容器的初始化,完成上面ShiroFilterFactoryBean的創(chuàng)建和維護(hù)
servlet觸發(fā)過(guò)濾器Filter的init方法,在initDelegate方法中會(huì)getBean(),這個(gè)getBean最終會(huì)轉(zhuǎn)移到ShiroFilterFactoryBean的getObject方法
上面的問(wèn)題第二個(gè)看源碼很容易解決。
在調(diào)用DelegatingFilterProxy初始化方法時(shí):
@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; }獲取的這個(gè)名字將用來(lái)追尋之前spring維護(hù)的那個(gè)bean,并且還要通過(guò)它來(lái)拿到一個(gè)Filter實(shí)例。
那么為什么配置的那個(gè)bean是一個(gè)factoryBean而不是一個(gè)普通的bean?
首先shiro是基于過(guò)濾器來(lái)實(shí)現(xiàn)的,配置一個(gè)filter是必要的。
但是和spring在一起使用,就要讓spirng來(lái)管理一些filter依賴(lài)的bean,例如安全管理器,還有自己實(shí)現(xiàn)的認(rèn)證和鑒權(quán)服務(wù)之類(lèi)。如果shiro直接寫(xiě)一個(gè)過(guò)濾器,那spring的容器早就啟動(dòng)完了,你這些東西怎么注入。
所以只有提前初始化那些過(guò)濾器需要的東西,讓他們依附于某個(gè)特定類(lèi),通過(guò)約定來(lái)在過(guò)濾器的初始化中獲取(這個(gè)就是前面提到的相同的name)。
那么這個(gè)bean可以是普通的bean嗎?答案是不可以,畢竟shiro要的這個(gè)bean得是一個(gè)filter。普通的bean只能獲取到它本身的實(shí)例,要獲取filter那么它必須實(shí)現(xiàn)Filter接口。但是創(chuàng)建filter的方法你掌控不了了,spring會(huì)通過(guò)反射來(lái)創(chuàng)建對(duì)象,怎么創(chuàng)建是它說(shuō)了算,自定義的創(chuàng)建是不可能了。
這時(shí)候你就只能使用FactoyBean了。
這個(gè)FactoryBean當(dāng)然得交給shiro實(shí)現(xiàn)。不過(guò)filter的創(chuàng)建方式自由了,我們可以通過(guò)getBean來(lái)獲取這個(gè)filter,另一邊的filter配置還有必要嗎?
當(dāng)然必要。因?yàn)檫@個(gè)filter怎么創(chuàng)建不重要,切入web的生命周期才重要,這個(gè)配置是一個(gè)規(guī)范。所以spring引入了這么一個(gè)類(lèi): DelegatingFilterProxy。就是一個(gè)代理類(lèi),自定義的實(shí)現(xiàn)轉(zhuǎn)移到factoryBean了,這里就是公共類(lèi),主要操作是在容器中追蹤并獲取之前的factoryBean,并在初始化方法中獲取需要的filter。
Spring容器的啟動(dòng)依靠監(jiān)聽(tīng)器,而filter是在監(jiān)聽(tīng)器之后,依靠servlet規(guī)范,在listener,filter和servlet三者之間尋找契機(jī),并形成一個(gè)共榮圈,Spring把這種關(guān)系處理得非常妙!
轉(zhuǎn)載于:https://www.cnblogs.com/lucare/p/8679131.html
與50位技術(shù)專(zhuān)家面對(duì)面20年技術(shù)見(jiàn)證,附贈(zèng)技術(shù)全景圖總結(jié)
以上是生活随笔為你收集整理的Shiro切入Spring的方式的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: spring mvc4 笔记
- 下一篇: JAVA知识积累 JSP第一篇【JSP介