New posts for Spring and Hibernate
This commit is contained in:
@@ -0,0 +1,6 @@
|
||||
# HelloApp started with: --greeting=hi --verbose notes.txt
|
||||
|
||||
hello: CommandLineRunner args = [--greeting=hi, --verbose, notes.txt]
|
||||
hello: ApplicationRunner options = [greeting, verbose], non-option args = [notes.txt]
|
||||
hello: ApplicationReadyEvent listener
|
||||
process exit code: 0
|
||||
@@ -0,0 +1,29 @@
|
||||
# Every startup hook in the order Spring Boot 4.1.2 really calls it
|
||||
|
||||
|
||||
--- non-web application ---
|
||||
@PostConstruct
|
||||
InitializingBean.afterPropertiesSet
|
||||
SmartInitializingSingleton.afterSingletonsInstantiated
|
||||
SmartLifecycle.start (default phase)
|
||||
ContextRefreshedEvent
|
||||
ApplicationStartedEvent
|
||||
AvailabilityChangeEvent -> CORRECT
|
||||
CommandLineRunner (readiness seen from inside: REFUSING_TRAFFIC, liveness: CORRECT)
|
||||
ApplicationRunner (readiness seen from inside: REFUSING_TRAFFIC)
|
||||
ApplicationReadyEvent (readiness seen from inside: REFUSING_TRAFFIC)
|
||||
AvailabilityChangeEvent -> ACCEPTING_TRAFFIC
|
||||
|
||||
--- servlet web application (Tomcat on a random port) ---
|
||||
@PostConstruct
|
||||
InitializingBean.afterPropertiesSet
|
||||
SmartInitializingSingleton.afterSingletonsInstantiated
|
||||
WebServerInitializedEvent (port is open)
|
||||
SmartLifecycle.start (default phase)
|
||||
ContextRefreshedEvent
|
||||
ApplicationStartedEvent
|
||||
AvailabilityChangeEvent -> CORRECT
|
||||
CommandLineRunner (readiness seen from inside: REFUSING_TRAFFIC, liveness: CORRECT)
|
||||
ApplicationRunner (readiness seen from inside: REFUSING_TRAFFIC)
|
||||
ApplicationReadyEvent (readiness seen from inside: REFUSING_TRAFFIC)
|
||||
AvailabilityChangeEvent -> ACCEPTING_TRAFFIC
|
||||
@@ -0,0 +1,12 @@
|
||||
# CommandLineRunner and ApplicationRunner beans sorted together by @Order / Ordered
|
||||
|
||||
(declaration order in OrderingApp.java is NOT the order below)
|
||||
|
||||
CommandLineRunner @Order(HIGHEST_PRECEDENCE)
|
||||
ApplicationRunner @Order(1) on the class
|
||||
CommandLineRunner @Order(2) on the class
|
||||
ApplicationRunner implements Ordered, getOrder() = 3
|
||||
Both @Order(4) -> ApplicationRunner.run
|
||||
Both @Order(4) -> CommandLineRunner.run
|
||||
CommandLineRunner @Order(5) on a @Bean method
|
||||
ApplicationRunner no order at all (lowest precedence)
|
||||
@@ -0,0 +1,16 @@
|
||||
# Four runners without @Order: the order chosen by each of 8 fresh JVMs
|
||||
|
||||
JVM 1: arD arB cliC cliA
|
||||
JVM 2: cliC cliA arD arB
|
||||
JVM 3: cliA arB arD cliC
|
||||
JVM 4: arD arB cliC cliA
|
||||
JVM 5: arD arB cliC cliA
|
||||
JVM 6: cliC cliA arB arD
|
||||
JVM 7: cliC cliA arB arD
|
||||
JVM 8: arD arB cliC cliA
|
||||
|
||||
distinct sequences seen: 4
|
||||
arD arB cliC cliA x4
|
||||
cliC cliA arD arB x1
|
||||
cliA arB arD cliC x1
|
||||
cliC cliA arB arD x2
|
||||
@@ -0,0 +1,14 @@
|
||||
# The same command line, seen by CommandLineRunner and ApplicationRunner
|
||||
|
||||
args passed to SpringApplication.run: [--name=Ankur, --verbose, --name=Second, data.csv, -x, --, --after-the-dashes]
|
||||
|
||||
CommandLineRunner String[] args = [--name=Ankur, --verbose, --name=Second, data.csv, -x, --, --after-the-dashes]
|
||||
ApplicationRunner getSourceArgs() = [--name=Ankur, --verbose, --name=Second, data.csv, -x, --, --after-the-dashes]
|
||||
ApplicationRunner getOptionNames() = [name, verbose]
|
||||
ApplicationRunner getOptionValues(name) = [Ankur, Second]
|
||||
ApplicationRunner getOptionValues(verbose) = []
|
||||
ApplicationRunner getOptionValues(missing) = null
|
||||
ApplicationRunner containsOption(verbose) = true
|
||||
ApplicationRunner getNonOptionArgs() = [data.csv, -x, --after-the-dashes]
|
||||
|
||||
Environment property 'name' (both values, joined by a comma): Ankur,Second
|
||||
@@ -0,0 +1,23 @@
|
||||
# A runner throws: exit code, log, events, and the runners that never ran
|
||||
|
||||
|
||||
--- three ordered runners, the second throws (non-web, in a separate JVM) ---
|
||||
TRACE ApplicationStartedEvent
|
||||
TRACE runner 1 ran
|
||||
TRACE runner 2 is about to throw
|
||||
TRACE ApplicationFailedEvent: java.lang.IllegalStateException: boom from runner 2
|
||||
TRACE ContextClosedEvent (the context is shutting down)
|
||||
ERROR o.s.b.SpringApplication : Application run failed
|
||||
java.lang.IllegalStateException: boom from runner 2
|
||||
process exit code: 1
|
||||
|
||||
--- a runner exception that implements ExitCodeGenerator ---
|
||||
ERROR o.s.b.SpringApplication : Application run failed
|
||||
com.ankurm.runners.failure.FailureApp$ExitWith42Exception: the data file is missing
|
||||
process exit code: 42
|
||||
|
||||
--- a runner that throws a checked exception (declared with throws Exception) ---
|
||||
ERROR o.s.b.SpringApplication : Application run failed
|
||||
java.lang.IllegalStateException: Failed to execute CommandLineRunner
|
||||
Caused by: java.io.IOException: cannot read data.csv
|
||||
process exit code: 1
|
||||
@@ -0,0 +1,20 @@
|
||||
# An ApplicationReadyEvent listener throws: the app was 'ready' and is now gone
|
||||
|
||||
|
||||
--- non-web application ---
|
||||
TRACE ApplicationStartedEvent
|
||||
TRACE ready listener 1 is about to throw (readiness: REFUSING_TRAFFIC)
|
||||
TRACE ContextClosedEvent (the context is shutting down)
|
||||
ERROR o.s.b.SpringApplication : Application run failed
|
||||
java.lang.IllegalStateException: boom from the ready listener
|
||||
process exit code: 1
|
||||
|
||||
--- web application (Tomcat is up when the listener runs) ---
|
||||
TRACE ApplicationStartedEvent
|
||||
TRACE GET /ping from inside the listener -> 200 pong
|
||||
TRACE ready listener 1 is about to throw (readiness: REFUSING_TRAFFIC)
|
||||
TRACE ContextClosedEvent (the context is shutting down)
|
||||
ERROR o.s.b.SpringApplication : Application run failed
|
||||
java.lang.IllegalStateException: boom from the ready listener
|
||||
process exit code: 1
|
||||
does the port answer after the process ended? false
|
||||
@@ -0,0 +1,16 @@
|
||||
# A runner that blocks: the port is open, liveness is UP, readiness is OUT_OF_SERVICE
|
||||
|
||||
|
||||
--- while the runner is blocked ---
|
||||
has SpringApplication.run() returned? false
|
||||
GET /ping -> 200 pong
|
||||
GET /actuator/health/liveness -> 200 {"status":"UP"}
|
||||
GET /actuator/health/readiness -> 503 {"status":"OUT_OF_SERVICE"}
|
||||
|
||||
--- after the runner returned ---
|
||||
has SpringApplication.run() returned? true
|
||||
GET /actuator/health/readiness -> 200 {"status":"UP"}
|
||||
|
||||
--- trace ---
|
||||
runner: started on platform thread app-main, now waiting (think: warming a cache for 40 s)
|
||||
runner: finished, returning to SpringApplication.run
|
||||
@@ -0,0 +1,14 @@
|
||||
# A runner that starts a virtual thread and returns: readiness does not wait, and failures do not fail startup
|
||||
|
||||
|
||||
--- the background work is still waiting ---
|
||||
has SpringApplication.run() returned? true
|
||||
GET /actuator/health/readiness -> 200 {"status":"UP"}
|
||||
|
||||
--- after the background work threw ---
|
||||
GET /actuator/health/readiness -> 200 {"status":"UP"}
|
||||
GET /ping -> 200 pong
|
||||
|
||||
--- trace ---
|
||||
runner: started the work on a virtual thread and returned
|
||||
background work on a virtual thread failed: the warm-up blew up
|
||||
@@ -0,0 +1,22 @@
|
||||
# SmartLifecycle: start in ascending phase, stop in descending phase, runners after all of it
|
||||
|
||||
|
||||
--- startup ---
|
||||
start low (phase -100) on main
|
||||
start mid (phase 0) on main
|
||||
start high (phase 100) on main
|
||||
start slow (phase 200) on main
|
||||
ApplicationStartedEvent
|
||||
CommandLineRunner runs
|
||||
ApplicationReadyEvent
|
||||
manual.isAutoStartup()=false isRunning()=false (never started by the context)
|
||||
|
||||
--- context.close() ---
|
||||
start manual (phase 50) on main
|
||||
ContextClosedEvent (stop phase begins)
|
||||
stop slow (phase 200) begins, will finish in 300 ms
|
||||
stop slow finished, calling the callback
|
||||
stop high (phase 100) on main
|
||||
stop manual (phase 50) on main
|
||||
stop mid (phase 0) on main
|
||||
stop low (phase -100) on main
|
||||
@@ -0,0 +1,15 @@
|
||||
# Every SmartLifecycle bean in a servlet web application, by phase (the ones this project adds are marked)
|
||||
|
||||
phase -2147483647 springBootLoggingLifecycle Lifecycle
|
||||
phase -100 low (this project)
|
||||
phase 0 mid (this project)
|
||||
phase 50 manual (this project)
|
||||
phase 100 high (this project)
|
||||
phase 200 slow (this project)
|
||||
phase 1073741823 applicationTaskExecutor ThreadPoolTaskExecutor
|
||||
phase 2147481599 webServerStartStop WebServerStartStopLifecycle
|
||||
phase 2147482623 webServerGracefulShutdown WebServerGracefulShutdownLifecycle
|
||||
SmartLifecycle.DEFAULT_PHASE = 2147483647
|
||||
Integer.MAX_VALUE = 2147483647
|
||||
timeout per shutdown phase = 30000 ms (spring.lifecycle.timeout-per-shutdown-phase, set by Boot)
|
||||
Spring Boot 4.1.2, Spring Framework 7.0.10
|
||||
@@ -0,0 +1,9 @@
|
||||
# SmartLifecycle.start() throws: no ApplicationStartedEvent, no runner
|
||||
|
||||
start healthy (phase 0)
|
||||
start broken (phase 10)
|
||||
stop healthy
|
||||
|
||||
application started? false
|
||||
org.springframework.context.ApplicationContextException: Failed to start bean 'broken'
|
||||
java.lang.IllegalStateException: could not connect to the broker
|
||||
@@ -0,0 +1,6 @@
|
||||
# isRunning() always false: start() is called, stop() never is
|
||||
|
||||
--- startup ---
|
||||
start() was called
|
||||
--- after context.close() ---
|
||||
(nothing)
|
||||
@@ -0,0 +1,6 @@
|
||||
# @SpringBootTest(classes = SlicesApp.class, args = "--from-the-test=1"): what ran before the first test method
|
||||
|
||||
CommandLineRunner from a top-level @Component ran, args = [--from-the-test=1]
|
||||
CommandLineRunner nested in SlicesApp ran, args = [--from-the-test=1]
|
||||
ApplicationRunner from a @Bean method ran, source args = [--from-the-test=1]
|
||||
ApplicationReadyEvent listener (a top-level @Component) ran
|
||||
@@ -0,0 +1,4 @@
|
||||
# @WebMvcTest(controllers = Hello.class): what ran before the first test method
|
||||
|
||||
CommandLineRunner nested in SlicesApp ran, args = []
|
||||
ApplicationRunner from a @Bean method ran, source args = []
|
||||
@@ -0,0 +1,81 @@
|
||||
# Spring Boot 4.1.2 sources: the order SpringApplication.run() calls things in, and callRunners
|
||||
|
||||
--- SpringApplication.run(): from refresh to ready (lines containing the calls) ---
|
||||
18: refreshContext(context);
|
||||
19: afterRefresh(context, applicationArguments);
|
||||
24: listeners.started(context, timeTakenToStarted);
|
||||
25: callRunners(context, applicationArguments);
|
||||
28: throw handleRunFailure(context, ex, listeners);
|
||||
32: listeners.ready(context, startup.ready());
|
||||
36: throw handleRunFailure(context, ex, null);
|
||||
|
||||
--- SpringApplication.callRunners ---
|
||||
private void callRunners(ConfigurableApplicationContext context, ApplicationArguments args) {
|
||||
ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
|
||||
String[] beanNames = beanFactory.getBeanNamesForType(Runner.class);
|
||||
Map<Runner, String> instancesToBeanNames = new IdentityHashMap<>();
|
||||
for (String beanName : beanNames) {
|
||||
instancesToBeanNames.put(beanFactory.getBean(beanName, Runner.class), beanName);
|
||||
}
|
||||
Comparator<Object> comparator = getOrderComparator(beanFactory)
|
||||
.withSourceProvider(new FactoryAwareOrderSourceProvider(beanFactory, instancesToBeanNames));
|
||||
instancesToBeanNames.keySet().stream().sorted(comparator).forEach((runner) -> callRunner(runner, args));
|
||||
}
|
||||
|
||||
--- SpringApplication.callRunner (what happens to a bean that is both kinds) ---
|
||||
private void callRunner(Runner runner, ApplicationArguments args) {
|
||||
if (runner instanceof ApplicationRunner) {
|
||||
callRunner(ApplicationRunner.class, runner, (applicationRunner) -> applicationRunner.run(args));
|
||||
}
|
||||
if (runner instanceof CommandLineRunner) {
|
||||
callRunner(CommandLineRunner.class, runner,
|
||||
(commandLineRunner) -> commandLineRunner.run(args.getSourceArgs()));
|
||||
}
|
||||
}
|
||||
|
||||
--- SpringApplication.callRunner(Class, Runner, ThrowingConsumer) (where 'Failed to execute' comes from) ---
|
||||
private <R extends Runner> void callRunner(Class<R> type, Runner runner, ThrowingConsumer<R> call) {
|
||||
call.throwing(
|
||||
(message, ex) -> new IllegalStateException("Failed to execute " + ClassUtils.getShortName(type), ex))
|
||||
.accept((R) runner);
|
||||
}
|
||||
|
||||
--- EventPublishingRunListener.started / ready ---
|
||||
public void started(ConfigurableApplicationContext context, @Nullable Duration timeTaken) {
|
||||
context.publishEvent(new ApplicationStartedEvent(this.application, this.args, context, timeTaken));
|
||||
AvailabilityChangeEvent.publish(context, LivenessState.CORRECT);
|
||||
}
|
||||
public void ready(ConfigurableApplicationContext context, @Nullable Duration timeTaken) {
|
||||
context.publishEvent(new ApplicationReadyEvent(this.application, this.args, context, timeTaken));
|
||||
AvailabilityChangeEvent.publish(context, ReadinessState.ACCEPTING_TRAFFIC);
|
||||
}
|
||||
|
||||
--- the marker interface that both runners extend ---
|
||||
interface Runner {
|
||||
public interface CommandLineRunner extends Runner {
|
||||
public interface ApplicationRunner extends Runner {
|
||||
|
||||
--- the same method in Spring Boot 3.0.13 ---
|
||||
private void callRunners(ApplicationContext context, ApplicationArguments args) {
|
||||
context.getBeanProvider(Runner.class).orderedStream().forEach((runner) -> {
|
||||
if (runner instanceof ApplicationRunner applicationRunner) {
|
||||
callRunner(applicationRunner, args);
|
||||
}
|
||||
if (runner instanceof CommandLineRunner commandLineRunner) {
|
||||
callRunner(commandLineRunner, args);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
--- the same method in Spring Boot 3.1.12 ---
|
||||
private void callRunners(ConfigurableApplicationContext context, ApplicationArguments args) {
|
||||
ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
|
||||
String[] beanNames = beanFactory.getBeanNamesForType(Runner.class);
|
||||
Map<Runner, String> instancesToBeanNames = new IdentityHashMap<>();
|
||||
for (String beanName : beanNames) {
|
||||
instancesToBeanNames.put(beanFactory.getBean(beanName, Runner.class), beanName);
|
||||
}
|
||||
Comparator<Object> comparator = getOrderComparator(beanFactory)
|
||||
.withSourceProvider(new FactoryAwareOrderSourceProvider(beanFactory, instancesToBeanNames));
|
||||
instancesToBeanNames.keySet().stream().sorted(comparator).forEach((runner) -> callRunner(runner, args));
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
# javap -p -c on spring-boot-4.1.2.jar: the compiled SpringApplication.callRunners
|
||||
|
||||
--- javap -p org.springframework.boot.Runner / CommandLineRunner / ApplicationRunner ---
|
||||
Compiled from "Runner.java"
|
||||
interface org.springframework.boot.Runner {
|
||||
}
|
||||
Compiled from "CommandLineRunner.java"
|
||||
public interface org.springframework.boot.CommandLineRunner extends org.springframework.boot.Runner {
|
||||
public abstract void run(java.lang.String...) throws java.lang.Exception;
|
||||
}
|
||||
Compiled from "ApplicationRunner.java"
|
||||
public interface org.springframework.boot.ApplicationRunner extends org.springframework.boot.Runner {
|
||||
public abstract void run(org.springframework.boot.ApplicationArguments) throws java.lang.Exception;
|
||||
}
|
||||
|
||||
--- invoke* instructions inside callRunners ---
|
||||
invokeinterface #393, 1 // InterfaceMethod org/springframework/context/ConfigurableApplicationContext.getBeanFactory:()Lorg/springframework/beans/factory/config/ConfigurableListableBeanFactory;
|
||||
invokeinterface #966, 2 // InterfaceMethod org/springframework/beans/factory/config/ConfigurableListableBeanFactory.getBeanNamesForType:(Ljava/lang/Class;)[Ljava/lang/String;
|
||||
new #970 // class java/util/IdentityHashMap
|
||||
invokespecial #972 // Method java/util/IdentityHashMap."<init>":()V
|
||||
invokeinterface #973, 3 // InterfaceMethod org/springframework/beans/factory/config/ConfigurableListableBeanFactory.getBean:(Ljava/lang/String;Ljava/lang/Class;)Ljava/lang/Object;
|
||||
invokeinterface #977, 3 // InterfaceMethod java/util/Map.put:(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
|
||||
invokevirtual #983 // Method getOrderComparator:(Lorg/springframework/beans/factory/config/ConfigurableListableBeanFactory;)Lorg/springframework/core/OrderComparator;
|
||||
new #987 // class org/springframework/boot/SpringApplication$FactoryAwareOrderSourceProvider
|
||||
invokespecial #989 // Method org/springframework/boot/SpringApplication$FactoryAwareOrderSourceProvider."<init>":(Lorg/springframework/beans/factory/config/ConfigurableBeanFactory;Ljava/util/Map;)V
|
||||
invokevirtual #992 // Method org/springframework/core/OrderComparator.withSourceProvider:(Lorg/springframework/core/OrderComparator$OrderSourceProvider;)Ljava/util/Comparator;
|
||||
invokeinterface #998, 1 // InterfaceMethod java/util/Map.keySet:()Ljava/util/Set;
|
||||
invokeinterface #1001, 1 // InterfaceMethod java/util/Set.stream:()Ljava/util/stream/Stream;
|
||||
invokeinterface #1002, 2 // InterfaceMethod java/util/stream/Stream.sorted:(Ljava/util/Comparator;)Ljava/util/stream/Stream;
|
||||
invokedynamic #1006, 0 // InvokeDynamic #12:accept:(Lorg/springframework/boot/SpringApplication;Lorg/springframework/boot/ApplicationArguments;)Ljava/util/function/Consumer;
|
||||
invokeinterface #1009, 2 // InterfaceMethod java/util/stream/Stream.forEach:(Ljava/util/function/Consumer;)V
|
||||
@@ -0,0 +1,97 @@
|
||||
# spring-context 7.0.10 sources: DefaultLifecycleProcessor, the object that starts and stops SmartLifecycle beans
|
||||
|
||||
--- doStart: start() is called only when isRunning() is false ---
|
||||
private void doStart(Map<String, ? extends Lifecycle> lifecycleBeans, String beanName,
|
||||
boolean autoStartupOnly, @Nullable List<CompletableFuture<?>> futures) {
|
||||
|
||||
Lifecycle bean = lifecycleBeans.remove(beanName);
|
||||
if (bean != null && bean != this) {
|
||||
String[] dependenciesForBean = getBeanFactory().getDependenciesForBean(beanName);
|
||||
for (String dependency : dependenciesForBean) {
|
||||
doStart(lifecycleBeans, dependency, autoStartupOnly, futures);
|
||||
}
|
||||
if (!bean.isRunning() && (!autoStartupOnly || toBeStarted(beanName, bean))) {
|
||||
if (futures != null) {
|
||||
futures.add(CompletableFuture.runAsync(() -> doStart(beanName, bean), getBootstrapExecutor()));
|
||||
}
|
||||
else {
|
||||
doStart(beanName, bean);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
--- doStop: stop() is called only when isRunning() is true ---
|
||||
private void doStop(Map<String, ? extends Lifecycle> lifecycleBeans, final String beanName,
|
||||
boolean pauseableOnly, final CountDownLatch latch, final Set<String> countDownBeanNames) {
|
||||
|
||||
Lifecycle bean = lifecycleBeans.remove(beanName);
|
||||
if (bean != null) {
|
||||
String[] dependentBeans = getBeanFactory().getDependentBeans(beanName);
|
||||
for (String dependentBean : dependentBeans) {
|
||||
doStop(lifecycleBeans, dependentBean, pauseableOnly, latch, countDownBeanNames);
|
||||
}
|
||||
try {
|
||||
if (bean.isRunning()) {
|
||||
Set<String> stoppedBeans = this.stoppedBeans;
|
||||
if (stoppedBeans != null) {
|
||||
stoppedBeans.add(beanName);
|
||||
}
|
||||
if (bean instanceof SmartLifecycle smartLifecycle) {
|
||||
if (!pauseableOnly || smartLifecycle.isPauseable()) {
|
||||
if (logger.isTraceEnabled()) {
|
||||
logger.trace("Asking bean '" + beanName + "' of type [" +
|
||||
bean.getClass().getName() + "] to stop");
|
||||
}
|
||||
countDownBeanNames.add(beanName);
|
||||
smartLifecycle.stop(() -> {
|
||||
latch.countDown();
|
||||
countDownBeanNames.remove(beanName);
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Bean '" + beanName + "' completed its stop procedure");
|
||||
}
|
||||
});
|
||||
}
|
||||
else {
|
||||
// Don't wait for beans that aren't pauseable...
|
||||
latch.countDown();
|
||||
}
|
||||
}
|
||||
else if (!pauseableOnly) {
|
||||
if (logger.isTraceEnabled()) {
|
||||
logger.trace("Stopping bean '" + beanName + "' of type [" +
|
||||
bean.getClass().getName() + "]");
|
||||
}
|
||||
bean.stop();
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Successfully stopped bean '" + beanName + "'");
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (bean instanceof SmartLifecycle) {
|
||||
// Don't wait for beans that aren't running...
|
||||
latch.countDown();
|
||||
}
|
||||
}
|
||||
catch (Throwable ex) {
|
||||
if (logger.isWarnEnabled()) {
|
||||
logger.warn("Failed to stop bean '" + beanName + "'", ex);
|
||||
}
|
||||
if (bean instanceof SmartLifecycle) {
|
||||
latch.countDown();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
--- isAutoStartupCandidate / toBeStarted: what isAutoStartup() decides ---
|
||||
private boolean isAutoStartupCandidate(String beanName, Lifecycle bean) {
|
||||
Set<String> stoppedBeans = this.stoppedBeans;
|
||||
return (stoppedBeans != null ? stoppedBeans.contains(beanName) :
|
||||
(bean instanceof SmartLifecycle smartLifecycle && smartLifecycle.isAutoStartup()));
|
||||
}
|
||||
private boolean toBeStarted(String beanName, Lifecycle bean) {
|
||||
Set<String> stoppedBeans = this.stoppedBeans;
|
||||
return (stoppedBeans != null ? stoppedBeans.contains(beanName) :
|
||||
(!(bean instanceof SmartLifecycle smartLifecycle) || smartLifecycle.isAutoStartup()));
|
||||
}
|
||||
Reference in New Issue
Block a user