DefaultLifecycleProcessor.LifecycleGroup#stop() fails to wait for all members, if there are dependencies between the members.
IMO the problem lies in this loop of LifecycleGroup#stop():
The loop iterates all members. doStop() removes the current member and its dependent members from this.lifecycleBeans and passes a callback to all of them which counts the latch down. This way the latch gets counted down for the current member and its dependent members.
Later on when the iteration reaches one of the dependent members from above, the else block gets executed, because the dependent member has already been removed from this.lifecycleBeans. This counts the latch down again for the dependent member.
This way the latch reaches 0 before all beans called their stop callback and the application context gets destroyed even though some of the members are still running.
I don't understand why the else block is needed at all. IMO it should be simply removed.