基本上,在彈簧MVC應用程序spring的上下文在th。中註冊Web應用程序的servlet上下文。您可以在web.xml
文件中設置彈簧ContextLoaderListener
或使用java配置來執行此操作。在評論我指出這個鏈接,它說明了這是如何通過Java配置類進行:
spring: where does `@autowired` look for beans?
在那裏,你可以看到「連接」是怎麼做的。然後,你在評論中問道,這是什麼實現:
WebApplicationContextUtils.getWebApplicationContext(myServlet.getServletContext())
如果你檢查類的代碼,你可以看到它從ServletContext
的屬性得到WebApplicationContext
。這些屬性在Web應用程序的初始化中設置。如果您發現,在ContextLoader
類(的ContextLoaderListener
母公司),在initWebApplicationContext
方法是將這些屬性的servlet上下文:
/**
* Initialize Spring's web application context for the given servlet context,
* using the application context provided at construction time, or creating a new one
* according to the "{@link #CONTEXT_CLASS_PARAM contextClass}" and
* "{@link #CONFIG_LOCATION_PARAM contextConfigLocation}" context-params.
* @param servletContext current servlet context
* @return the new WebApplicationContext
* @see #ContextLoader(WebApplicationContext)
* @see #CONTEXT_CLASS_PARAM
* @see #CONFIG_LOCATION_PARAM
*/
public WebApplicationContext initWebApplicationContext(ServletContext servletContext) {
if (servletContext.getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE) != null) {
throw new IllegalStateException(
"Cannot initialize context because there is already a root application context present - " +
"check whether you have multiple ContextLoader* definitions in your web.xml!");
}
Log logger = LogFactory.getLog(ContextLoader.class);
servletContext.log("Initializing Spring root WebApplicationContext");
if (logger.isInfoEnabled()) {
logger.info("Root WebApplicationContext: initialization started");
}
long startTime = System.currentTimeMillis();
try {
// Store context in local instance variable, to guarantee that
// it is available on ServletContext shutdown.
if (this.context == null) {
this.context = createWebApplicationContext(servletContext);
}
if (this.context instanceof ConfigurableWebApplicationContext) {
ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) this.context;
if (!cwac.isActive()) {
// The context has not yet been refreshed -> provide services such as
// setting the parent context, setting the application context id, etc
if (cwac.getParent() == null) {
// The context instance was injected without an explicit parent ->
// determine parent for root web application context, if any.
ApplicationContext parent = loadParentContext(servletContext);
cwac.setParent(parent);
}
configureAndRefreshWebApplicationContext(cwac, servletContext);
}
}
servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.context);
ClassLoader ccl = Thread.currentThread().getContextClassLoader();
if (ccl == ContextLoader.class.getClassLoader()) {
currentContext = this.context;
}
else if (ccl != null) {
currentContextPerThread.put(ccl, this.context);
}
if (logger.isDebugEnabled()) {
logger.debug("Published root WebApplicationContext as ServletContext attribute with name [" +
WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE + "]");
}
if (logger.isInfoEnabled()) {
long elapsedTime = System.currentTimeMillis() - startTime;
logger.info("Root WebApplicationContext: initialization completed in " + elapsedTime + " ms");
}
return this.context;
}
catch (RuntimeException ex) {
logger.error("Context initialization failed", ex);
servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, ex);
throw ex;
}
catch (Error err) {
logger.error("Context initialization failed", err);
servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, err);
throw err;
}
}
也就是在這一行做了:
servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.context);
正如你可以看到,它被保存在你正試圖與WebApplicationContextUtils.getWebApplicationContext(myServlet.getServletContext())
得到它同一個地方:
/**
* Find the root {@code WebApplicationContext} for this web app, typically
* loaded via {@link org.springframework.web.context.ContextLoaderListener}.
* <p>Will rethrow an exception that happened on root context startup,
* to differentiate between a failed context startup and no context at all.
* @param sc ServletContext to find the web application context for
* @return the root WebApplicationContext for this web app, or {@code null} if none
* @see org.springframework.web.context.WebApplicationContext#ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE
*/
public static WebApplicationContext getWebApplicationContext(ServletContext sc) {
return getWebApplicationContext(sc, WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE);
}
所以你可以看到所有的在Web應用程序啓動過程中,Spring會執行的代碼將解答您的疑問。
希望我回答了你的問題。
'WebApplicationContext'是一個'ApplicationContext'。 「ContextLoaderLIstener」和「DispatcherServlet」都加載了一個「WebApplicationContext」實例(實際上是一個接口)。只有一個「ApplicationContext」,無論它是Web還是非Web相關的。 'ApplicationContext'是容器。 –
@ M.Deinum正如你指出的那樣,每個應用程序都有一個'context',有很多白皮書解釋了兩者的存在,其中一些問題本身就提到了。而且,如果你僅僅通過'DispatcherServlet'初始化你的上下文, 'ContextLoaderListner'回覆spring security''這會拋出'IllegalStateException:沒有找到ApplicationContext:' –
2017-02-17 09:05:22
不,我沒有指出只有一個上下文......但只有spring具有'ApplicationContext'的概念。它可以是'WebApplicationContext'類型。可以有1或100.我暗示'ContextLoaderListener'和'DispatcherServlet'都加載了一個'WebApplicationContext'。 ContextLoaderLIstener加載一個通常稱爲根上下文的上下文,這也是過濾器可以訪問的內容。你也可以這樣做(如果你有一個'DispatcherServlet'來公開那個作爲根環境(這通常是人們忘記導致你指向的問題))。 –