# 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()));
	}
