原文出處: xieyu_zyweb
爲啥寫這個文章呢?spring各個版本不一樣,以及和系統框架套在一塊兒不一樣,致使獲取的方式不一樣,網絡上各類版本,太亂了,寫獲取方式的人都不寫這個獲取方式是在本地仍是在WEB,在那種應用服務器下,在spring那個版本下,太過度了!spring
我這寫一些,常見的,可能常常要用的版本;數據庫
首先了解,爲何要獲取這個東西:當你想經過spring獲取一個你指定的類的實例的時候,而又沒有經過spring加載到當前調用的類裏面,例如你在filter裏面,可能要對人員角色作斷定,此時還沒到業務層代碼,可是又要訪問數據庫或其餘的服務類。編程
而後再確保一點:這個context是一個全局變量,spring加載的時候,根handle信息就被裝載,不管是本地應用程序仍是web應用都是這樣,下面分別說下若是是本地程序和其餘狀況的獲取方式。tomcat
若是是main方法,你要啓動spring,有不少方法,有基於annotation的註解來說配置文件裝載起來,固然,你想獲取applicationCntext可在main方法中這樣獲取:服務器
1
|
XmlBeanFactory factory =
new
XmlBeanFactory(
new
ClassPathResource(
"beans.xml"
));
//這樣來加載配置文件
|
還有沒有其餘的方式呢?有的網絡
1
|
ApplicationContext context =
new
ClassPathXmlApplicationContext(
new
String[] {
"a.xml"
,
"b.xml"
});
|
還有沒有其餘的?有session
1
2
3
4
5
6
|
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);
|
其實方法差很少,他們有着繼承關係,因此方法不少,你每次new的時候,至關於從新建立一個applicationContext,他會從新裝載,因此不適合反覆調用,若是本身new,你就應當把它放到一個全局變量中,用main啓動的,固然你經過直接或間接的static應用到這個application便可。架構
而在WEB上呢,有一種是經過spring來加載spring自己的方式是:app
經過實現接口:
1
|
org.springframework.context.ApplicationContextAware
|
而後spring反射,來源文章:http://blog.163.com/xuyang1974@126/blog/static/2684016320101028101923914/
這種方式適在spring 二、3當中均有效:
編寫類:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
import
org.springframework.beans.BeansException;
import
org.springframework.context.ApplicationContext;
import
org.springframework.context.ApplicationContextAware;
import
org.springframework.stereotype.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);
}
}
|
我這裏是經過annotation註解的,若是不是annotation,那麼能夠經過配置文件:
1
|
<
bean
class
=
"xxx.xxx.xxx.SpringContextHolder"
></
bean
>
|
來進行注入操做,結果同樣,若是的spring配置中,沒有設置byName的話,bean的配置裏面記得要加參數來設置applicationContext來反射進去。
而你要加載spring,不少時候,並非進入業務層的,由於反射是反射到業務層的,你尚未進入業務層,怎麼來獲取這個反射的東西呢?除非你反射的時候,用static變量來獲取,那麼就沒有問題了;因此上面的例子中他也用的是static;
當你不想用static來反射,而常常想要用到它的時候,就有不少種獲取方式了。
在spring 3之前的版本,咱們在WEB應用中一般是這樣獲取的:
1
|
WebApplicationContext wac = WebApplicationContextUtils.getWebApplicationContext(context);
|
而contexnt是什麼呢?若是是servlet中,是能夠直接經過getServletContext()獲取,
而經過request要這樣獲取:
對於全部的tomcat通用的寫法是:
1
|
ServletContext context = req.getSession().getServletContext();
|
對於tomcat 7以上的寫法是(也就是tomcat 7能夠直接從request中獲取servletContext,tomcat6不行,必須經過session才能夠):
1
|
ServletContext context = req.getServletContext();
|
其實從spring 3事後,獲取的方法就有所改變,變得很詭異,由於居然不兼容之前的獲取方法,spring 3當中將其進行了進一步的包裝,你在其餘地方可能看到各類各樣的版本。
spring 2中之因此能夠那樣獲取,是由於spring 2當中一般會配置一個listener,由他來加載spring,他在filter以前;spring 3當中,經過org.springframework.web.servlet.DispatcherServlet來裝載spring的信息,初始化在其父親類:org.springframework.web.servlet.FrameworkServlet中方法:initWebApplicationContext();
跟蹤方法明顯看到內部獲取增長了一個參數:
1
|
WebApplicationContext wac = WebApplicationContextUtils.getWebApplicationContext(getServletContext(),attrName);
|
這個參數是什麼呢?
通過跟蹤能夠發現是:
1
|
FrameworkServlet.SERVLET_CONTEXT_PREFIX + getServletName()
|
而SERVLET_CONTEXT_PREFIX的定義是:
1
|
public
static
final
String SERVLET_CONTEXT_PREFIX = FrameworkServlet.
class
.getName() +
".CONTEXT."
;
|
也就是:
1
|
「org.springframework.web.servlet.FrameworkServlet.CONTEXT.」
|
而getServletName()呢?他是當前請求的servlet,能夠獲取到的一個web.xml裏面配置的名稱,例如,
若是你的web.xml中配置的是:
1
2
3
4
5
|
<
servlet
>
<
servlet-name
>spring</
servlet-name
>
<
servlet-class
>org.springframework.web.servlet.DispatcherServlet</
servlet-class
>
<
load-on-startup
>1</
load-on-startup
>
</
servlet
>
|
說明getServletName()的結果就是spring,不然就是其餘,那麼若是是spring,就是:
1
|
org.springframework.web.servlet.FrameworkServlet.CONTEXT.spring
|
ok,若是按照上面的配置,獲取方式就是:
1
|
request.getSession().getServletContext().getAttribute(
"org.springframework.web.servlet.FrameworkServlet.CONTEXT.spring"
);
|
tomcat 7以上能夠寫成:
1
|
request.getServletContext().getAttribute(
"org.springframework.web.servlet.FrameworkServlet.CONTEXT.spring"
);
|
更爲好的寫法是:
1
|
request.getSession().getServletContext().getAttribute(FrameworkServlet.SERVLET_CONTEXT_PREFIX +"spring");
|
如下爲spring爲了方便,作的一些擴展:
spring爲了業務代碼中獲取這個參數方便,在進入業務代碼前作了一個操做,在DispatcherServlet的方法:doService中doDispatch調用以前:
1
|
request.setAttribute(WEB_APPLICATION_CONTEXT_ATTRIBUTE, getWebApplicationContext());
|
也就是,當你進入Controller之後,獲取就不用那麼麻煩了,你只須要這樣就能獲取到:
1
|
request.getAttribute(DispatcherServlet.WEB_APPLICATION_CONTEXT_ATTRIBUTE);
|
固然,你能夠將值寫進去,看定義是:
1
|
public
static
final
String WEB_APPLICATION_CONTEXT_ATTRIBUTE = DispatcherServlet.
class
.getName() +
".CONTEXT"
;
|
那麼值就應該是:
1
|
org.springframework.web.servlet.DispatcherServlet.CONTEXT
|
因此在Controller中你還能夠這樣來獲取:
1
|
request.getAttribute(
"org.springframework.web.servlet.DispatcherServlet.CONTEXT"
)
|
通過spring包裝後,你也能夠經過:
1
|
RequestContextUtils.getWebApplicationContext(request , context)
|
來獲取,源碼以下:
其實它獲取的方式和上面給的方法是同樣的,RequestContextUtils.getWebApplicationContext在spring 3當中,若是沒有啓動ContextLoaderListener(固然你能夠配置監聽),是不會成功的。
ContextLoaderListener的簡單配置爲(web.xml中):
1
2
3
|
<
listener
>
<
listener-class
>org.springframework.web.context.ContextLoaderListener</
listener-class
>
</
listener
>
|
spring 3之後基本不這樣配置了。
問啊-定製化IT教育平臺,牛人一對一服務,有問必答,開發編程社交頭條 官方網站:www.wenaaa.com
QQ羣290551701 彙集不少互聯網精英,技術總監,架構師,項目經理!開源技術研究,歡迎業內人士,大牛及新手有志於從事IT行業人員進入!