Prevent retention of child from parent
When the child is listening for parent closed events the parent has a reference to the listener which contains the chils. Thust there is a cycle of references and a GC probalem waiting to happen. This change breaks the cycle by making the reference to the child a WeakReference. Fixes gh-559
This commit is contained in:
parent
770c115d88
commit
9d2983e994
|
|
@ -16,6 +16,8 @@
|
||||||
|
|
||||||
package org.springframework.boot.builder;
|
package org.springframework.boot.builder;
|
||||||
|
|
||||||
|
import java.lang.ref.WeakReference;
|
||||||
|
|
||||||
import org.springframework.boot.builder.ParentContextApplicationContextInitializer.ParentContextAvailableEvent;
|
import org.springframework.boot.builder.ParentContextApplicationContextInitializer.ParentContextAvailableEvent;
|
||||||
import org.springframework.context.ApplicationListener;
|
import org.springframework.context.ApplicationListener;
|
||||||
import org.springframework.context.ConfigurableApplicationContext;
|
import org.springframework.context.ConfigurableApplicationContext;
|
||||||
|
|
@ -23,14 +25,13 @@ import org.springframework.context.event.ContextClosedEvent;
|
||||||
import org.springframework.core.Ordered;
|
import org.springframework.core.Ordered;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Listener that closes the application context if its parent is closed. It listens for
|
* Listener that closes the application context if its parent is closed. It listens for refresh events and grabs the
|
||||||
* refresh events and grabs the current context from there, and then listens for closed
|
* current context from there, and then listens for closed events and propagates it down the hierarchy.
|
||||||
* events and propagates it down the hierarchy.
|
|
||||||
*
|
*
|
||||||
* @author Dave Syer
|
* @author Dave Syer
|
||||||
*/
|
*/
|
||||||
public class ParentContextCloserApplicationListener implements
|
public class ParentContextCloserApplicationListener implements ApplicationListener<ParentContextAvailableEvent>,
|
||||||
ApplicationListener<ParentContextAvailableEvent>, Ordered {
|
Ordered {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getOrder() {
|
public int getOrder() {
|
||||||
|
|
@ -38,34 +39,39 @@ public class ParentContextCloserApplicationListener implements
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onApplicationEvent(ParentContextAvailableEvent event) {
|
public final void onApplicationEvent(ParentContextAvailableEvent event) {
|
||||||
maybeInstallListenerInParent(event.getApplicationContext());
|
maybeInstallListenerInParent(event.getApplicationContext());
|
||||||
}
|
}
|
||||||
|
|
||||||
private void maybeInstallListenerInParent(ConfigurableApplicationContext child) {
|
private void maybeInstallListenerInParent(ConfigurableApplicationContext child) {
|
||||||
if (child.getParent() instanceof ConfigurableApplicationContext) {
|
if (child.getParent() instanceof ConfigurableApplicationContext) {
|
||||||
ConfigurableApplicationContext parent = (ConfigurableApplicationContext) child
|
ConfigurableApplicationContext parent = (ConfigurableApplicationContext) child.getParent();
|
||||||
.getParent();
|
parent.addApplicationListener(createContextCloserListener(child));
|
||||||
parent.addApplicationListener(new ContextCloserListener(child));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected static class ContextCloserListener implements
|
/**
|
||||||
ApplicationListener<ContextClosedEvent> {
|
* Subclasses may override to create their own subclass of ContextCloserListener. This still enforces the use of a
|
||||||
|
* weak reference.
|
||||||
|
*/
|
||||||
|
protected ContextCloserListener createContextCloserListener(ConfigurableApplicationContext child) {
|
||||||
|
return new ContextCloserListener(child);
|
||||||
|
}
|
||||||
|
|
||||||
private ConfigurableApplicationContext context;
|
protected static class ContextCloserListener implements ApplicationListener<ContextClosedEvent> {
|
||||||
|
|
||||||
|
private WeakReference<ConfigurableApplicationContext> contextRef;
|
||||||
|
|
||||||
public ContextCloserListener(ConfigurableApplicationContext context) {
|
public ContextCloserListener(ConfigurableApplicationContext context) {
|
||||||
this.context = context;
|
this.contextRef = new WeakReference<ConfigurableApplicationContext>(context);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onApplicationEvent(ContextClosedEvent event) {
|
public void onApplicationEvent(ContextClosedEvent event) {
|
||||||
if (this.context != null
|
ConfigurableApplicationContext context = contextRef.get();
|
||||||
&& event.getApplicationContext() == this.context.getParent()
|
if (context != null && event.getApplicationContext() == context.getParent() && context.isActive()) {
|
||||||
&& this.context.isActive()) {
|
context.close();
|
||||||
this.context.close();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue