1. 程式人生 > >Spring ApplicationListener使用方法及問題(onApplicationEvent被呼叫兩次)

Spring ApplicationListener使用方法及問題(onApplicationEvent被呼叫兩次)

開發十年,就只剩下這套架構體系了! >>>   

使用場景

在一些業務場景中,當容器初始化完成之後,需要處理一些操作,比如一些資料的載入、初始化快取、特定任務的註冊等等。這個時候我們就可以使用Spring提供的ApplicationListener來進行操作。

用法

本文以在Spring boot下的使用為例來進行說明。首先,需要實現ApplicationListener介面並實現onApplicationEvent方法。把需要處理的操作放在onApplicationEvent中進行處理:


package com.secbro.learn.context;
 
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextRefreshedEvent;
 
public class ApplicationStartListener implements ApplicationListener<ContextRefreshedEvent>{
    @Override
    public void onApplicationEvent(ContextRefreshedEvent contextRefreshedEvent) {
        System.out.println("我的父容器為:" + contextRefreshedEvent.getApplicationContext().getParent());
        System.out.println("初始化時我被呼叫了。");
    }
}

然後,例項化ApplicationStartListener這個類,在Spring boot中通過一個配置類來進行例項化:


package com.secbro.learn.conf;
 
import com.secbro.learn.context.ApplicationStartListener;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
 
 
@Configuration
public class ListenerConfig {
 
    @Bean
    public ApplicationStartListener applicationStartListener(){
        return new ApplicationStartListener();
    }
}

隨後,啟動Spring boot服務,打印出一下內容:

我的父容器為:null
初始化時我被呼叫了。

從列印的結果可以看出,ApplicationStartListener的onApplicationEvent方法在容器啟動時已經被成功呼叫了。而此時初始化的容器為root容器。

二次呼叫問題

此處使用Spring boot來進行操作,沒有出現二次呼叫的問題。在使用傳統的application.xml和project-servlet.xml配置中會出現二次呼叫的問題。主要原因是初始化root容器之後,會初始化project-servlet.xml對應的子容器。我們需要的是隻執行一遍即可。那麼上面列印父容器的程式碼用來進行判斷排除子容器即可。在業務處理之前新增如下判斷:

if(contextRefreshedEvent.getApplicationContext().getParent() != null){
            return;
}if(contextRefreshedEvent.getApplicationContext().getParent() != null){
            return;
}

這樣其他容器的初始化就會直接返回,而父容器(Parent為null的容器)啟動時將會執行相應的業務操作。

關聯知識

在spring中InitializingBean介面也提供了類似的功能,只不過它進行操作的時機是在所有bean都被例項化之後才進行呼叫。根據不同的業務場景和需求,可選擇不同