其他网址
Lifecycle和SmartLifecycle的正确使用姿势_咔咔学长-CSDN博客
Spring容器级生命周期回调——LifeCycle_tinysakura的博客-CSDN博客
【Spring源码分析】39-Spring容器生命周期回调接口——LifeCycle_通往神秘的道路的专栏-CSDN博客
简介
bean的初始化方法和销毁方法是Bean生命周期级别的;而Lifecycle是容器生命周期级别的。如果我们想在容器本身的生命周期(比如容器启动完成后、停止之前)事件上做一些工作,可以使用LifeCycle接口。
LifeCycle
简介
源码
public interface Lifecycle { void start(); void stop(); boolean isRunning(); }
start:如果类A没在运行(isRunning返回false),则走该方法;否则不走该方法
stop:如果类A在运行(isRunning返回true),则走该方法;否则不走该方法
isRunning:返回true表示类A已经运行,返回false表示类A没运行
简单示例
isRunning返回true
代码
package com.example.config; import org.springframework.context.Lifecycle; import org.springframework.stereotype.Component; @Component public class MyLifeCycle implements Lifecycle { @Override public void start() { System.out.println("start"); } @Override public void stop() { System.out.println("stop"); } @Override public boolean isRunning() { System.out.println("isRunning"); return true; } }
结果
启动时无打印
关闭时:
isRunning stop
isRunning返回false
package com.example.config; import org.springframework.context.Lifecycle; import org.springframework.stereotype.Component; @Component public class MyLifeCycle implements Lifecycle { @Override public void start() { System.out.println("start"); } @Override public void stop() { System.out.println("stop"); } @Override public boolean isRunning() { System.out.println("isRunning"); return false; } }
结果
启动时无打印
关闭时
isRunning
改动isRunning值
我本以为,手动改isRunning返回值即可让它既执行start()又执行stop(),但我错了,如下所示:
package com.example.config; import org.springframework.context.Lifecycle; import org.springframework.stereotype.Component; @Component public class MyLifeCycle implements Lifecycle { private volatile boolean running = false; @Override public void start() { System.out.println("start"); running = true; } @Override public void stop() { System.out.println("stop"); } @Override public boolean isRunning() { System.out.println("isRunning"); return running; } }
结果
启动时无打印
关闭时:
isRunning
显式调用start()
其他网址:https://blog.csdn.net/u011624903/article/details/109000785
在上边“简单示例” 可以发现,无论怎么搞,都调用不到start()方法!!。有人说必须显式去调用它,如下所示:
public static void main(String[] args) { AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext( "com.example.config.MyLifecycle"); ctx.start(); ctx.close(); }
但是,我只看到如下输出:
19:20:23.914 [main] DEBUG org.springframework.context.annotation.AnnotationConfigApplicationContext - Refreshing org.springframework.context.annotation.AnnotationConfigApplicationContext@3ab39c39 19:20:23.924 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'org.springframework.context.annotation.internalConfigurationAnnotationProcessor' 19:20:23.944 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'org.springframework.context.event.internalEventListenerProcessor' 19:20:23.944 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'org.springframework.context.event.internalEventListenerFactory' 19:20:23.944 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'org.springframework.context.annotation.internalAutowiredAnnotationProcessor' 19:20:23.944 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'org.springframework.context.annotation.internalCommonAnnotationProcessor' 19:20:23.964 [main] DEBUG org.springframework.core.env.PropertySourcesPropertyResolver - Found key 'spring.liveBeansView.mbeanDomain' in PropertySource 'systemProperties' with value of type String 19:20:23.974 [main] DEBUG org.springframework.context.annotation.AnnotationConfigApplicationContext - Closing org.springframework.context.annotation.AnnotationConfigApplicationContext@3ab39c39, started on Tue Mar 09 19:20:23 CST 2021 19:20:23.974 [main] DEBUG org.springframework.core.env.PropertySourcesPropertyResolver - Found key 'spring.liveBeansView.mbeanDomain' in PropertySource 'systemProperties' with value of type String
对此,该有一张黑人问号脸。。。留到以后再看为什么会这样吧
SmartLifeCycle
简介
说明
SmartLifecycle是Lifecycle的一个子接口,比Lifecycle有更丰富的功能。其中有两点最重要的改进:
- 无需容器显示调用start()方法,就可以回调SmartLifecycle接口的start()
- 容器中如果有多个SmartLifecycle实例,可以方便控制调用顺序。
方法
方法名
描述
isAutoStartup()
一定要返回true。否则,容器启动时不会回调start()方法。
true:让Lifecycle类所在的上下文在调用`refresh`时,能够自己自动进行回调。
false:表明组件打算通过显式的start()调用来启动,类似于普通的Lifecycle实现。这个一定要返回true,不然就跟Lifecycle一样了。getPhase()
控制多个SmartLifecycle的回调顺序的:越小:start()方法越靠前,stop()方法越靠后
isRunning()
与Lifecycle接口中的功能一样,用来判你的断组件是否在运行。
start()
如果类A没在运行(isRunning返回false),则走该方法;否则不走该方法。
当刷新容器(启动完成)时调用。跟Lifecycle接口一样。
stop(Runnable callback)
当容器停止时,回调该方法。
当执行完你自定义的逻辑后,一定要调用下callback.run(); 这是为了,告诉容器你已停止自己的组件完成。
很多源码会在该方法内仅写两行代码,参考下面例子。一行是stop():把真正的逻辑转发到stop()这个方法。另一行就是必须调用的callback.run();此方法是有超时时间的,默认为30s。可以通过以下方式设置超时时间
stop()
需要自己调用。不会被Spring框架调用到
stop(Runnable callback)
在SmartLifecycle中定义的停止方法接收一个回调函数。任何实现在关闭进程完成之后都必须调用回调的run()方法。当需要时这可以进行异步关闭,因为LifecycleProcessor接口、DefaultLifecycleProcessor接口的默认实现会等待每个阶段的对象组直到达到超时值,然后调用回调函数。默认每个阶段的超时值为30秒。可以在上下文中通过定义名为”lifecycleProcessor”的bean来覆盖默认的生命周期处理器实例。如果你只想修改超时值,这样改即可:
<bean id="lifecycleProcessor" class="org.springframework.context.support.DefaultLifecycleProcessor"> <!-- timeout value in milliseconds --> <property name="timeoutPerShutdownPhase" value="10000"/> </bean>
简单示例
代码
package com.example.config; import org.springframework.context.SmartLifecycle; import org.springframework.stereotype.Component; @Component public class MySmartLifecycle implements SmartLifecycle { private volatile boolean running = false; /** * true:让Lifecycle类所在的上下文在调用`refresh`时,能够自己自动进行回调 * false:表明组件打算通过显式的start()调用来启动,类似于普通的Lifecycle实现。 */ @Override public boolean isAutoStartup() { return true; } /** * 很多框架中,把真正逻辑写在stop()方法内。比如quartz和Redis的spring支持包 */ @Override public void stop(Runnable callback) { System.out.println("stop(callback)"); stop(); callback.run(); } @Override public void start() { System.out.println("start()"); running = true; } @Override public void stop() { System.out.println("stop()"); running = false; } @Override public boolean isRunning() { System.out.println("isRunning()"); return running; } /** * 阶段值。越小:start()方法越靠前,stop()方法越靠后 */ @Override public int getPhase() { System.out.println("getPhase()"); return 0; } }
测试
启动时:
. ____ _ __ _ _ /\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \ ( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \ \\/ ___)| |_)| | | | | || (_| | ) ) ) ) ' |____| .__|_| |_|_| |_\__, | / / / / =========|_|==============|___/=/_/_/_/ :: Spring Boot :: (v2.3.0.RELEASE) 2021-03-09 19:30:57.138 INFO 6600 --- [ main] com.example.DemoApplication : Starting DemoApplication on DESKTOP-QI6B9ME with PID 6600 (E:\work\Idea_proj\demo_JAVA\demo_SpringBoot\target\classes started by Liu in E:\work\Idea_proj\demo_JAVA\demo_SpringBoot) 2021-03-09 19:30:57.143 INFO 6600 --- [ main] com.example.DemoApplication : No active profile set, falling back to default profiles: default 2021-03-09 19:30:57.899 INFO 6600 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port(s): 8080 (http) 2021-03-09 19:30:57.907 INFO 6600 --- [ main] o.apache.catalina.core.StandardService : Starting service [Tomcat] 2021-03-09 19:30:57.907 INFO 6600 --- [ main] org.apache.catalina.core.StandardEngine : Starting Servlet engine: [Apache Tomcat/9.0.35] 2021-03-09 19:30:57.986 INFO 6600 --- [ main] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext 2021-03-09 19:30:57.986 INFO 6600 --- [ main] o.s.web.context.ContextLoader : Root WebApplicationContext: initialization completed in 808 ms 2021-03-09 19:30:58.135 INFO 6600 --- [ main] o.s.s.concurrent.ThreadPoolTaskExecutor : Initializing ExecutorService 'applicationTaskExecutor' getPhase() isRunning() start() 2021-03-09 19:30:58.260 INFO 6600 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8080 (http) with context path '' 2021-03-09 19:30:58.268 INFO 6600 --- [ main] com.example.DemoApplication : Started DemoApplication in 1.442 seconds (JVM running for 2.44)
关闭时:
getPhase() isRunning() stop(callback) stop()