Browse Source

Initialize application context with initializer-given ServletContext

Closes gh-22319
pull/33604/head
Juergen Hoeller 1 year ago
parent
commit
5326640f79
  1. 4
      spring-web/src/main/java/org/springframework/web/context/AbstractContextLoaderInitializer.java
  2. 26
      spring-web/src/main/java/org/springframework/web/context/ContextLoader.java
  3. 47
      spring-web/src/main/java/org/springframework/web/context/ContextLoaderListener.java

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

@ -1,5 +1,5 @@ @@ -1,5 +1,5 @@
/*
* Copyright 2002-2018 the original author or authors.
* Copyright 2002-2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -58,7 +58,7 @@ public abstract class AbstractContextLoaderInitializer implements WebApplication @@ -58,7 +58,7 @@ public abstract class AbstractContextLoaderInitializer implements WebApplication
protected void registerContextLoaderListener(ServletContext servletContext) {
WebApplicationContext rootAppContext = createRootApplicationContext();
if (rootAppContext != null) {
ContextLoaderListener listener = new ContextLoaderListener(rootAppContext);
ContextLoaderListener listener = new ContextLoaderListener(rootAppContext, servletContext);
listener.setContextInitializers(getRootApplicationContextInitializers());
servletContext.addListener(listener);
}

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

@ -1,5 +1,5 @@ @@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 the original author or authors.
* Copyright 2002-2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -152,7 +152,7 @@ public class ContextLoader { @@ -152,7 +152,7 @@ public class ContextLoader {
* The root WebApplicationContext instance that this loader manages.
*/
@Nullable
private WebApplicationContext context;
private WebApplicationContext rootContext;
/** Actual ApplicationContextInitializer instances to apply to the context. */
private final List<ApplicationContextInitializer<ConfigurableApplicationContext>> contextInitializers =
@ -205,12 +205,12 @@ public class ContextLoader { @@ -205,12 +205,12 @@ public class ContextLoader {
* WebApplicationContext#ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE} and subclasses are
* free to call the {@link #closeWebApplicationContext} method on container shutdown
* to close the application context.
* @param context the application context to manage
* @param rootContext the application context to manage
* @see #initWebApplicationContext(ServletContext)
* @see #closeWebApplicationContext(ServletContext)
*/
public ContextLoader(WebApplicationContext context) {
this.context = context;
public ContextLoader(WebApplicationContext rootContext) {
this.rootContext = rootContext;
}
@ -259,10 +259,10 @@ public class ContextLoader { @@ -259,10 +259,10 @@ public class ContextLoader {
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.rootContext == null) {
this.rootContext = createWebApplicationContext(servletContext);
}
if (this.context instanceof ConfigurableWebApplicationContext cwac && !cwac.isActive()) {
if (this.rootContext instanceof ConfigurableWebApplicationContext cwac && !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) {
@ -273,14 +273,14 @@ public class ContextLoader { @@ -273,14 +273,14 @@ public class ContextLoader {
}
configureAndRefreshWebApplicationContext(cwac, servletContext);
}
servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.context);
servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.rootContext);
ClassLoader ccl = Thread.currentThread().getContextClassLoader();
if (ccl == ContextLoader.class.getClassLoader()) {
currentContext = this.context;
currentContext = this.rootContext;
}
else if (ccl != null) {
currentContextPerThread.put(ccl, this.context);
currentContextPerThread.put(ccl, this.rootContext);
}
if (logger.isInfoEnabled()) {
@ -288,7 +288,7 @@ public class ContextLoader { @@ -288,7 +288,7 @@ public class ContextLoader {
logger.info("Root WebApplicationContext initialized in " + elapsedTime + " ms");
}
return this.context;
return this.rootContext;
}
catch (RuntimeException | Error ex) {
logger.error("Context initialization failed", ex);
@ -506,7 +506,7 @@ public class ContextLoader { @@ -506,7 +506,7 @@ public class ContextLoader {
public void closeWebApplicationContext(ServletContext servletContext) {
servletContext.log("Closing Spring root WebApplicationContext");
try {
if (this.context instanceof ConfigurableWebApplicationContext cwac) {
if (this.rootContext instanceof ConfigurableWebApplicationContext cwac) {
cwac.close();
}
}

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

@ -1,5 +1,5 @@ @@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 the original author or authors.
* Copyright 2002-2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -16,9 +16,12 @@ @@ -16,9 +16,12 @@
package org.springframework.web.context;
import jakarta.servlet.ServletContext;
import jakarta.servlet.ServletContextEvent;
import jakarta.servlet.ServletContextListener;
import org.springframework.lang.Nullable;
/**
* Bootstrap listener to start up and shut down Spring's root {@link WebApplicationContext}.
* Simply delegates to {@link ContextLoader} as well as to {@link ContextCleanupListener}.
@ -36,6 +39,10 @@ import jakarta.servlet.ServletContextListener; @@ -36,6 +39,10 @@ import jakarta.servlet.ServletContextListener;
*/
public class ContextLoaderListener extends ContextLoader implements ServletContextListener {
@Nullable
private ServletContext servletContext;
/**
* Create a new {@code ContextLoaderListener} that will create a web application
* context based on the "contextClass" and "contextConfigLocation" servlet
@ -56,6 +63,19 @@ public class ContextLoaderListener extends ContextLoader implements ServletConte @@ -56,6 +63,19 @@ public class ContextLoaderListener extends ContextLoader implements ServletConte
public ContextLoaderListener() {
}
/**
* Create a new {@code ContextLoaderListener} with the given application context,
* initializing it with the {@link ServletContextEvent}-provided
* {@link ServletContext} reference which is spec-restricted in terms of capabilities.
* <p>It is generally preferable to initialize the application context with a
* {@link org.springframework.web.WebApplicationInitializer#onStartup}-given reference
* which is usually fully capable.
* @see #ContextLoaderListener(WebApplicationContext, ServletContext)
*/
public ContextLoaderListener(WebApplicationContext rootContext) {
super(rootContext);
}
/**
* Create a new {@code ContextLoaderListener} with the given application context. This
* constructor is useful in Servlet initializers where instance-based registration of
@ -85,12 +105,15 @@ public class ContextLoaderListener extends ContextLoader implements ServletConte @@ -85,12 +105,15 @@ public class ContextLoaderListener extends ContextLoader implements ServletConte
* WebApplicationContext#ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE} and the Spring
* application context will be closed when the {@link #contextDestroyed} lifecycle
* method is invoked on this listener.
* @param context the application context to manage
* @param rootContext the application context to manage
* @param servletContext the ServletContext to initialize with
* @since 6.2
* @see #contextInitialized(ServletContextEvent)
* @see #contextDestroyed(ServletContextEvent)
*/
public ContextLoaderListener(WebApplicationContext context) {
super(context);
public ContextLoaderListener(WebApplicationContext rootContext, ServletContext servletContext) {
super(rootContext);
this.servletContext = servletContext;
}
@ -99,7 +122,8 @@ public class ContextLoaderListener extends ContextLoader implements ServletConte @@ -99,7 +122,8 @@ public class ContextLoaderListener extends ContextLoader implements ServletConte
*/
@Override
public void contextInitialized(ServletContextEvent event) {
initWebApplicationContext(event.getServletContext());
ServletContext scToUse = getServletContextToUse(event);
initWebApplicationContext(scToUse);
}
@ -108,8 +132,17 @@ public class ContextLoaderListener extends ContextLoader implements ServletConte @@ -108,8 +132,17 @@ public class ContextLoaderListener extends ContextLoader implements ServletConte
*/
@Override
public void contextDestroyed(ServletContextEvent event) {
closeWebApplicationContext(event.getServletContext());
ContextCleanupListener.cleanupAttributes(event.getServletContext());
ServletContext scToUse = getServletContextToUse(event);
closeWebApplicationContext(scToUse);
ContextCleanupListener.cleanupAttributes(scToUse);
}
/**
* Preferably use a fully-capable local ServletContext instead of
* the spec-restricted ServletContextEvent-provided reference.
*/
private ServletContext getServletContextToUse(ServletContextEvent event) {
return (this.servletContext != null ? this.servletContext : event.getServletContext());
}
}

Loading…
Cancel
Save