spring裏頭各類獲取ApplicationContext的方法

原文出處: 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行業人員進入!

相關文章
相關標籤/搜索