/*
* Copyright 2012-2019 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.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
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;
import org.springframework.core.Ordered;
import org.springframework.util.ObjectUtils;
Listener that closes the application context if its parent is closed. It listens for
refresh events and grabs the current context from there, and then listens for closed
events and propagates it down the hierarchy.
Author: Dave Syer, Eric Bottard Since: 1.0.0
/**
* Listener that closes the application context if its parent is closed. It listens for
* refresh events and grabs the current context from there, and then listens for closed
* events and propagates it down the hierarchy.
*
* @author Dave Syer
* @author Eric Bottard
* @since 1.0.0
*/
public class ParentContextCloserApplicationListener
implements ApplicationListener<ParentContextAvailableEvent>, ApplicationContextAware, Ordered {
private int order = Ordered.LOWEST_PRECEDENCE - 10;
private ApplicationContext context;
@Override
public int getOrder() {
return this.order;
}
@Override
public void setApplicationContext(ApplicationContext context) throws BeansException {
this.context = context;
}
@Override
public void onApplicationEvent(ParentContextAvailableEvent event) {
maybeInstallListenerInParent(event.getApplicationContext());
}
private void maybeInstallListenerInParent(ConfigurableApplicationContext child) {
if (child == this.context && child.getParent() instanceof ConfigurableApplicationContext) {
ConfigurableApplicationContext parent = (ConfigurableApplicationContext) child.getParent();
parent.addApplicationListener(createContextCloserListener(child));
}
}
Subclasses may override to create their own subclass of ContextCloserListener. This
still enforces the use of a weak reference.
Params: - child – the child context
Returns: the ContextCloserListener
to use
/**
* Subclasses may override to create their own subclass of ContextCloserListener. This
* still enforces the use of a weak reference.
* @param child the child context
* @return the {@link ContextCloserListener} to use
*/
protected ContextCloserListener createContextCloserListener(ConfigurableApplicationContext child) {
return new ContextCloserListener(child);
}
ApplicationListener
to close the context. /**
* {@link ApplicationListener} to close the context.
*/
protected static class ContextCloserListener implements ApplicationListener<ContextClosedEvent> {
private WeakReference<ConfigurableApplicationContext> childContext;
public ContextCloserListener(ConfigurableApplicationContext childContext) {
this.childContext = new WeakReference<>(childContext);
}
@Override
public void onApplicationEvent(ContextClosedEvent event) {
ConfigurableApplicationContext context = this.childContext.get();
if ((context != null) && (event.getApplicationContext() == context.getParent()) && context.isActive()) {
context.close();
}
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (obj instanceof ContextCloserListener) {
ContextCloserListener other = (ContextCloserListener) obj;
return ObjectUtils.nullSafeEquals(this.childContext.get(), other.childContext.get());
}
return super.equals(obj);
}
@Override
public int hashCode() {
return ObjectUtils.nullSafeHashCode(this.childContext.get());
}
}
}