Spring容器級生命週期回撥——LifeCycle
之前我們談了bean的生命週期中利用容器擴充套件點回調,來實現後置處理器以及bean的初始和銷燬回撥。但這些事件都是建立在容器已經成功啟動的基礎上,如果我們想在容器本身的生命週期(比如容器啟動、停止)事件上做一些工作怎麼辦呢?Spring提供了以下介面:
Lifecycle介面
任何Spring管理的物件都可以實現此介面。當ApplicationContext介面啟動和關閉時,它會呼叫本容器內所有的Lifecycle實現。
Lifecycle介面原型如下:
public interface Lifecycle { void start(); void stop(); boolean isRunning(); }
LifecycleProcessor介面
它繼承Lifcycle介面。同時,增加了2個方法,用於處理容器的refreshed和closed事件。
原型如下:
public interface LifecycleProcessor extends Lifecycle {
void onRefresh();
void onClose();
}
SmartLifecycle介面
若兩個物件有依賴關係(這種依賴不一定是一個bean引用另一個bean),希望某些bean先初始化,完成一些工作後,再初始化另一些bean。在此場景中,可以使用SmartLifecycle介面,該介面有個方法getPhase(),實現了父介面Phased,它返回一個int型數字,表明執行順序
public interface Phased {
int getPhase();
}
SmartLifecycle介面原型如下:
public interface SmartLifecycle extends Lifecycle, Phased {
boolean isAutoStartup();
void stop(Runnable callback);
}
啟動時,最小的phase最先啟動,停止時相反。因此,若物件實現了SmartLifecycle介面,它的getPhase()方法返回Integer.MIN_VALUE,那麼該物件最先啟動,最後停止。若是getPhase()方法返回Integer.MAX_VALUE,那麼該方法最後啟動最先停止。關於phase的值,常規的並未實現SmartLifecycle介面的Lifecycle物件,其值預設為0。因此,負phase值表示要在常規Lifecycle物件之前啟動(在常規Lifecycyle物件之後停止),使用正值則恰恰相反。
SmartLifecycle中stop()方法有一個回撥引數。所有的實現在關閉處理完成後會呼叫回撥的run()方法,相當於開啟非同步關閉功能。
LifecycleProcessor介面在Spring中的預設實現是DefaultLifecycleProcessor類,該類會為每個回撥等待超時,預設超時是30秒。
可以重寫該類預設的引數,該類在容器內預設bean名稱是lifecycleProcessor。比如修改超時時間:
<bean id="lifecycleProcessor" class="org.springframework.context.support.DefaultLifecycleProcessor">
<!-- timeout value in milliseconds -->
<property name="timeoutPerShutdownPhase" value="10000"/>
</bean>
SmartLifecycle的簡單使用
SmartLifecycle介面的實現類,簡單的說下每個方法的作用:
isAutoStartup()返回true時,Spring容器啟動時會去執行start()方法。
isRunning()返回true的時候,容器銷燬時會呼叫stop()方法。
getPhase()返回的是優先順序,如果有多個這樣的類可以指定不同的優先順序,讓其先後執行(銷燬的時候順序相反)。
@Component
public class CustomComponent implements SmartLifecycle {
@Autowired
private JdbcTemplate jdbcTemplate;
private boolean hasData;
@Override
public boolean isRunning() {
// TODO Auto-generated method stub
return hasData;
}
@Override
public void start() {
System.out.println(">>>>>>>>>>>>>");
String result = jdbcTemplate.queryForObject("select name from user ", String.class);
System.out.println("start啟動服務載入的資料:" + result);
hasData = StringUtils.isNotEmpty(result) ? true : false;
}
@Override
public void stop() {
// TODO Auto-generated method stub
}
@Override
public int getPhase() {
// TODO Auto-generated method stub
return 0;
}
@Override
public boolean isAutoStartup() {
// TODO Auto-generated method stub
return true;
}
@Override
public void stop(Runnable arg0) {
if(hasData) {
System.out.println("刪除表");
jdbcTemplate.execute("drop table user");
}
}
}