Browse Source

Thread-safe removal of destruction callbacks in web scopes

Closes gh-23117
pull/25598/head
Juergen Hoeller 7 years ago
parent
commit
d032beddb5
  1. 20
      spring-web/src/main/java/org/springframework/web/context/ContextCleanupListener.java
  2. 7
      spring-web/src/main/java/org/springframework/web/context/request/ServletRequestAttributes.java
  3. 18
      spring-web/src/main/java/org/springframework/web/context/support/ServletContextScope.java

20
spring-web/src/main/java/org/springframework/web/context/ContextCleanupListener.java

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2012 the original author or authors. * Copyright 2002-2019 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -54,22 +54,26 @@ public class ContextCleanupListener implements ServletContextListener {
/** /**
* Find all ServletContext attributes which implement {@link DisposableBean} * Find all Spring-internal ServletContext attributes which implement
* and destroy them, removing all affected ServletContext attributes eventually. * {@link DisposableBean} and invoke the destroy method on them.
* @param sc the ServletContext to check * @param servletContext the ServletContext to check
* @see DisposableBean#destroy()
*/ */
static void cleanupAttributes(ServletContext sc) { static void cleanupAttributes(ServletContext servletContext) {
Enumeration<String> attrNames = sc.getAttributeNames(); Enumeration<String> attrNames = servletContext.getAttributeNames();
while (attrNames.hasMoreElements()) { while (attrNames.hasMoreElements()) {
String attrName = attrNames.nextElement(); String attrName = attrNames.nextElement();
if (attrName.startsWith("org.springframework.")) { if (attrName.startsWith("org.springframework.")) {
Object attrValue = sc.getAttribute(attrName); Object attrValue = servletContext.getAttribute(attrName);
if (attrValue instanceof DisposableBean) { if (attrValue instanceof DisposableBean) {
try { try {
((DisposableBean) attrValue).destroy(); ((DisposableBean) attrValue).destroy();
} }
catch (Throwable ex) { catch (Throwable ex) {
logger.error("Couldn't invoke destroy method of attribute with name '" + attrName + "'", ex); if (logger.isWarnEnabled()) {
logger.warn("Invocation of destroy method failed on ServletContext " +
"attribute with name '" + attrName + "'", ex);
}
} }
} }
} }

7
spring-web/src/main/java/org/springframework/web/context/request/ServletRequestAttributes.java

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2017 the original author or authors. * Copyright 2002-2019 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -188,8 +188,8 @@ public class ServletRequestAttributes extends AbstractRequestAttributes {
public void removeAttribute(String name, int scope) { public void removeAttribute(String name, int scope) {
if (scope == SCOPE_REQUEST) { if (scope == SCOPE_REQUEST) {
if (isRequestActive()) { if (isRequestActive()) {
this.request.removeAttribute(name);
removeRequestDestructionCallback(name); removeRequestDestructionCallback(name);
this.request.removeAttribute(name);
} }
} }
else { else {
@ -197,9 +197,8 @@ public class ServletRequestAttributes extends AbstractRequestAttributes {
if (session != null) { if (session != null) {
this.sessionAttributesToUpdate.remove(name); this.sessionAttributesToUpdate.remove(name);
try { try {
session.removeAttribute(name);
// Remove any registered destruction callback as well.
session.removeAttribute(DESTRUCTION_CALLBACK_NAME_PREFIX + name); session.removeAttribute(DESTRUCTION_CALLBACK_NAME_PREFIX + name);
session.removeAttribute(name);
} }
catch (IllegalStateException ex) { catch (IllegalStateException ex) {
// Session invalidated - shouldn't usually happen. // Session invalidated - shouldn't usually happen.

18
spring-web/src/main/java/org/springframework/web/context/support/ServletContextScope.java

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2017 the original author or authors. * Copyright 2002-2019 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -78,8 +78,10 @@ public class ServletContextScope implements Scope, DisposableBean {
public Object remove(String name) { public Object remove(String name) {
Object scopedObject = this.servletContext.getAttribute(name); Object scopedObject = this.servletContext.getAttribute(name);
if (scopedObject != null) { if (scopedObject != null) {
synchronized (this.destructionCallbacks) {
this.destructionCallbacks.remove(name);
}
this.servletContext.removeAttribute(name); this.servletContext.removeAttribute(name);
this.destructionCallbacks.remove(name);
return scopedObject; return scopedObject;
} }
else { else {
@ -89,7 +91,9 @@ public class ServletContextScope implements Scope, DisposableBean {
@Override @Override
public void registerDestructionCallback(String name, Runnable callback) { public void registerDestructionCallback(String name, Runnable callback) {
this.destructionCallbacks.put(name, callback); synchronized (this.destructionCallbacks) {
this.destructionCallbacks.put(name, callback);
}
} }
@Override @Override
@ -112,10 +116,12 @@ public class ServletContextScope implements Scope, DisposableBean {
*/ */
@Override @Override
public void destroy() { public void destroy() {
for (Runnable runnable : this.destructionCallbacks.values()) { synchronized (this.destructionCallbacks) {
runnable.run(); for (Runnable runnable : this.destructionCallbacks.values()) {
runnable.run();
}
this.destructionCallbacks.clear();
} }
this.destructionCallbacks.clear();
} }
} }

Loading…
Cancel
Save