文章目录
初始化和销毁回调
在bean交由spring管理的过程中,bean从初始化到销毁之间经历许多过程,其中初始化回调方法会在bean实例化之后,属性赋值(set方法执行)之前被调用;销毁回调方法会在bean即将被销毁之前调用,可以在销毁回调中做一些资源的释放工作。
InitializingBean和DisposableBean接口
public interface InitializingBean {
//属性初始化之前被调用
void afterPropertiesSet() throws Exception;
}
public interface DisposableBean {
//销毁bean之前被调用
void destroy() throws Exception;
}
实现InitializingBean的bean,会在属性初始化之前被调用,实现DisposableBean的bean,会在bean即将被销毁时调用。
演示
@Component
public class InitAndDestroyBean implements InitializingBean, DisposableBean {
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("InitAndDestroyBean初始化...");
}
@Override
public void destroy() throws Exception {
System.out.println("InitAndDestroyBean销毁...");
}
}
@Configuration
@ComponentScan("com.vm")
public class SpringConfig {
}
public class InitAndDestroyBeanTest {
public static ApplicationContext app;
@BeforeClass
public static void before(){
app = new AnnotationConfigApplicationContext(SpringConfig.class);
}
@AfterClass
public static void after(){
if (app instanceof AbstractApplicationContext)
((AbstractApplicationContext)app).close();//关闭容器
}
@Test
public void test(){
InitAndDestroyBean bean = app.getBean(InitAndDestroyBean.class);
System.out.println(bean);
}
}
@PostConstruct和@PreDestroy注解
@Documented
@Retention (RUNTIME)
@Target(METHOD)
public @interface PostConstruct {
}
@Documented
@Retention (RUNTIME)
@Target(METHOD)
public @interface PreDestroy {
}
被@PostConstruct标注的方法将会被当初初始化回调,被@PreDestroy标注的方法将会被作为销毁回调执行。
演示
@Component
public class InitAndDestroyBean2 {
@PostConstruct
public void initMethod(){
System.out.println("InitAndDestroyBean2初始化...");
}
@PreDestroy
public void destoryMethod(){
System.out.println("InitAndDestroyBean2销毁...");
}
}
public class InitAndDestroyBeanTest {
public static ApplicationContext app;
@BeforeClass
public static void before(){
app = new AnnotationConfigApplicationContext(SpringConfig.class);
}
@AfterClass
public static void after(){
if (app instanceof AbstractApplicationContext)
((AbstractApplicationContext)app).close();//关闭容器
}
@Test
public void test(){
InitAndDestroyBean2 bean = app.getBean(InitAndDestroyBean2.class);
System.out.println(bean);
}
}
手动配置初始化和销毁回调
使用java配置类或xml配置一个bean到容器时,可以为这个bean指定初始化和调回的回调方法。如下:
public class InitAndDestroyBean3 {
public void initMethod(){
System.out.println("InitAndDestroyBean3初始化...");
}
public void destoryMethod(){
System.out.println("InitAndDestroyBean3销毁...");
}
}
使用Java配置类注入容器,配置如下
@Configuration
@ComponentScan("com.vm")
public class SpringConfig {
@Bean(initMethod = "initMethod",destroyMethod = "destoryMethod")
public InitAndDestroyBean3 getInitAndDestroyBean3(){
return new InitAndDestroyBean3();
}
}
initMethod 属性指定一个初始化回调的方法名,destroyMethod 指定一个销毁回调方法。XML同等配置如下
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<context:component-scan base-package="com.vm"/>
<bean id="initAndDestroyBean3" class="com.vm.pojo.InitAndDestroyBean3" init-method="initMethod" destroy-method="destoryMethod"/>
</beans>
演示
public class InitAndDestroyBeanTest {
public static ApplicationContext app;
@BeforeClass
public static void before(){
app = new AnnotationConfigApplicationContext(SpringConfig.class);
}
@AfterClass
public static void after(){
if (app instanceof AbstractApplicationContext)
((AbstractApplicationContext)app).close();//关闭容器
}
@Test
public void test(){
InitAndDestroyBean3 bean = app.getBean(InitAndDestroyBean3.class);
System.out.println(bean);
}
}
执行顺序
如果一个bean同时使用上述三种方式配置,他的执行顺序如下:
注解->接口->配置
演示
public class InitAndDestroyBean4 implements InitializingBean, DisposableBean {
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("接口初始化...");
}
@Override
public void destroy() throws Exception {
System.out.println("接口销毁...");
}
@PostConstruct
public void initMethod(){
System.out.println("注解初始化...");
}
@PreDestroy
public void destoryMethod(){
System.out.println("注解销毁...");
}
public void initMethod2(){
System.out.println("配置初始化...");
}
public void destoryMethod2(){
System.out.println("配置销毁...");
}
}
@Configuration
@ComponentScan("com.vm")
public class SpringConfig {
@Bean(initMethod = "initMethod2",destroyMethod = "destoryMethod2")
public InitAndDestroyBean4 getInitAndDestroyBean4(){
return new InitAndDestroyBean4();
}
}
public class InitAndDestroyBeanTest {
public static ApplicationContext app;
@BeforeClass
public static void before(){
app = new AnnotationConfigApplicationContext(SpringConfig.class);
}
@AfterClass
public static void after(){
if (app instanceof AbstractApplicationContext)
((AbstractApplicationContext)app).close();//关闭容器
}
@Test
public void test(){
InitAndDestroyBean4 bean = app.getBean(InitAndDestroyBean4.class);
System.out.println(bean);
}
}
容器的启动和关闭
在容器的启动或关闭阶段,bean实现了相应的接口,可以被通知到(调用回调方法)
Lifecycle接口
public interface Lifecycle {
void start();
void stop();
boolean isRunning();
}
start()方法在容器启动时被调用;stop()在容器被关闭时调用;isRunning()用来判断容器是否在运行;当isRunning()返回false时start()方法才能被执行,同理当isRunning()返回true时stop()方法才能被执行。
演示
@Component
public class LifecycleImpl implements Lifecycle {
private boolean isRunning = false;
@Override
public void start() {
System.out.println("LifecycleImpl.start...");
isRunning = true;
}
@Override
public void stop() {
System.out.println("LifecycleImpl.stop...");
isRunning = false;
}
@Override
public boolean isRunning() {
return isRunning;
}
}
public class LifecycleTest {
public static ApplicationContext app;
@BeforeClass
public static void before(){
app = new AnnotationConfigApplicationContext(SpringConfig.class);
if (app instanceof AbstractApplicationContext)
((AbstractApplicationContext)app).start();
}
@AfterClass
public static void after(){
if (app instanceof AbstractApplicationContext)
((AbstractApplicationContext)app).close();
}
@Test
public void test(){
LifecycleImpl bean = app.getBean(LifecycleImpl.class);
System.out.println(bean);
}
}
需要注意,start()和stop()方法要想被调用,必须手动调用容器的start()和close()方法,这是不智能的,大部分情况下我们希望这些方法能被自动调用。
SmartLifecycle接口
public interface SmartLifecycle extends Lifecycle, Phased {
int DEFAULT_PHASE = 2147483647;
/**
*是否自动启动,当返回值为true,SmartLifecycle 的start()方法将会在容器启动时被调用,而不需要再去手动的调用容器的启动方法,反之则和Lifecycle接口类似
*/
default boolean isAutoStartup() {
return true;
}
/**
*该方法会在容器关闭时被调用,入参callback一定要执行一下,相当于告诉容器stop()方法逻辑执行完毕,这个接口的默认实现调用了父接口Lifecycle的stop()方法,所以实际的逻辑也可以写在stop()方法,或者重写该方法,但是别忘记执行callback.run()
*/
default void stop(Runnable callback) {
this.stop();
callback.run();
}
/**
*用于确定执行顺序
*/
default int getPhase() {
return 2147483647;
}
}
public interface Phased {
int getPhase();
}
SmartLifecycle继承了Lifecycle接口,同时还继承了Phased ,Phased 接口的作用是当我们同时向容器中注入多个SmartLifecycle类型的bean时,能指定它们的执行顺序,数值越小,优先级越高。
演示
@Component
public class SmartLifecycleImpl implements SmartLifecycle {
private boolean isRunning = false;
@Override
public void start() {
System.out.println("SmartLifecycleImpl.start...");
isRunning = true;
}
@Override
public void stop() {
System.out.println("SmartLifecycleImpl.stop...");
isRunning = false;
}
@Override
public boolean isRunning() {
return isRunning;
}
@Override
public int getPhase() {
return 1;
}
}
@Component
public class SmartLifecycleImpl2 implements SmartLifecycle {
private boolean isRunning = false;
@Override
public void start() {
System.out.println("SmartLifecycleImpl2.start...");
isRunning = true;
}
@Override
public void stop() {
System.out.println("SmartLifecycleImpl2.stop...");
isRunning = false;
}
@Override
public boolean isRunning() {
return isRunning;
}
@Override
public int getPhase() {
return 2;
}
}
public class LifecycleTest {
public static ApplicationContext app;
@BeforeClass
public static void before(){
app = new AnnotationConfigApplicationContext(SpringConfig.class);
if (app instanceof AbstractApplicationContext)
((AbstractApplicationContext)app).registerShutdownHook();//向JVM注册一个关闭钩子函数,程序执行完毕由JVM关闭容器,无需我们调用容器的close()方法
}
@Test
public void testSmartLifecycleImpl(){
SmartLifecycleImpl bean1 = app.getBean(SmartLifecycleImpl.class);
SmartLifecycleImpl2 bean2 = app.getBean(SmartLifecycleImpl2.class);
System.out.println(bean1);
System.out.println(bean2);
}
}
方法被正确的调用,并且执行顺序也正确。
LifecycleProcessor接口
public interface LifecycleProcessor extends Lifecycle {
/**
*容器刷新时被调用
*/
void onRefresh();
/**
*容器关闭时被调用
*/
void onClose();
}
LifecycleProcessor也继承了Lifecycle 接口,同时还扩展了两个方法。
这个接口是一个很重要的接口,SmartLifecycle和Lifecycle 接口都依赖于spring提供的一个LifecycleProcessor的默认实现类DefaultLifecycleProcessor。
SmartLifecycle和Lifecycle被调用的逻辑实际在DefaultLifecycleProcessor中,AbstractApplicationContext的部分源码如下:
从第二张图可以看出,如果我们需要向容器中注入一个自定义的LifecycleProcessor实现类替换默认的DefaultLifecycleProcessor,那么bean的名字必须叫“lifecycleProcessor”,否则只能被当作一个普通的Lifecycle 接口的实现类了。
需要注意的时,如果我们替换了默认的DefaultLifecycleProcessor,那么实现SmartLifecycle和Lifecycle的接口的bean可能不会被调用了,除非我们自定义的LifecycleProcessor实现类有类似DefaultLifecycleProcessor的逻辑。
演示
@Component("lifecycleProcessor")
public class LifecycleProcessorImpl implements LifecycleProcessor {
private boolean isRunning = false;
@Override
public void onRefresh() {
System.out.println("LifecycleProcessorImpl.onRefresh...");
isRunning = true;
}
@Override
public void onClose() {
System.out.println("LifecycleProcessorImpl.onClose...");
isRunning = false;
}
@Override
public void start() {
System.out.println("LifecycleProcessorImpl.start...");
isRunning = true;
}
@Override
public void stop() {
System.out.println("LifecycleProcessorImpl.stop...");
isRunning = false;
}
@Override
public boolean isRunning() {
return isRunning;
}
}
public class LifecycleTest {
public static ApplicationContext app;
@BeforeClass
public static void before(){
app = new AnnotationConfigApplicationContext(SpringConfig.class);
if (app instanceof AbstractApplicationContext)
((AbstractApplicationContext)app).registerShutdownHook();//向JVM注册一个关闭钩子函数,程序执行完毕由JVM关闭容器,无需我们调用容器的close()方法
}
@Test
public void testLifecycleProcessorImpl(){
LifecycleProcessorImpl bean = app.getBean(LifecycleProcessorImpl.class);
System.out.println(bean);
}
}
onRefresh()方法会在容器刷新时被执行,onClose()方法会在容器关闭时被执行。start()和stop()方法需要手动调用容器的start()和stop()方法时才会被调用。