為啥寫(xiě)這個(gè)文章呢?spring各個(gè)版本不同,以及和系統(tǒng)框架套在一起不同,導(dǎo)致獲取的方式不同,網(wǎng)絡(luò)上各種版本,太亂了,寫(xiě)獲取方式的人都不寫(xiě)這個(gè)獲取方式是在本地還是在WEB,在那種應(yīng)用服務(wù)器下,在spring那個(gè)版本下,太過(guò)分了!
我這寫(xiě)一些,常見(jiàn)的,可能經(jīng)常要用的版本;
首先了解,為什么要獲取這個(gè)東西 :當(dāng)你想通過(guò)spring獲取一個(gè)你指定的類的實(shí)例的時(shí)候,而又沒(méi)有通過(guò)spring加載到當(dāng)前調(diào)用的類里面,例如你在filter里面,可能要對(duì)人員角色做判定,此時(shí)還沒(méi)到業(yè)務(wù)層代碼,但是又要訪問(wèn)數(shù)據(jù)庫(kù)或其他的服務(wù)類。
然后再確保一點(diǎn) :這個(gè)context是一個(gè)全局變量,spring加載的時(shí)候,根handle信息就被裝載,無(wú)論是本地應(yīng)用程序還是web應(yīng)用都是這樣,下面分別說(shuō)下如果是本地程序和其他情況的獲取方式。
如果是main方法,你要啟動(dòng)spring,有很多方法,有基于annotation的注解來(lái)講配置文件裝載起來(lái),當(dāng)然,你想獲取applicationCntext可在main方法中這樣獲取:
[java] ?view plaincopy
XmlBeanFactory?factory?=? new ?XmlBeanFactory( new ?ClassPathResource( "beans.xml" )); ??
還有沒(méi)有其他的方式呢?有的
[java] view plaincopy
ApplicationContext?context?=? new ?ClassPathXmlApplicationContext( new ?String[]?{ "a.xml" ,? "b.xml" });??
還有沒(méi)有其他的?有
[java] view plaincopy
XmlWebApplicationContext?context?=? new ?XmlWebApplicationContext();?? context.setConfigLocations(new ?String[]?{ "aaa.xml" ?,? "bb.xml" });?? MockServletContext?msc?=?new ?MockServletContext();?? context.setServletContext(msc);?? context.refresh();?? msc.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE,?context);??
其實(shí)方法差不多,他們有著繼承關(guān)系,所以方法很多,你每次new的時(shí)候,相當(dāng)于重新創(chuàng)建一個(gè)
applicationContext ,他會(huì)重新裝載,所以不適合反復(fù)調(diào)用,如果自己new,你就應(yīng)當(dāng)把它放到一個(gè)全局變量中,用main啟動(dòng)的,當(dāng)然你通過(guò)直接或間接的
static 應(yīng)用到這個(gè)
application 即可。
而在WEB上呢,有一種是通過(guò)spring來(lái)加載spring本身的方式是:
通過(guò)實(shí)現(xiàn)接口:
[java] view plaincopy
org.springframework.context.ApplicationContextAware??
然后spring反射,來(lái)源文章:http://blog.163.com/xuyang1974@126/blog/static/2684016320101028101923914/
這種方式適在spring 2、3當(dāng)中均有效:
編寫(xiě)類:
[java] view plaincopy
import ?org.springframework.beans.BeansException;?? import ?org.springframework.context.ApplicationContext;?? import ?org.springframework.context.ApplicationContextAware;?? import ?org.springframework.stereotype.Service;?? @Service ?? public ? class ?SpringContextHolder? implements ?ApplicationContextAware?{?? ????private ? static ?ApplicationContext?applicationContext;?? ?? ????@Override ?? ????public ? void ?setApplicationContext(ApplicationContext?applicationContext)? throws ?BeansException?{?? ????????SpringContextHolder.applicationContext?=?applicationContext;?? ????}?? ?? ?? ????public ? static ?ApplicationContext?getApplicationContext()?{?? ????????return ?applicationContext;?? ????}?? ????public ? static ?Object?getBean(String?beanName)?{?? ????????return ?applicationContext.getBean(beanName);?? ????}?? ?????? ????public ? static ?<T>T?getBean(String?beanName?,?Class<T>clazz)?{?? ????????return ?applicationContext.getBean(beanName?,?clazz);?? ????}?? }??
我這里是通過(guò)annotation注解的,如果不是annotation,那么可以通過(guò)配置文件:
[html] view plaincopy
< bean ? class = "xxx.xxx.xxx.SpringContextHolder" > </ bean > ??
來(lái)進(jìn)行注入操作,結(jié)果一樣,如果的spring配置中,沒(méi)有設(shè)置byName 的話,bean的配置里面記得要加參數(shù)來(lái)設(shè)置applicationContext來(lái)反射進(jìn)去。
而你要加載spring,很多時(shí)候,并不是進(jìn)入業(yè)務(wù)層的,因?yàn)榉瓷涫欠瓷涞綐I(yè)務(wù)層的,你還沒(méi)有進(jìn)入業(yè)務(wù)層,怎么來(lái)獲取這個(gè)反射的東西呢?除非你反射的時(shí)候,用static變量來(lái)獲取,那么就沒(méi)有問(wèn)題了;所以上面的例子中他也用的是static;
當(dāng)你不想用static來(lái)反射,而經(jīng)常想要用到它的時(shí)候,就有很多種獲取方式了。
在spring 3以前 的版本,我們?cè)赪EB應(yīng)用中通常是這樣獲取的:
[java] view plaincopy
WebApplicationContext?wac?=?WebApplicationContextUtils.getWebApplicationContext(context);??
而contexnt是什么呢?如果是servlet中,是可以直接通過(guò)getServletContext()獲取,
而通過(guò)request要這樣獲取:
對(duì)于所有的tomcat通用的寫(xiě)法是:
[java] view plaincopy
ServletContext?context?=?req.getSession().getServletContext();??
對(duì)于
tomcat 7 以上的寫(xiě)法是(也就是tomcat 7可以直接從request中獲取servletContext,tomcat6不行,必須通過(guò)session才可以):
[java] view plaincopy
ServletContext?context?=?req.getServletContext();??
其實(shí)從spring 3過(guò)后,獲取的方法就有所改變,變得很詭異,因?yàn)榫谷徊患嫒菀郧暗墨@取方法,spring 3當(dāng)中將其進(jìn)行了進(jìn)一步的包裝,你在其他地方可能看到各種各樣的版本。
spring 2中之所以可以那樣獲取,是因?yàn)閟pring 2當(dāng)中通常會(huì)配置一個(gè)listener,由他來(lái)加載spring,他在filter之前;spring 3當(dāng)中,通過(guò)org.springframework.web.servlet.DispatcherServlet 來(lái)裝載spring的信息,初始化在其父親類:org.springframework.web.servlet.FrameworkServlet中方法:initWebApplicationContext();
跟蹤方法明顯看到內(nèi)部獲取增加了一個(gè)參數(shù):
[java] ?view plaincopy
WebApplicationContext?wac?=?WebApplicationContextUtils.getWebApplicationContext(getServletContext(),attrName);??
這個(gè)參數(shù)是什么呢?
經(jīng)過(guò)跟蹤可以發(fā)現(xiàn)是:
[java] ?view plaincopy
FrameworkServlet.SERVLET_CONTEXT_PREFIX?+?getServletName()??
而SERVLET_CONTEXT_PREFIX的定義是:
[java] ?view plaincopy
public ? static ? final ?String?SERVLET_CONTEXT_PREFIX?=?FrameworkServlet. class .getName()?+? ".CONTEXT." ;??
也就是:
[java] ?view plaincopy
“org.springframework.web.servlet.FrameworkServlet.CONTEXT.”??
而getServletName()呢?他是當(dāng)前請(qǐng)求的servlet,可以獲取到的一個(gè)web.xml里面配置的名稱,例如,
如果你的web.xml中配置的是:
[html] ?view plaincopy
< servlet > ?? ????????< servlet-name > spring </ servlet-name > ?? ????????< servlet-class > org.springframework.web.servlet.DispatcherServlet </ servlet-class > ?? ????????< load-on-startup > 1 </ load-on-startup > ?? ????</ servlet > ??
說(shuō)明getServletName()的結(jié)果就是spring,否則就是其他,那么如果是spring,就是:
[java] ?view plaincopy
org.springframework.web.servlet.FrameworkServlet.CONTEXT.spring??
ok,如果按照上面的配置,獲取方式就是:
[java] ?view plaincopy
request.getSession().getServletContext().getAttribute( "org.springframework.web.servlet.FrameworkServlet.CONTEXT.spring" );??
tomcat 7以上可以寫(xiě)成:
[java] ?view plaincopy
request.getServletContext().getAttribute( "org.springframework.web.servlet.FrameworkServlet.CONTEXT.spring" );??
更為好的寫(xiě)法是:
[html] ?view plaincopy
request.getSession().getServletContext().getAttribute(FrameworkServlet.SERVLET_CONTEXT_PREFIX?+"spring");??
以下為spring為了方便,做的一些擴(kuò)展:
spring為了業(yè)務(wù)代碼中獲取這個(gè)參數(shù)方便,在進(jìn)入業(yè)務(wù)代碼前做了一個(gè)操作,在DispatcherServlet的方法:doService中doDispatch調(diào)用之前:
[java] ?view plaincopy
request.setAttribute(WEB_APPLICATION_CONTEXT_ATTRIBUTE,?getWebApplicationContext());??
也就是,當(dāng)你進(jìn)入Controller以后,獲取就不用那么麻煩了,你只需要這樣就能獲取到:
[java] ?view plaincopy
request.getAttribute(DispatcherServlet.WEB_APPLICATION_CONTEXT_ATTRIBUTE);??
當(dāng)然,你可以將值寫(xiě)進(jìn)去,看定義是:
[java] ?view plaincopy
public ? static ? final ?String?WEB_APPLICATION_CONTEXT_ATTRIBUTE?=?DispatcherServlet. class .getName()?+? ".CONTEXT" ;??
那么值就應(yīng)該是:
[java] ?view plaincopy
org.springframework.web.servlet.DispatcherServlet.CONTEXT??
所以在Controller中你還可以這樣來(lái)獲取:
[java] ?view plaincopy
request.getAttribute( "org.springframework.web.servlet.DispatcherServlet.CONTEXT" )??
經(jīng)過(guò)spring包裝后,你也可以通過(guò):
[java] ?view plaincopy
RequestContextUtils.getWebApplicationContext(request?,?context)??
來(lái)獲取,源碼如下:
其實(shí)它獲取的方式和上面給的方法是一樣的,RequestContextUtils.getWebApplicationContext 在spring 3當(dāng)中,如果沒(méi)有啟動(dòng)ContextLoaderListener (當(dāng)然你可以配置監(jiān)聽(tīng)),是不會(huì)成功的。
ContextLoaderListener 的簡(jiǎn)單配置為(web.xml中):
[html] ?view plaincopy
< listener > ?? ?< listener-class > org.springframework.web.context.ContextLoaderListener </ listener-class > ?? </ listener > ??
spring 3以后基本不這樣配置了。
from:?http://blog.csdn.net/xieyuooo/article/details/8473503
總結(jié)
以上是生活随笔 為你收集整理的spring里头各种获取ApplicationContext的方法 的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
如果覺(jué)得生活随笔 網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔 推薦給好友。