-
Notifications
You must be signed in to change notification settings - Fork 13
Description
Hi,
Another edge case! As part of our applications, we use netflix-archaius for dynamic configuration at runtime - in this case, to control whether a queue listener is enabled or not, and to change if needed.
To do this, I have extended the DefaultMessageListenerContainerCoordinator to accept a small properties holder class that is used to determine the value of isAutoStartup, and add callbacks to properties to call start|stopContainer(identifier) to try and match the pattern used for creating other containers etc -
interface MessageListenerContainerCoordinatorProperties {
/**
* @return Whether the {@link MessageListenerContainerCoordinator}'s {@link MessageListenerContainerCoordinator#startAllContainers()} will be invoked by Spring.
*/
boolean isAutoStartContainersEnabled();
}
@Value
@Builder(toBuilder = true)
class DefaultMessageListenerContainerCoordinatorProperties implements MessageListenerContainerCoordinatorProperties {
Boolean isAutoStartContainersEnabled;
@Override
public boolean isAutoStartContainersEnabled() {
return isAutoStartContainersEnabled;
}
}
class ExtendedDefaultMessageListenerContainerCoordinator extends DefaultMessageListenerContainerCoordinator {
private final MessageListenerContainerCoordinatorProperties properties;
public ExtendedDefaultMessageListenerContainerCoordinator(final List<MessageListenerContainerFactory> factories, final MessageListenerContainerCoordinatorProperties properties) {
super(factories);
this.properties = properties;
}
// Used to get a list of all containers so we can build the property callbacks...
public Collection<String> getContainerIdentifiers() {
return getContainers().stream()
.map(MessageListenerContainer::getIdentifier)
.collect(toUnmodifiableSet());
}
@Override
public boolean isAutoStartup() {
return properties.isAutoStartContainersEnabled();
}
}
class MessageListenerContainerLifecycleController implements SmartLifecycle {
private final DefaultMessageListenerContainerCoordinator coordinator;
private final Map<String, DynamicBooleanProperty> containerEnabled;
public MessageListenerContainerLifecycleController(final DefaultMessageListenerContainerCoordinator coordinator) {
this.coordinator = coordinator;
/**
* Create all the properties and callbacks for each container identifier returned from
* {@link ExtendedDefaultMessageListenerContainerCoordinator#getContainerIdentifiers()} on each to invoke the
* @{@link MessageListenerContainerCoordinator#startContainer(String)} or
* @{@link MessageListenerContainerCoordinator#stopContainer(String)}} depending on the value...
*/
this.containerEnabled = createContainerLifecycleCallbacks(coordinator);
}
@Override
public void start() {
containerEnabled.forEach((identifier, enabled) -> {
if (enabled.getValue()) {
coordinator.startContainer(identifier);
}
});
}
@Override
public void stop() {
coordinator.stopAllContainers();
}
@Override
public boolean isRunning() {}
}Another tweak that would help is being able to return a collection of all identifiers if possible 😄 Currently I have these classes sitting under the same package as the original to access the getContainers() method - other than this the library does everything I needed and more, nice to get a consumer going with a few annotations!
If there is a better way to raise these let me know - technically this is not an issue or bug!