From 999748bdabe1005dd6cfcb012eb7f2eae9df8e06 Mon Sep 17 00:00:00 2001 From: Dave Syer Date: Tue, 24 Jun 2014 14:31:22 +0100 Subject: [PATCH] Fix some sloppy code in context hierarchy support * The SpringApplicationBuilder was registering the parent context initializer twice (not really a problem, but confusing if you are debugging). * ParentContextApplicationContextInitializer itself should have been checking that the current context is not the parent * The EventPublishingRunListener as a result needs to call setApplicationContext on any listeners that are AplicationContextAware * ParentContextCloserApplicationListener can ensure that there is only one of its kind per application context by implementing hashCode and equals Fixes gh-1142 --- ...tContextApplicationContextInitializer.java | 9 ++- ...arentContextCloserApplicationListener.java | 56 +++++++++++++++++-- .../builder/SpringApplicationBuilder.java | 1 - .../event/EventPublishingRunListener.java | 4 ++ 4 files changed, 60 insertions(+), 10 deletions(-) diff --git a/spring-boot/src/main/java/org/springframework/boot/builder/ParentContextApplicationContextInitializer.java b/spring-boot/src/main/java/org/springframework/boot/builder/ParentContextApplicationContextInitializer.java index 97a77bcf7b5..edaa399bbf2 100644 --- a/spring-boot/src/main/java/org/springframework/boot/builder/ParentContextApplicationContextInitializer.java +++ b/spring-boot/src/main/java/org/springframework/boot/builder/ParentContextApplicationContextInitializer.java @@ -53,8 +53,10 @@ public class ParentContextApplicationContextInitializer implements @Override public void initialize(ConfigurableApplicationContext applicationContext) { - applicationContext.setParent(this.parent); - applicationContext.addApplicationListener(EventPublisher.INSTANCE); + if (applicationContext != this.parent) { + applicationContext.setParent(this.parent); + applicationContext.addApplicationListener(EventPublisher.INSTANCE); + } } private static class EventPublisher implements @@ -70,7 +72,8 @@ public class ParentContextApplicationContextInitializer implements @Override public void onApplicationEvent(ContextRefreshedEvent event) { ApplicationContext context = event.getApplicationContext(); - if (context instanceof ConfigurableApplicationContext) { + if (context instanceof ConfigurableApplicationContext + && context == event.getSource()) { context.publishEvent(new ParentContextAvailableEvent( (ConfigurableApplicationContext) context)); } diff --git a/spring-boot/src/main/java/org/springframework/boot/builder/ParentContextCloserApplicationListener.java b/spring-boot/src/main/java/org/springframework/boot/builder/ParentContextCloserApplicationListener.java index bb26b38fe9a..271943e1bf7 100644 --- a/spring-boot/src/main/java/org/springframework/boot/builder/ParentContextCloserApplicationListener.java +++ b/spring-boot/src/main/java/org/springframework/boot/builder/ParentContextCloserApplicationListener.java @@ -18,7 +18,10 @@ package org.springframework.boot.builder; import java.lang.ref.WeakReference; +import org.springframework.beans.BeansException; import org.springframework.boot.builder.ParentContextApplicationContextInitializer.ParentContextAvailableEvent; +import org.springframework.context.ApplicationContext; +import org.springframework.context.ApplicationContextAware; import org.springframework.context.ApplicationListener; import org.springframework.context.ConfigurableApplicationContext; import org.springframework.context.event.ContextClosedEvent; @@ -33,11 +36,21 @@ import org.springframework.core.Ordered; * @author Eric Bottard */ public class ParentContextCloserApplicationListener implements - ApplicationListener, Ordered { + ApplicationListener, ApplicationContextAware, + Ordered { + + private int order = Ordered.LOWEST_PRECEDENCE - 10; + + private ApplicationContext context; @Override public int getOrder() { - return Ordered.LOWEST_PRECEDENCE - 10; + return this.order; + } + + @Override + public void setApplicationContext(ApplicationContext context) throws BeansException { + this.context = context; } @Override @@ -46,10 +59,12 @@ public class ParentContextCloserApplicationListener implements } private void maybeInstallListenerInParent(ConfigurableApplicationContext child) { - if (child.getParent() instanceof ConfigurableApplicationContext) { - ConfigurableApplicationContext parent = (ConfigurableApplicationContext) child - .getParent(); - parent.addApplicationListener(createContextCloserListener(child)); + if (child == this.context) { + if (child.getParent() instanceof ConfigurableApplicationContext) { + ConfigurableApplicationContext parent = (ConfigurableApplicationContext) child + .getParent(); + parent.addApplicationListener(createContextCloserListener(child)); + } } } @@ -82,6 +97,35 @@ public class ParentContextCloserApplicationListener implements } } + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime + * result + + ((this.childContext.get() == null) ? 0 : this.childContext.get() + .hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + ContextCloserListener other = (ContextCloserListener) obj; + if (this.childContext.get() == null) { + if (other.childContext.get() != null) + return false; + } + else if (!this.childContext.get().equals(other.childContext.get())) + return false; + return true; + } + } } diff --git a/spring-boot/src/main/java/org/springframework/boot/builder/SpringApplicationBuilder.java b/spring-boot/src/main/java/org/springframework/boot/builder/SpringApplicationBuilder.java index 5aca2719815..a4caea8b149 100644 --- a/spring-boot/src/main/java/org/springframework/boot/builder/SpringApplicationBuilder.java +++ b/spring-boot/src/main/java/org/springframework/boot/builder/SpringApplicationBuilder.java @@ -215,7 +215,6 @@ public class SpringApplicationBuilder { this.parent = new SpringApplicationBuilder(); this.parent.context = parent; this.parent.running.set(true); - initializers(new ParentContextApplicationContextInitializer(parent)); return this; } diff --git a/spring-boot/src/main/java/org/springframework/boot/context/event/EventPublishingRunListener.java b/spring-boot/src/main/java/org/springframework/boot/context/event/EventPublishingRunListener.java index 96240c4622c..fc064447158 100644 --- a/spring-boot/src/main/java/org/springframework/boot/context/event/EventPublishingRunListener.java +++ b/spring-boot/src/main/java/org/springframework/boot/context/event/EventPublishingRunListener.java @@ -19,6 +19,7 @@ package org.springframework.boot.context.event; import org.springframework.beans.factory.BeanFactoryAware; import org.springframework.boot.SpringApplication; import org.springframework.boot.SpringApplicationRunListener; +import org.springframework.context.ApplicationContextAware; import org.springframework.context.ApplicationListener; import org.springframework.context.ConfigurableApplicationContext; import org.springframework.context.event.ApplicationEventMulticaster; @@ -78,6 +79,9 @@ public class EventPublishingRunListener implements SpringApplicationRunListener @Override public void contextLoaded(ConfigurableApplicationContext context) { for (ApplicationListener listener : this.application.getListeners()) { + if (listener instanceof ApplicationContextAware) { + ((ApplicationContextAware) listener).setApplicationContext(context); + } context.addApplicationListener(listener); } publishEvent(new ApplicationPreparedEvent(this.application, this.args, context));