Skip to content

Commit 5326640

Browse files
committed
Initialize application context with initializer-given ServletContext
Closes gh-22319
1 parent 13b49d4 commit 5326640

File tree

3 files changed

+55
-22
lines changed

3 files changed

+55
-22
lines changed

spring-web/src/main/java/org/springframework/web/context/AbstractContextLoaderInitializer.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2018 the original author or authors.
2+
* Copyright 2002-2024 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -58,7 +58,7 @@ public void onStartup(ServletContext servletContext) throws ServletException {
5858
protected void registerContextLoaderListener(ServletContext servletContext) {
5959
WebApplicationContext rootAppContext = createRootApplicationContext();
6060
if (rootAppContext != null) {
61-
ContextLoaderListener listener = new ContextLoaderListener(rootAppContext);
61+
ContextLoaderListener listener = new ContextLoaderListener(rootAppContext, servletContext);
6262
listener.setContextInitializers(getRootApplicationContextInitializers());
6363
servletContext.addListener(listener);
6464
}

spring-web/src/main/java/org/springframework/web/context/ContextLoader.java

+13-13
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2023 the original author or authors.
2+
* Copyright 2002-2024 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -152,7 +152,7 @@ public class ContextLoader {
152152
* The root WebApplicationContext instance that this loader manages.
153153
*/
154154
@Nullable
155-
private WebApplicationContext context;
155+
private WebApplicationContext rootContext;
156156

157157
/** Actual ApplicationContextInitializer instances to apply to the context. */
158158
private final List<ApplicationContextInitializer<ConfigurableApplicationContext>> contextInitializers =
@@ -205,12 +205,12 @@ public ContextLoader() {
205205
* WebApplicationContext#ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE} and subclasses are
206206
* free to call the {@link #closeWebApplicationContext} method on container shutdown
207207
* to close the application context.
208-
* @param context the application context to manage
208+
* @param rootContext the application context to manage
209209
* @see #initWebApplicationContext(ServletContext)
210210
* @see #closeWebApplicationContext(ServletContext)
211211
*/
212-
public ContextLoader(WebApplicationContext context) {
213-
this.context = context;
212+
public ContextLoader(WebApplicationContext rootContext) {
213+
this.rootContext = rootContext;
214214
}
215215

216216

@@ -259,10 +259,10 @@ public WebApplicationContext initWebApplicationContext(ServletContext servletCon
259259
try {
260260
// Store context in local instance variable, to guarantee that
261261
// it is available on ServletContext shutdown.
262-
if (this.context == null) {
263-
this.context = createWebApplicationContext(servletContext);
262+
if (this.rootContext == null) {
263+
this.rootContext = createWebApplicationContext(servletContext);
264264
}
265-
if (this.context instanceof ConfigurableWebApplicationContext cwac && !cwac.isActive()) {
265+
if (this.rootContext instanceof ConfigurableWebApplicationContext cwac && !cwac.isActive()) {
266266
// The context has not yet been refreshed -> provide services such as
267267
// setting the parent context, setting the application context id, etc
268268
if (cwac.getParent() == null) {
@@ -273,22 +273,22 @@ public WebApplicationContext initWebApplicationContext(ServletContext servletCon
273273
}
274274
configureAndRefreshWebApplicationContext(cwac, servletContext);
275275
}
276-
servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.context);
276+
servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.rootContext);
277277

278278
ClassLoader ccl = Thread.currentThread().getContextClassLoader();
279279
if (ccl == ContextLoader.class.getClassLoader()) {
280-
currentContext = this.context;
280+
currentContext = this.rootContext;
281281
}
282282
else if (ccl != null) {
283-
currentContextPerThread.put(ccl, this.context);
283+
currentContextPerThread.put(ccl, this.rootContext);
284284
}
285285

286286
if (logger.isInfoEnabled()) {
287287
long elapsedTime = System.currentTimeMillis() - startTime;
288288
logger.info("Root WebApplicationContext initialized in " + elapsedTime + " ms");
289289
}
290290

291-
return this.context;
291+
return this.rootContext;
292292
}
293293
catch (RuntimeException | Error ex) {
294294
logger.error("Context initialization failed", ex);
@@ -506,7 +506,7 @@ protected ApplicationContext loadParentContext(ServletContext servletContext) {
506506
public void closeWebApplicationContext(ServletContext servletContext) {
507507
servletContext.log("Closing Spring root WebApplicationContext");
508508
try {
509-
if (this.context instanceof ConfigurableWebApplicationContext cwac) {
509+
if (this.rootContext instanceof ConfigurableWebApplicationContext cwac) {
510510
cwac.close();
511511
}
512512
}

spring-web/src/main/java/org/springframework/web/context/ContextLoaderListener.java

+40-7
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2023 the original author or authors.
2+
* Copyright 2002-2024 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -16,9 +16,12 @@
1616

1717
package org.springframework.web.context;
1818

19+
import jakarta.servlet.ServletContext;
1920
import jakarta.servlet.ServletContextEvent;
2021
import jakarta.servlet.ServletContextListener;
2122

23+
import org.springframework.lang.Nullable;
24+
2225
/**
2326
* Bootstrap listener to start up and shut down Spring's root {@link WebApplicationContext}.
2427
* Simply delegates to {@link ContextLoader} as well as to {@link ContextCleanupListener}.
@@ -36,6 +39,10 @@
3639
*/
3740
public class ContextLoaderListener extends ContextLoader implements ServletContextListener {
3841

42+
@Nullable
43+
private ServletContext servletContext;
44+
45+
3946
/**
4047
* Create a new {@code ContextLoaderListener} that will create a web application
4148
* context based on the "contextClass" and "contextConfigLocation" servlet
@@ -56,6 +63,19 @@ public class ContextLoaderListener extends ContextLoader implements ServletConte
5663
public ContextLoaderListener() {
5764
}
5865

66+
/**
67+
* Create a new {@code ContextLoaderListener} with the given application context,
68+
* initializing it with the {@link ServletContextEvent}-provided
69+
* {@link ServletContext} reference which is spec-restricted in terms of capabilities.
70+
* <p>It is generally preferable to initialize the application context with a
71+
* {@link org.springframework.web.WebApplicationInitializer#onStartup}-given reference
72+
* which is usually fully capable.
73+
* @see #ContextLoaderListener(WebApplicationContext, ServletContext)
74+
*/
75+
public ContextLoaderListener(WebApplicationContext rootContext) {
76+
super(rootContext);
77+
}
78+
5979
/**
6080
* Create a new {@code ContextLoaderListener} with the given application context. This
6181
* constructor is useful in Servlet initializers where instance-based registration of
@@ -85,12 +105,15 @@ public ContextLoaderListener() {
85105
* WebApplicationContext#ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE} and the Spring
86106
* application context will be closed when the {@link #contextDestroyed} lifecycle
87107
* method is invoked on this listener.
88-
* @param context the application context to manage
108+
* @param rootContext the application context to manage
109+
* @param servletContext the ServletContext to initialize with
110+
* @since 6.2
89111
* @see #contextInitialized(ServletContextEvent)
90112
* @see #contextDestroyed(ServletContextEvent)
91113
*/
92-
public ContextLoaderListener(WebApplicationContext context) {
93-
super(context);
114+
public ContextLoaderListener(WebApplicationContext rootContext, ServletContext servletContext) {
115+
super(rootContext);
116+
this.servletContext = servletContext;
94117
}
95118

96119

@@ -99,7 +122,8 @@ public ContextLoaderListener(WebApplicationContext context) {
99122
*/
100123
@Override
101124
public void contextInitialized(ServletContextEvent event) {
102-
initWebApplicationContext(event.getServletContext());
125+
ServletContext scToUse = getServletContextToUse(event);
126+
initWebApplicationContext(scToUse);
103127
}
104128

105129

@@ -108,8 +132,17 @@ public void contextInitialized(ServletContextEvent event) {
108132
*/
109133
@Override
110134
public void contextDestroyed(ServletContextEvent event) {
111-
closeWebApplicationContext(event.getServletContext());
112-
ContextCleanupListener.cleanupAttributes(event.getServletContext());
135+
ServletContext scToUse = getServletContextToUse(event);
136+
closeWebApplicationContext(scToUse);
137+
ContextCleanupListener.cleanupAttributes(scToUse);
138+
}
139+
140+
/**
141+
* Preferably use a fully-capable local ServletContext instead of
142+
* the spec-restricted ServletContextEvent-provided reference.
143+
*/
144+
private ServletContext getServletContextToUse(ServletContextEvent event) {
145+
return (this.servletContext != null ? this.servletContext : event.getServletContext());
113146
}
114147

115148
}

0 commit comments

Comments
 (0)