Stop already started Lifecycle beans on cancelled refresh

Closes gh-35964
This commit is contained in:
Juergen Hoeller
2025-12-05 16:14:27 +01:00
parent 196c1dd51c
commit c74af40288
4 changed files with 111 additions and 10 deletions
@@ -18,17 +18,25 @@ package org.springframework.context.support;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.core.io.ClassPathResource;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatIllegalStateException;
/**
* @author Mark Fisher
* @author Chris Beams
* @author Juergen Hoeller
*/
class ApplicationContextLifecycleTests {
@Test
void beansStart() {
AbstractApplicationContext context = new ClassPathXmlApplicationContext("lifecycleTests.xml", getClass());
context.start();
LifecycleTestBean bean1 = (LifecycleTestBean) context.getBean("bean1");
LifecycleTestBean bean2 = (LifecycleTestBean) context.getBean("bean2");
@@ -39,12 +47,14 @@ class ApplicationContextLifecycleTests {
assertThat(bean2.isRunning()).as(error).isTrue();
assertThat(bean3.isRunning()).as(error).isTrue();
assertThat(bean4.isRunning()).as(error).isTrue();
context.close();
}
@Test
void beansStop() {
AbstractApplicationContext context = new ClassPathXmlApplicationContext("lifecycleTests.xml", getClass());
context.start();
LifecycleTestBean bean1 = (LifecycleTestBean) context.getBean("bean1");
LifecycleTestBean bean2 = (LifecycleTestBean) context.getBean("bean2");
@@ -55,18 +65,21 @@ class ApplicationContextLifecycleTests {
assertThat(bean2.isRunning()).as(startError).isTrue();
assertThat(bean3.isRunning()).as(startError).isTrue();
assertThat(bean4.isRunning()).as(startError).isTrue();
context.stop();
String stopError = "bean was not stopped";
assertThat(bean1.isRunning()).as(stopError).isFalse();
assertThat(bean2.isRunning()).as(stopError).isFalse();
assertThat(bean3.isRunning()).as(stopError).isFalse();
assertThat(bean4.isRunning()).as(stopError).isFalse();
context.close();
}
@Test
void startOrder() {
AbstractApplicationContext context = new ClassPathXmlApplicationContext("lifecycleTests.xml", getClass());
context.start();
LifecycleTestBean bean1 = (LifecycleTestBean) context.getBean("bean1");
LifecycleTestBean bean2 = (LifecycleTestBean) context.getBean("bean2");
@@ -81,18 +94,22 @@ class ApplicationContextLifecycleTests {
assertThat(bean2.getStartOrder()).as(orderError).isGreaterThan(bean1.getStartOrder());
assertThat(bean3.getStartOrder()).as(orderError).isGreaterThan(bean2.getStartOrder());
assertThat(bean4.getStartOrder()).as(orderError).isGreaterThan(bean2.getStartOrder());
context.close();
}
@Test
void stopOrder() {
AbstractApplicationContext context = new ClassPathXmlApplicationContext("lifecycleTests.xml", getClass());
context.start();
context.stop();
LifecycleTestBean bean1 = (LifecycleTestBean) context.getBean("bean1");
LifecycleTestBean bean2 = (LifecycleTestBean) context.getBean("bean2");
LifecycleTestBean bean3 = (LifecycleTestBean) context.getBean("bean3");
LifecycleTestBean bean4 = (LifecycleTestBean) context.getBean("bean4");
void autoStartup() {
GenericApplicationContext context = new GenericApplicationContext();
new XmlBeanDefinitionReader(context).loadBeanDefinitions(new ClassPathResource("smartLifecycleTests.xml", getClass()));
context.refresh();
LifecycleTestBean bean1 = (LifecycleTestBean) context.getBeanFactory().getBean("bean1");
LifecycleTestBean bean2 = (LifecycleTestBean) context.getBeanFactory().getBean("bean2");
LifecycleTestBean bean3 = (LifecycleTestBean) context.getBeanFactory().getBean("bean3");
LifecycleTestBean bean4 = (LifecycleTestBean) context.getBeanFactory().getBean("bean4");
context.close();
String notStoppedError = "bean was not stopped";
assertThat(bean1.getStopOrder()).as(notStoppedError).isGreaterThan(0);
assertThat(bean2.getStopOrder()).as(notStoppedError).isGreaterThan(0);
@@ -102,7 +119,36 @@ class ApplicationContextLifecycleTests {
assertThat(bean2.getStopOrder()).as(orderError).isLessThan(bean1.getStopOrder());
assertThat(bean3.getStopOrder()).as(orderError).isLessThan(bean2.getStopOrder());
assertThat(bean4.getStopOrder()).as(orderError).isLessThan(bean2.getStopOrder());
context.close();
}
@Test
void cancelledRefresh() {
GenericApplicationContext context = new GenericApplicationContext();
new XmlBeanDefinitionReader(context).loadBeanDefinitions(new ClassPathResource("smartLifecycleTests.xml", getClass()));
context.registerBean(FailingContextRefreshedListener.class);
LifecycleTestBean bean1 = (LifecycleTestBean) context.getBeanFactory().getBean("bean1");
LifecycleTestBean bean2 = (LifecycleTestBean) context.getBeanFactory().getBean("bean2");
LifecycleTestBean bean3 = (LifecycleTestBean) context.getBeanFactory().getBean("bean3");
LifecycleTestBean bean4 = (LifecycleTestBean) context.getBeanFactory().getBean("bean4");
assertThatIllegalStateException().isThrownBy(context::refresh);
String notStoppedError = "bean was not stopped";
assertThat(bean1.getStopOrder()).as(notStoppedError).isGreaterThan(0);
assertThat(bean2.getStopOrder()).as(notStoppedError).isGreaterThan(0);
assertThat(bean3.getStopOrder()).as(notStoppedError).isGreaterThan(0);
assertThat(bean4.getStopOrder()).as(notStoppedError).isGreaterThan(0);
String orderError = "dependent bean must stop before the bean it depends on";
assertThat(bean2.getStopOrder()).as(orderError).isLessThan(bean1.getStopOrder());
assertThat(bean3.getStopOrder()).as(orderError).isLessThan(bean2.getStopOrder());
assertThat(bean4.getStopOrder()).as(orderError).isLessThan(bean2.getStopOrder());
}
private static class FailingContextRefreshedListener implements ApplicationListener<ContextRefreshedEvent> {
public void onApplicationEvent(ContextRefreshedEvent event) {
throw new IllegalStateException();
}
}
}
@@ -0,0 +1,26 @@
/*
* Copyright 2002-present 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.context.support;
import org.springframework.context.SmartLifecycle;
/**
* @author Juergen Hoeller
*/
public class SmartLifecycleTestBean extends LifecycleTestBean implements SmartLifecycle {
}