ThinkChat2.0新版上线,更智能更精彩,支持会话、画图、阅读、搜索等,送10W Token,即刻开启你的AI之旅 广告
SmartLifeCycle 在LifeCycle的基础上增加了对容器上下文的刷新感知能力。同时继承了Phase接口提供了Bean 创建和销毁一定的干预能力。SmartLifeCycle定义如下: ~~~ public interface SmartLifecycle extends Lifecycle, Phased { boolean isAutoStartup(); void stop(Runnable callback); } ~~~ 修改 MyLifeCycle [自定义实现Lifecycle接口](Lifecycle%E6%8E%A5%E5%8F%A3.md) 实现 SmartLifeCycle 运行输出如下: ``` 检查MyLifeCycle组件的运行状态:false 容器启动后执行MyLifeCycle操作... ==================== 检查MyLifeCycle组件的运行状态:true =============================== 检查MyLifeCycle组件的运行状态:true 收到关闭容器的信号MyLifeCycle操作... ``` 与Lifecycle 的区别是 自动调用 start方法 如果重写 isAutoStartup 则执行结果和Lifecycle 一样,但是执行的过程不一样 ~~~ public boolean isAutoStartup() { return false; } ~~~ ## 关于Stop与Timeout SmartLifeCycle的stop方法传入了一个Runnable方法,实现方是必须要调用runnable的run方法。其实查看lifecycleProcessor的默认实现DefaultLifecycleProcessor就可以知道其原因。 DefaultLifecycleProcessor中通过不同的phase进行分组排序,对于每个分组会创建一个CountdownLatch。传入的callback中会对countdownLatch进行countdown操作。 这样做是为了这个操作可能会采用多线程执行,需要通过countdownLatch进行并发控制,同时提供了timeout参数控制每个group的启动以及销毁顺序。 ## onRefresh与isAutoStartup SmartLifeCycle的isAutoStartup方法用于表明bean是否希望接受onRefresh回调。如果返回true的话,那么在容器refresh的时候,就会触发这个回调方法。Spring文档中提到,不是每一个context都一定会实现start方法进行调用。获取refresh回调的时候就可以提前感知而不需要等待start事件的触发。 When the context is refreshed (after all objects have been instantiated and initialized), that callback is invoked. At that point, the default lifecycle processor checks the boolean value returned by each SmartLifecycle object’s isAutoStartup() method. If true, that object is started at that point rather than waiting for an explicit invocation of the context’s or its own start() method (unlike the context refresh, the context start does not happen automatically for a standard context implementation). The phase value and any “depends-on” relationships determine the startup order as described earlier.《官网说明》 我们通过源码来分析一下这个过程。Spring的ApplicationContext 构造函数中调用onRefresh方法进行容器的初始化,如下: ~~~ @Override public void refresh() throws BeansException, IllegalStateException { synchronized (this.startupShutdownMonitor) { // Prepare this context for refreshing. prepareRefresh(); // Tell the subclass to refresh the internal bean factory. ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); // Prepare the bean factory for use in this context. prepareBeanFactory(beanFactory); try { // Allows post-processing of the bean factory in context subclasses. postProcessBeanFactory(beanFactory); // Invoke factory processors registered as beans in the context. invokeBeanFactoryPostProcessors(beanFactory); // Register bean processors that intercept bean creation. registerBeanPostProcessors(beanFactory); // Initialize message source for this context. initMessageSource(); // Initialize event multicaster for this context. initApplicationEventMulticaster(); // Initialize other special beans in specific context subclasses. onRefresh(); // Check for listener beans and register them. registerListeners(); // Instantiate all remaining (non-lazy-init) singletons. finishBeanFactoryInitialization(beanFactory); // Last step: publish corresponding event. finishRefresh(); } catch (BeansException ex) { if (logger.isWarnEnabled()) { logger.warn("Exception encountered during context initialization - " + "cancelling refresh attempt: " + ex); } // Destroy already created singletons to avoid dangling resources. destroyBeans(); // Reset 'active' flag. cancelRefresh(ex); // Propagate exception to caller. throw ex; } finally { // Reset common introspection caches in Spring's core, since we // might not ever need metadata for singleton beans anymore... resetCommonCaches(); } } } ~~~ 可以看到,在容器的onRefresh(context的入口)方法中,在完成了bean的加载,解析,factory的初始化,BeanFactoryPostProcessor,BeanPostProcessor,listner的注册,以及初始化(依赖注入,bean的初始化完成)之后,调用finishRefresh方法。finishRefresh代码逻辑如下: ~~~ protected void finishRefresh() { // Initialize lifecycle processor for this context. initLifecycleProcessor(); // Propagate refresh to lifecycle processor first. --- 调用LifeCycle的onRefresh方法 getLifecycleProcessor().onRefresh(); // Publish the final event. ---- 发送事件广播 publishEvent(new ContextRefreshedEvent(this)); // Participate in LiveBeansView MBean, if active. LiveBeansView.registerApplicationContext(this); } ~~~ 先执行LifeCycleProcessor的初始化,注册到容器中,然后执行LifeCycleProcessor的onRefresh方法。注意,这里其实还没有调用start方法的。所以说onRefresh是先于start的。 * **容器实现了lifeCycle接口** 我们可以发现ConfigurableApplicationContext也实现了lifeCycle接口(但此时调用LifeCycleProcessor获取lifeCycle的接口Bean时,是没有ConfigurableApplicationContext实现类的),context的start方法就是通过这个接口获得的。并且context的start方法是需要创建context的调用方手动调用的,所以也就是说context的start并不会调用。而LifeCycleProcessor的start就是在context 的start中触发的。这个也就是上面官方文档里面说到的,start对于context并不一定会实现以及进行调用。 这个是需要十分关注的点。就是对于容器context来说,onRefresh是创建context实例的构造函数就会调用的。而start需要通过实现了lifeCycle接口的context才会具有这个能力,并且还需要client主动调用start方法,lifeCycle的start方法才会被调用。 * SmartLifeCycle与事件监听机制 通过实现ApplicationListener接口,可以获取容器的生命周期事件通知。 ~~~ public interface ApplicationListener<E extends ApplicationEvent\> extends EventListener { /** * Handle an application event. * @param event the event to respond to */ void onApplicationEvent(E event); } ~~~ 与事件监听的方式感知容器事件的方式相比,实现SmartLifeCycle接口可以获取整个生命周期的能力,包括启动和关闭等各个方法的回调。事件监听的广播可以看到其实和lifeCycle的调用是前后调用的。事件监听一样可以获取容器的各个阶段的事件,但是需要判断事件的类型处理不同的事件逻辑。