文章目录




一、前言


本文概要:
学习方法:以六个方法为根本,一个个去看
模拟到实践,模拟的六个方法,实践的六个方法



涉及的类:AbstractApplicationContext、DefaultLifecycleProcessor、ApplicationListenerDetector、SmartLifecycle和CountDownLatch,前三个很重要,后面两个稍微涉及而已。

金手指:我们实现SmartLifeCycle接口并在这个类上加上@Component注解


本章由以下几部分组成:


  1. SmartLifecycle 6个方法;
  2. spring容器启动与SmartLifecycle的关系;
  3. spring容器关闭与SmartLifecycle的关系;
  4. 关于Lifecycle和SmartLifecycle;

二、SmartLifecycle接口 6个方法

先来看看SmartLifecycle接口的类图:

生命周期,探秘Spring容器的SmartLifecycle接口_spring

如上图所示,在继承了Lifecycle和Phased两个接口后,SmartLifecycle一共定义了六个方法,为了便于后面的源码分析,先做个简介:

方法

作用

start()

bean初始化完毕后,该方法会被执行(实际:,模拟:加一句打印就好了)

stop()

分为两种情况,如果当前对象实现了SmartLifecycle,就调用stop(Runnable);如果只是实现了Lifecycle,就调用stop()

isRunning()

当前状态

getPhase()

返回值决定start方法在众多Lifecycle实现类中的执行顺序(stop也是)

isAutoStartup()

start方法被执行前先看此方法返回值,返回false就不执行start方法了

stop(Runnable)

分为两种情况,如果当前对象实现了SmartLifecycle,就调用stop(Runnable);如果只是实现了Lifecycle,就调用stop()


这个六个方法的全文的主线:
1、要看这六个方法在源码中是怎样搞的;源码中什么位置调用
2、要看着六个方法在自定义模拟接口实现SmartLifeCycle是怎么搞的;模拟中如何模拟


从上述列举中可以看出,感知容器变化的能力最终来自Lifecycle,而SmartLifecycle只是Lifecycle的增强版,可以自定义优先级(getPhase),自主决定是否随容器启动(isAutoStartup),以及停止时能接受一个runnable对象(stop(Runnable));

三、启动:spring容器启动与SmartLifecycle的关系

现在可以结合spring源码来看看SmartLifecycle的使用场景,从spring容器初始化看起;

3.1 AbstractApplicationContext类的refresh()方法

起手式, AbstractApplicationContext类的refresh方法中,在bean的实例化和初始化操作完毕后,会调用finishRefresh方法,如下图红框所示:

生命周期,探秘Spring容器的SmartLifecycle接口_自定义_02

3.2 refresh()中的finishRefresh()方法

接上面,finishRefresh方法内容如下,中文注释对每个方法做了简介:

protected void finishRefresh() {
// LifecycleProcessor实例初始化,
// LifecycleProcessor是所有Lifecycle实现类的管家,里面包含了对Lifecycle的各种操作.
initLifecycleProcessor();

// 通过LifecycleProcessor来执行Lifecycle实现类的start方法
getLifecycleProcessor().onRefresh();

// 向监听器发送广播,消息类型是ContextRefreshedEvent
publishEvent(new ContextRefreshedEvent(this));

// 如果配置了MBeanServer,就完成在MBeanServer上的注册
LiveBeansView.registerApplicationContext(this);
}

上述代码中,initLifecycleProcessor()和getLifecycleProcessor().onRefresh()这两个方法和本章的主题有关,其他两个就不在本章展开了,我们从initLifecycleProcessor开始看起吧;


金手指:
如何执行实现了SmartLifeCycle接口,Spring实际执行
生命周期,探秘Spring容器的SmartLifecycle接口_初始化_03


3.3 finishRefresh()中的initLifecycleProcessor()方法

接上面,initLifecycleProcessor方法的作用是为applicationContext的成员变量lifecycleProcessor赋值,如果已有名为”lifecycleProcessor”的bean,lifecycleProcessor就等于这个bean,否则就实例化一个DefaultLifecycleProcessor对象,再让lifecycleProcessor等于这个对象,并且把这个对象作注册到spring环境中(名为”lifecycleProcessor”),源码如下:

protected void initLifecycleProcessor() {
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
if (beanFactory.containsLocalBean(LIFECYCLE_PROCESSOR_BEAN_NAME)) {
this.lifecycleProcessor =
beanFactory.getBean(LIFECYCLE_PROCESSOR_BEAN_NAME, LifecycleProcessor.class);
}
}
else {
DefaultLifecycleProcessor defaultProcessor = new DefaultLifecycleProcessor();
defaultProcessor.setBeanFactory(beanFactory);
this.lifecycleProcessor = defaultProcessor;
beanFactory.registerSingleton(LIFECYCLE_PROCESSOR_BEAN_NAME, this.lifecycleProcessor);
}
}


金手指: initLifecycleProcessor()=设置变量+注册bean
initLifecycleProcessor()中每一个分支完成两件事:设置变量lifecycleProcessor和对象作注册到spring(其实spring中很多地方初始化都是完成这两件事,设置变量和注册bean)
(1)spring ioc容器中已经存在这个bean,直接设置变量;
(2)spring ioc容器中不存在这个bean,设置变量并注册bean。



要完成两件事,第一,为defaultProcessor变量赋值,第二,将defaultProcessor对象注入到spring
ioc容器(BeanFactory和Application) 具体:
(1)如果spring ioc容器中已有名为”lifecycleProcessor”的bean,lifecycleProcessor就等于这个bean,
(2)如果spring ioc容器中,没有就实例化一个DefaultLifecycleProcessor对象,再让lifecycleProcessor等于这个对象,并且把这个对象作注册到spring环境中(名为”lifecycleProcessor”)

这里,LIFECYCLE_PROCESSOR_BEAN_NAME常量就是字符串“lifecycleProcessor”。
生命周期,探秘Spring容器的SmartLifecycle接口_初始化_04
如果业务不自定义一个LifecycleProcessor,就默认创建一个DefaultLifecycleProcessor对象

生命周期,探秘Spring容器的SmartLifecycle接口_初始化_05

返回的时候是直接返回的
生命周期,探秘Spring容器的SmartLifecycle接口_spring_06


3.4 finishRefresh()中的getLifecycleProcessor().onRefresh()方法(DefaultLifecycleProcessor类startBeans()–>start())

接上面,现在是getLifecycleProcessor().onRefresh()的执行,如果业务不自定义一个LifecycleProcessor,就默认创建一个DefaultLifecycleProcessor对象,因此执行的就是DefaultLifecycleProcessor的onRefresh方法,来看看源码:

@Override
public void onRefresh() {
startBeans(true);
this.running = true;
}


金手指:重写的方法也是可以调用的,比如常见的重写toString()
这里就使用getLifecycleProcessor().onRefresh()调用了DefaultLifecycleProcessor的onRefresh方法
AbstractApplicationContext构造函数中就调动了自己类中重写的refresh()方法


展开startBeans方法看看,注意入参autoStartupOnly等于true:


入参为true,条件为 if (!autoStartupOnly || (bean instanceof SmartLifecycle && ((SmartLifecycle) bean).isAutoStartup()))
bean必须实现SmartLifecycle接口,并且isAutoStartup()返回true


DefaultLifecycleProcessor类

private void startBeans(boolean autoStartupOnly) {
//取得所有Lifecycle接口的实例,此map的key是实例的名称,value是实例
Map<String, Lifecycle> lifecycleBeans = getLifecycleBeans(); // 直接用map,不用在乎线程安全
Map<Integer, LifecycleGroup> phases = new HashMap<Integer, LifecycleGroup>(); // 直接用map,不用在乎线程安全
for (Map.Entry<String, ? extends Lifecycle> entry : lifecycleBeans.entrySet()) { //遍历map中的元素entry
Lifecycle bean = entry.getValue(); // map中元素就是entry,其中的value就是bean具体实例
//autoStartupOnly等于true时,bean必须实现SmartLifecycle接口,并且isAutoStartup()返回true,才会被放入LifecycleGroup中(后续会从LifecycleGroup中取出来执行start())
if (!autoStartupOnly || (bean instanceof SmartLifecycle && ((SmartLifecycle) bean).isAutoStartup())) {
int phase = getPhase(bean);
LifecycleGroup group = phases.get(phase);
if (group == null) {
group = new LifecycleGroup(phase, this.timeoutPerShutdownPhase, lifecycleBeans, autoStartupOnly);
//phases是个map,key是Lifecycle实例的phase值,value是Lifecycle实例
phases.put(phase, group);
}
//当前实例加入LifecycleGroup中,该LifecycleGroup内的所有实例的phase都相等
group.add(entry.getKey(), bean);
}
}
if (phases.size() > 0) {
List<Integer> keys = new ArrayList<Integer>(phases.keySet());
//按照所有的phase值排序,然后依次执行bean的start方法,每次都是一批phase相同的
Collections.sort(keys);
for (Integer key : keys) {
//这里面会对所有Lifecycle实例逐个调用start方法
phases.get(key).start();
}
}
}

public void start() {
if (this.members.isEmpty()) {
return;
}
Collections.sort(this.members);
for (LifecycleGroupMember member : this.members) {
doStart(this.lifecycleBeans, member.name, this.autoStartupOnly);
}
}


源码中,保证线程安全用ConcurrentHashMap,不用保证线程安全用HashMap
生命周期,探秘Spring容器的SmartLifecycle接口_spring_07
生命周期,探秘Spring容器的SmartLifecycle接口_初始化_08
map中元素为entry,其中包括key value等四个属性,startBeans()方法中使用getLifeCycles(),方法返回的是LinkedHashMap,保证插入顺序。


3.5 DefaultLifecycleProcessor类的doStart()方法

SmartLifecycle的实例的start被调用的地方是在LifecycleGroup内部,对应的方法是doStart,如下所示,优先处理依赖bean:


优先处理依赖bean是指:
String[] dependenciesForBean = this.beanFactory.getDependenciesForBean(beanName);
for (String dependency : dependenciesForBean) {
//如果有依赖类,就先调用依赖类的start方法,这里做了迭代调用
doStart(lifecycleBeans, dependency, autoStartupOnly);
}


private void doStart(Map<String, ? extends Lifecycle> lifecycleBeans, String beanName, boolean autoStartupOnly) {
Lifecycle bean = lifecycleBeans.remove(beanName);
if (bean != null && !this.equals(bean)) {
String[] dependenciesForBean = this.beanFactory.getDependenciesForBean(beanName);
for (String dependency : dependenciesForBean) {
//如果有依赖类,就先调用依赖类的start方法,这里做了迭代调用
doStart(lifecycleBeans, dependency, autoStartupOnly);
}
//条件略多,首先要求isRunning返回false,其次:不能是SmartLifecycle的实现类,**若是SmartLifecycle实现类,其isAutoStartup方法必须返回true**
if (!bean.isRunning() &&
(!autoStartupOnly || !(bean instanceof SmartLifecycle) || ((SmartLifecycle) bean).isAutoStartup())) {
if (logger.isDebugEnabled()) {
logger.debug("Starting bean '" + beanName + "' of type [" + bean.getClass() + "]");
}
try {
bean.start();
}
catch (Throwable ex) {
throw new ApplicationContextException;
}
}
}
}


小结:Spring容器初始化阶段对SmartLifecycle实例的处理逻辑:


  1. Lifecycle的处理都是委托给LifecycleProcessor执行的,先准备好此实例;(第一步和第二步是入口,第三步准备实例,设置属性和注入bean)
  2. 将所有的Lifecycle实例按照phase分组;(获取实例并分组,上面第四步前面和中间)
  3. 从phase值最小的分组开始,依次执行其中每个Lifecycle对象的start方法;(上面第四步后面和第五步)



启动流程:
AbstractApplicationContext类的refresh()方法 --> refresh()中的finishRefresh()方法 --> finishRefresh()中的getLifecycleProcessor().onRefresh() --> startBeans()->start()–>doStart()整个过程,其中,包含doStart()自己的递归调用
关闭流程:
AbstractApplicationContext类的doClose() --> DefaultLifecycleProcessor类中的onClose() --> DefaultLifecycleProcessor类中的 stopBeans() -->LifecycleGroup类中的stop() --> DefaultLifecycleProcessor类中的doStop() (其中,doStop()包含递归调用)
生命周期,探秘Spring容器的SmartLifecycle接口_自定义_09

生命周期,探秘Spring容器的SmartLifecycle接口_自定义_10

这里注意一个递归调用就好,完成迭代的工作
生命周期,探秘Spring容器的SmartLifecycle接口_spring_11
生命周期,探秘Spring容器的SmartLifecycle接口_spring_12


四、关闭:spring容器关闭与SmartLifecycle的关系

分析SmartLifecycle如何感知spring容器的关闭,首先要弄清楚stop方法的调用栈,从LifecycleProcessor接口看起吧:

public interface LifecycleProcessor extends Lifecycle {

void onRefresh(); // Lifecycle的处理都是委托给LifecycleProcessor执行的,onRefresh()是感知启动

void onClose(); // Lifecycle的处理都是委托给LifecycleProcessor执行的,onClose()是感知关闭

}

如上所示,感知容器关闭只能靠onClose方法被调用了,去看看该方法的调用处;


小结:
LifecycleProcessor接口继承LifeCycle,仅新增两个方法,onRefresh()感知启动,onClose()感知关闭。


4.1 AbstractApplicationContext类的doClose()调用DefaultLifecycleProcessor类的onClose()

从AbstractApplicationContext的doClose()方法开始:LifecycleProcessor的onClose方法是在AbstractApplicationContext的doClose方法中被调用的,如下图红框所示,(金手指:doClose()汇集了容器关闭时要执行的基本逻辑,很多关闭都是在这里)

生命周期,探秘Spring容器的SmartLifecycle接口_初始化_13

弄清了调用逻辑,可以去DefaultLifecycleProcessor中看看SmartLifecycle实例的stop方法是如何被调用的;


启动流程:
AbstractApplicationContext类的refresh()方法 --> refresh()中的finishRefresh()方法 --> finishRefresh()中的getLifecycleProcessor().onRefresh() --> startBeans()->start()–>doStart()整个过程,其中,包含doStart()自己的递归调用
关闭流程:
AbstractApplicationContext类的doClose() --> DefaultLifecycleProcessor类中的onClose() --> DefaultLifecycleProcessor类中的 stopBeans() -->LifecycleGroup类中的stop() --> DefaultLifecycleProcessor类中的doStop() (其中,doStop()包含递归调用)
生命周期,探秘Spring容器的SmartLifecycle接口_spring_14
ctrl + alt +B,进入onClose()方法
生命周期,探秘Spring容器的SmartLifecycle接口_spring_15


4.2 DefaultLifecycleProcessor类的stop()调用stopBeans()方法

DefaultLifecycleProcessor的stop方法中先调用stopBeans方法,再将成员变量running设置为false,表示状态已不是运行中:

@Override
public void stop() {
stopBeans();
this.running = false;
}

4.3 DefaultLifecycleProcessor中的stopBeans()调用stop()方法

展开stopBeans方法:和startBeans差不多


stopBeans()方法和startBeans()方法差不多


private void stopBeans() {
//取得所有Lifecycle接口的实例,此map的key是实例的名称,value是实例
Map<String, Lifecycle> lifecycleBeans = getLifecycleBeans();
Map<Integer, LifecycleGroup> phases = new HashMap<Integer, LifecycleGroup>();
for (Map.Entry<String, Lifecycle> entry : lifecycleBeans.entrySet()) {
Lifecycle bean = entry.getValue();
//SmartLifecycle实例通过getPhase方法返回,只实现了Lifecycle的返回0
int shutdownOrder = getPhase(bean);
LifecycleGroup group = phases.get(shutdownOrder);
if (group == null) {
group = new LifecycleGroup(shutdownOrder, this.timeoutPerShutdownPhase, lifecycleBeans, false);
//phases是个map,key是Lifecycle实例的phase值,value是Lifecycle实例
phases.put(shutdownOrder, group);
}
group.add(entry.getKey(), bean);
}
if (phases.size() > 0) {
List<Integer> keys = new ArrayList<Integer>(phases.keySet());
//按照phase排序,和启动的时候的排序正好相反
Collections.sort(keys, Collections.reverseOrder());
for (Integer key : keys) {
//对phase相同的Lifecycle实例,逐一执行stop方法
phases.get(key).stop();
}
}
}


金手指:上述代码和启动时执行start的逻辑基本相似,不同的是执行顺序正好相反,这就是getLifecycleBeans()为什么使用LinkedHashMap的原因,这个方法同时被startBeans()和stopBeans()同时调用


4.4 LifecycleGroup类中的stop()方法调用doStop()方法

看看LifecycleGroup的stop方法内部,是如何调用Lifecycle实例的doStop方法的:

public void stop() {
if (this.members.isEmpty()) {
return;
}
if (logger.isInfoEnabled()) {
logger.info("Stopping beans in phase " + this.phase);
}
Collections.sort(this.members, Collections.reverseOrder());
//这里有个同步逻辑,CounDownLatch中计数器的数量为当前LifecycleGroup中Lifecycle实例数量,关闭的时候不断减少
CountDownLatch latch = new CountDownLatch(this.smartMemberCount);
Set<String> countDownBeanNames = Collections.synchronizedSet(new LinkedHashSet<String>());
for (LifecycleGroupMember member : this.members) {
//这个containsKey判断很重要,在doStop方法中,SmartLifecycle的stop方法可能会在新线程中执行,执行时如果发现了bean的依赖bean,会先去执行依赖bean的stop方法,
//因此有可能此处的Lifecycle实例是实例A的依赖bean,已经在执行A实例的stop时执行过stop方法了,执行stop方法完成的时候会将自己从this.lifecycleBeans中remove掉,所以在this.lifecycleBeans就不存在了
if (this.lifecycleBeans.containsKey(member.name)) {
doStop(this.lifecycleBeans, member.name, latch, countDownBeanNames);
}
else if (member.bean instanceof SmartLifecycle) {
latch.countDown();
}
}
try {
//等到所有Lifecycle实例都执行完毕,当前线程才会执行下去
latch.await(this.timeout, TimeUnit.MILLISECONDS);
if (latch.getCount() > 0 && !countDownBeanNames.isEmpty() && logger.isWarnEnabled()) {
logger.warn("Failed to shut down " + countDownBeanNames.size() + " bean" +
(countDownBeanNames.size() > 1 ? "s" : "") + " with phase value " +
this.phase + " within timeout of " + this.timeout + ": " + countDownBeanNames);
}
}
catch (InterruptedException ex) {
Thread.currentThread().interrupt();
}
}

以上代码有一处需要注意:

SmartLifecycle实例有个stop(Runnable)方法,实现的时候可以在另一个线程中执行stop的逻辑,这样就可以多个SmartLifecycle实例并行执行stop逻辑了,可以提高执行速度,当前线程为了等待所有执行stop的线程,用了CountDownLatch来等待,为了避免无限期等待还设置了超时时间;

4.5 DefaultLifecycleProcessor类中的doStop()方法

最后来看看LifecycleGroup的stop方法中循环调用的doStop方法吧,这里面才会真正的调用到Lifecycle实例的stop方法,还有上面我们分析的多线程逻辑:

private void doStop(Map<String, ? extends Lifecycle> lifecycleBeans, final String beanName,
final CountDownLatch latch, final Set<String> countDownBeanNames) {
//从成员变量lifecycleBeans中remove当前bean,表示已经执行过stop方法
Lifecycle bean = lifecycleBeans.remove(beanName);
if (bean != null) {
//找出依赖bean,通过迭代调用来保证依赖bean先执行stop方法
String[] dependentBeans = this.beanFactory.getDependentBeans(beanName);
for (String dependentBean : dependentBeans) {
//迭代
doStop(lifecycleBeans, dependentBean, latch, countDownBeanNames);
}
try {
//isRunning方法返回true才会执行stop,因此自定义Lifecycle的时候要注意
if (bean.isRunning()) {
if (bean instanceof SmartLifecycle) {
if (logger.isDebugEnabled()) {
logger.debug("Asking bean '" + beanName + "' of type [" + bean.getClass() + "] to stop");
}
countDownBeanNames.add(beanName);
//传入CountDownLatch减一的逻辑,这样SmartLifecycle的stop方法中就可以使用新线程来执行相关逻辑了,记得执行完毕后再执行Runnable中的逻辑,这样主线程才不会一直等待;
((SmartLifecycle) bean).stop(new Runnable() {
@Override
public void run() {
latch.countDown();
countDownBeanNames.remove(beanName);
if (logger.isDebugEnabled()) {
logger.debug("Bean '" + beanName + "' completed its stop procedure");
}
}
});
}
else {
if (logger.isDebugEnabled()) {
logger.debug("Stopping bean '" + beanName + "' of type [" + bean.getClass() + "]");
}
//如果不是SmartLifecycle实例,就调用stop,在当前线程中执行
bean.stop();
if (logger.isDebugEnabled()) {
logger.debug("Successfully stopped bean '" + beanName + "'");
}
}
}
else if (bean instanceof SmartLifecycle) {
// CountDownLatch中计数器的数量是按照SmartLifecycle实例的数量来算的,如果不在runing状态,实例的stop方法就不会调用,主线程就不用等待这次stop,latch直接减一
latch.countDown();
}
}
catch (Throwable ex) {
if (logger.isWarnEnabled()) {
logger.warn("Failed to stop bean '" + beanName + "'", ex);
}
}
}
}

从以上代码可以看出,SmartLifecycle实现类的stop(Runnable)被调用时,LifecycleGroup已经将stop调用完毕后要做的工作通过Runnable传递给实现类了,因此实现类中要记得执行Runnable的run方法,否则会导致外部调用逻辑的参数不准备,影响调用线程的执行;


以上就是关闭容器阶段对SmartLifecycle实例的处理逻辑,简单的小结如下:


  1. AbstractApplicationContext的doClose方法在容器关闭时会被执行,此处调用LifecycleProcessor的onClose方法,由LifecycleProcessor负责所有Lifecycle实例的关闭操作;(第一步和第二步)
  2. 将所有的Lifecycle实例按照phase分组;(第三步和第四步中间)
  3. 从phase值最大的分组开始,依次执行其中每个Lifecycle对象的stop方法;(第四步后面)
  4. 对每个SmartLifecycle实例,若想并行执行以加快stop执行速度,可以在stop方法中用新的线程来执行stop业务逻辑,但是最后不要忘记调用Runnable入参的run方法,以完成主线程的计数和统计;(第六步doStop()方法内部)
  5. 主线程使用了CountDownLatch,在调用了SmartLifecycle实例的stop方法后就会等待,等到计数达到SmartLifecycle总数或者等待超时,再继续向后执行;(第五步后面 //等到所有Lifecycle实例都执行完毕,当前线程才会执行下去 latch.await(this.timeout, TimeUnit.MILLISECONDS);)


关于容器启动时的Lifecycle的处理就分析到这里,接下来看看容器关闭时对Lifecycle操作;


金手指:关闭逻辑:从stopBeans()->stop()->doStop()
生命周期,探秘Spring容器的SmartLifecycle接口_初始化_16

生命周期,探秘Spring容器的SmartLifecycle接口_spring_17

上述代码和启动时执行start的逻辑基本相似,不同的是执行顺序正好相反;进入stop(),查看stop具体逻辑:

生命周期,探秘Spring容器的SmartLifecycle接口_自定义_18
进入doStop()方法
生命周期,探秘Spring容器的SmartLifecycle接口_自定义_19


五、Lifecycle和SmartLifecycle,自定义的时候用哪个?

分为两种情况:


  1. 如果对执行顺序没有要求,在关闭的时候也没有性能或者时间要求,那么就用Lifecycle吧,因为更简单;
  2. 如果在乎顺序,也期望关闭时多个Lifecycle实例能并行执行,快速结束,SmartLifecycle无疑更适合;

六、彻底搞懂SmartLifeCycle 6个方法

金手指:六个方法,全文核心,实际源码中对于六个方法的处理,模拟中六个方法的逻辑

生命周期,探秘Spring容器的SmartLifecycle接口_初始化_20


对于6个方法,只要知道实际的调用的位置和逻辑的怎么写就好了


6.1 start()方法

6.1.1 start()方法的实际调用位置

start()方法在源码中的调用,如下(start()方法在模拟中的使用,直接打印一句就好了):

// LifecycleProcessor是所有Lifecycle实现类的管家,里面包含了对Lifecycle的各种操作.
initLifecycleProcessor();

// 通过LifecycleProcessor来执行Lifecycle实现类的start方法
getLifecycleProcessor().onRefresh();

这两行代码,先初始化LifecycleProcessor,然后使用它调用Lifecycle实现类的start方法,最后使用它调用Lifecycle实现类的stop方法。

startBeans->start()–>doStart()

生命周期,探秘Spring容器的SmartLifecycle接口_自定义_21

6.1.2 模拟的start()方法逻辑怎么写?仿照原来的

模拟的start()方法,设置一定标志位,打印一句就好

@Override
public void start() {
Utils.printTrack("do start");
//设置为false,表示正在执行中
setRunningFlag(true);
}


金手指:模拟代码中为什么要设置自己的runningFlag 变量:
没有太大意义就是模拟一下,仅仅一个表示,我们没有将自定义的runningFlag 用于任何分支判断逻辑,所以这个变量runningFlag 没有任何作用,但是这是代码中的isRunning变量是有价值的
生命周期,探秘Spring容器的SmartLifecycle接口_自定义_22



金手指:模拟类中既要实现SmartLifeCycle方法,又要@Component注解 表面上的原因:instance of Xxx
生命周期,探秘Spring容器的SmartLifecycle接口_自定义_23
实际的原因:
生命周期,探秘Spring容器的SmartLifecycle接口_自定义_24


6.2 isRunning()

6.2.1 isRunning()方法的实际调用位置

实际的isRuninng()什么时候被调用,这才是重要,逻辑只是返回一个变量而已,很简单

实际调用位置,也只有两个,就是doStart()中的一个判断和doStop()中的一个判断

生命周期,探秘Spring容器的SmartLifecycle接口_spring_25

生命周期,探秘Spring容器的SmartLifecycle接口_spring_26

6.2.2 模拟的isRunning()方法逻辑怎么写?仿照原来的

模拟的isRunning()的逻辑,参考实际的isRunning(),直接返回变量就好

@Override
public boolean isRunning() {
return isRunningFlag();
}


金手指:doStop()中的逻辑
生命周期,探秘Spring容器的SmartLifecycle接口_spring_27
生命周期,探秘Spring容器的SmartLifecycle接口_初始化_28
生命周期,探秘Spring容器的SmartLifecycle接口_初始化_29


6.3 isAutoStartup()

6.3.1 isAutoStartup()实际调用位置

两个使用位置,就是startBeans()和doStart()中使用

生命周期,探秘Spring容器的SmartLifecycle接口_spring_30

生命周期,探秘Spring容器的SmartLifecycle接口_初始化_31

6.3.2 模拟的isAutoStartup()方法逻辑怎么写?仿照原来的

生命周期,探秘Spring容器的SmartLifecycle接口_初始化_32

@Override
public boolean isAutoStartup() {
//只有设置为true,start方法才会被回调
return true;
}

6.4 getPhase()

6.4.1 getPhase()方法的实际调用位置

生命周期,探秘Spring容器的SmartLifecycle接口_初始化_33

getPhase()方法对于我们有用的调用只有startBeans()中的调用和stopBeans()中的调用

6.4.2 getPhase()方法的模拟,仿照原有的就好了

生命周期,探秘Spring容器的SmartLifecycle接口_初始化_34

因为SmartLifeCycle是一个Phased,

生命周期,探秘Spring容器的SmartLifecycle接口_自定义_35

所以,执行((Phased) bean).getPhase()

生命周期,探秘Spring容器的SmartLifecycle接口_初始化_36

生命周期,探秘Spring容器的SmartLifecycle接口_自定义_37

生命周期,探秘Spring容器的SmartLifecycle接口_初始化_38

生命周期,探秘Spring容器的SmartLifecycle接口_spring_39

一图小结,SmartLifeCycle就是这样通过实现Phased接口,排序start()的

生命周期,探秘Spring容器的SmartLifecycle接口_spring_40

生命周期,探秘Spring容器的SmartLifecycle接口_spring_41

@Override
public int getPhase() {
return 666;
}

6.5 stop()方法的实际调用位置和stop()方法的模拟

6.5.1 stop()方法的实际调用位置

stop()方法实际调用位置:关闭逻辑中的自定义的关系,同样启动的时候也是调用自定义的start()方法

生命周期,探秘Spring容器的SmartLifecycle接口_初始化_42

6.5.2 模拟的stop()方法逻辑怎么写?仿照原来的

stop()方法的模拟:设置标志位并打印一句就好了

@Override
public void stop() {
Utils.printTrack("do stop");
//设置为false,表示已经不在执行中了
setRunningFlag(false);
}

6.6 stop(Runnable runnable)

6.6.1 stop(Runnable runnable)方法的实际调用位置

在这里调用,如果我们重写,

((SmartLifecycle) bean).stop(() -> {

生命周期,探秘Spring容器的SmartLifecycle接口_自定义_43

将->展开就是new Runnable() good 这里调用

if (bean.isRunning()) {
if (bean instanceof SmartLifecycle) {
if (logger.isDebugEnabled()) {
logger.debug("Asking bean '" + beanName + "' of type [" + bean.getClass() + "] to stop");
}
countDownBeanNames.add(beanName);
//传入CountDownLatch减一的逻辑,这样SmartLifecycle的stop方法中就可以使用新线程来执行相关逻辑了,记得执行完毕后再执行Runnable中的逻辑,这样主线程才不会一直等待;
((SmartLifecycle) bean).stop(new Runnable() {
@Override
public void run() {
latch.countDown();
countDownBeanNames.remove(beanName);
if (logger.isDebugEnabled()) {
logger.debug("Bean '" + beanName + "' completed its stop procedure");
}
}
});
}

6.6.2 模拟的stop(Runnable runnable)方法逻辑怎么写?仿照原来的

仿照SmartLifeCycle自带的stop(Runnable runnable)方法(自带方法中this.stop();callback.run())

生命周期,探秘Spring容器的SmartLifecycle接口_自定义_44

打印一句,设置标志位,并 callback.run();

@Override
public void stop(Runnable callback) {

new Thread(new Runnable() {
@Override
public void run() {
Utils.printTrack("do stop with callback param");
//设置为false,表示已经不在执行中了
setRunningFlag(false);
//callback中有个CountDownLatch实例,总数是SmartLifecycle对象的数量,
//此方法被回调时CountDownLatch实例才会减一,初始化容器的线程一直在wait中;
callback.run();
}
}).start();

}

6.7 CountDownLatch

6.7.1 CountDownLatch latch作用:主线程等待子线程


CountDownLatch latch 局限性:
仅仅是并发情况下计数,仅仅改变一个数字,仅仅服务于SmartLifeCycle及其子类,仅仅是stop()方法中latch.await(this.timeout, TimeUnit.MILLISECONDS);的触发条件而已,仅仅是子线程执行后主线程执行而已


CountDownLatch中计数器的数量为当前LifecycleGroup中Lifecycle实例数量,关闭的时候不断减少,无论是stop方法还是doStop方法,只要减少到0,主线程就可以执行了

先看CountDownLatch类,jdk1.5引入,在java.util.concurrent包里面,所以和并发有关。

生命周期,探秘Spring容器的SmartLifecycle接口_spring_45


金手指:latch是使用smartMemberCount变量确定,是使用在stop()和doStop()方法确定的

第一,latch是使用smartMemberCount变量确定:

smartMemberCount变量唯一的确定就是在LifecycleGroup类的add方法中(一定要是SmartLifeCycle及其子类实例才
++ ),唯一的使用在LifecycleGroup类的stop方法中用来初始化latch容量大小

生命周期,探秘Spring容器的SmartLifecycle接口_自定义_46生命周期,探秘Spring容器的SmartLifecycle接口_自定义_47生命周期,探秘Spring容器的SmartLifecycle接口_初始化_48
第二,latch是使用在stop()和doStop()方法确定的:

无论stop()方法还是doStop()方法,一定要是SmartLifeCycle及其子类实例才 latch.countDown();

stop()方法:

stop()方法里面: CountDownLatch latch = new CountDownLatch(this.smartMemberCount); // 构造函数初始化线程数量 生命周期,探秘Spring容器的SmartLifecycle接口_spring_49
生命周期,探秘Spring容器的SmartLifecycle接口_初始化_50
doStop()方法:
生命周期,探秘Spring容器的SmartLifecycle接口_初始化_51


小结:

latch只为SmartLifeCycle使用:无论是LifecycleGroup的add()方法确定smartMemberCount,然后使用smartMemberCount来确定latch数量,还是latch.countDown(),latch都只为SmartLifeCycle使用。

6.7.2 Set countDownBeanNames作用:作为是否超时的判断条件

countDownBeanNames在stop()方法中确定,在stop()和doStop()方法中使用


stop()和doStop()
doStop()处理包含在lifecycleBeanNames里面的bean,这些bean分为两类实现了LifeCycle接口或实现了SmartLifeCycle接口
其他的,不包含在lifecycleBeanNames里面的,但是确实SmartLifeCycle实现类的,就是已经被删除了的,直接sync同步减一就好了
else if (member.bean instanceof SmartLifecycle) {
// Already removed: must have been a dependent bean from another phase
latch.countDown();
}


从CountDownLatch类的latch变量到 Set 的countDownBeanNames变量 :

​Set<String> countDownBeanNames = Collections.synchronizedSet(new LinkedHashSet<String>());​

这里是保证插入顺序的,但是stop()方法并没有为这个set集合添加元素

生命周期,探秘Spring容器的SmartLifecycle接口_spring_52

且看doStop()方法,

生命周期,探秘Spring容器的SmartLifecycle接口_初始化_53

生命周期,探秘Spring容器的SmartLifecycle接口_初始化_54

6.7.3 Set lifecycleBeanNames作用:存放Map<beanName,bean>,递归使用

生命周期,探秘Spring容器的SmartLifecycle接口_初始化_55

生命周期,探秘Spring容器的SmartLifecycle接口_自定义_56

好了,lifecycleBeans确定了,看看怎么用的,在哪里用的,在doStart()和doStop()方法中使用的

生命周期,探秘Spring容器的SmartLifecycle接口_spring_57

先看doStart()方法

生命周期,探秘Spring容器的SmartLifecycle接口_初始化_58

doStart()方法中的lifecycleBeans只是形参传递过来的,不是全局的lifecycleBeans,

doStart()里面的lifecycleBeans.remove(beanName); // 如果该键存在,则该方法返回先前映射到指定键的值,否则该方法返回NULL。

只是为了执行完自己的方法完成,不会对全局lifecycleBeans有任何影响

再看doStop()方法

生命周期,探秘Spring容器的SmartLifecycle接口_自定义_59

七、面试金手指

7.1 SmartLifecycle 6个方法

生命周期,探秘Spring容器的SmartLifecycle接口_spring

如上图所示,在继承了Lifecycle和Phased两个接口后,SmartLifecycle一共定义了六个方法,为了便于后面的源码分析,先做个简介:

方法

作用

start()

bean初始化完毕后,该方法会被执行(实际:,模拟:加一句打印就好了)

stop()

分为两种情况,如果当前对象实现了SmartLifecycle,就调用stop(Runnable);如果只是实现了Lifecycle,就调用stop()

isRunning()

当前状态

getPhase()

返回值决定start方法在众多Lifecycle实现类中的执行顺序(stop也是)

isAutoStartup()

start方法被执行前先看此方法返回值,返回false就不执行start方法了

stop(Runnable)

分为两种情况,如果当前对象实现了SmartLifecycle,就调用stop(Runnable);如果只是实现了Lifecycle,就调用stop()


这个六个方法的全文的主线:
1、要看这六个方法在源码中是怎样搞的;源码中什么位置调用
2、要看着六个方法在自定义模拟接口实现SmartLifeCycle是怎么搞的;模拟中如何模拟


从上述列举中可以看出,感知容器变化的能力最终来自Lifecycle,而SmartLifecycle只是Lifecycle的增强版,可以自定义优先级(getPhase),自主决定是否随容器启动(isAutoStartup),以及停止时能接受一个runnable对象(stop(Runnable));

7.2 spring容器启动与SmartLifecycle的关系


启动流程:
AbstractApplicationContext类的refresh()方法 --> refresh()中的finishRefresh()方法 --> finishRefresh()中的getLifecycleProcessor().onRefresh() --> startBeans()->start()–>doStart()整个过程,其中,包含doStart()自己的递归调用
关闭流程:
AbstractApplicationContext类的doClose() --> DefaultLifecycleProcessor类中的onClose() --> DefaultLifecycleProcessor类中的 stopBeans() -->LifecycleGroup类中的stop() --> DefaultLifecycleProcessor类中的doStop() (其中,doStop()包含递归调用)



小结:Spring容器初始化阶段对SmartLifecycle实例的处理逻辑:


  1. Lifecycle的处理都是委托给LifecycleProcessor执行的,先准备好此实例;(第一步和第二步是入口,第三步准备实例,设置属性和注入bean)
  2. 将所有的Lifecycle实例按照phase分组;(获取实例并分组,上面第四步前面和中间)
  3. 从phase值最小的分组开始,依次执行其中每个Lifecycle对象的start方法;(上面第四步后面和第五步)


7.3 spring容器关闭与SmartLifecycle的关系


以上就是关闭容器阶段对SmartLifecycle实例的处理逻辑,简单的小结如下:


  1. AbstractApplicationContext的doClose方法在容器关闭时会被执行,此处调用LifecycleProcessor的onClose方法,由LifecycleProcessor负责所有Lifecycle实例的关闭操作;(第一步和第二步)
  2. 将所有的Lifecycle实例按照phase分组;(第三步和第四步中间)
  3. 从phase值最大的分组开始,依次执行其中每个Lifecycle对象的stop方法;(第四步后面)
  4. 对每个SmartLifecycle实例,若想并行执行以加快stop执行速度,可以在stop方法中用新的线程来执行stop业务逻辑,但是最后不要忘记调用Runnable入参的run方法,以完成主线程的计数和统计;(第六步doStop()方法内部)
  5. 主线程使用了CountDownLatch,在调用了SmartLifecycle实例的stop方法后就会等待,等到计数达到SmartLifecycle总数或者等待超时,再继续向后执行;(第五步后面 //等到所有Lifecycle实例都执行完毕,当前线程才会执行下去 latch.await(this.timeout, TimeUnit.MILLISECONDS);)


7.4 关于Lifecycle和SmartLifecycle选用问题

分为两种情况:


  1. 如果对执行顺序没有要求,在关闭的时候也没有性能或者时间要求,那么就用Lifecycle吧,因为更简单;
  2. 如果在乎顺序,也期望关闭时多个Lifecycle实例能并行执行,快速结束,SmartLifecycle无疑更适合;

八、小结

SmartLifeCycle完成了

天天打码,天天进步!!!