1. 程式人生 > >Spring Boot實踐——事件監聽

Spring Boot實踐——事件監聽

width tar java nco csdn ONBUILD man 初始 ebo

借鑒:https://blog.csdn.net/Harry_ZH_Wang/article/details/79691994

   https://blog.csdn.net/ignorewho/article/details/80702827

   https://www.jianshu.com/p/edd4cb960da7

事件監聽介紹

  Spring提供5種標準的事件監聽:

  1. 上下文更新事件(ContextRefreshedEvent):該事件會在ApplicationContext被初始化或者更新時發布。也可以在調用ConfigurableApplicationContext接口中的refresh()方法時被觸發。
  2. 上下文開始事件(ContextStartedEvent):當容器ConfigurableApplicationContext的Start()方法開始/重新開始容器時觸發該事件。
  3. 上下文停止事件(ContextStoppedEvent):當容ConfigurableApplicationContext的Stop()方法停止容器時觸發該事件。
  4. 上下文關閉事件(ContextClosedEvent):當ApplicationContext被關閉時觸發該事件。容器被關閉時,其管理的所有單例Bean都被銷毀。
  5. 請求處理事件(RequestHandledEvent):在Web應用中,當一個http請求(request)結束觸發該事件。

  Spring Boot擴展了Spring的ApplicationContextEvent,提供了四種事件:

  1. ApplicationStartedEvent :spring boot啟動開始時執行的事件
  2. ApplicationEnvironmentPreparedEvent:spring boot 對應Enviroment已經準備完畢,但此時上下文context還沒有創建。
  3. ApplicationPreparedEvent:spring boot上下文context創建完成,但此時spring中的bean是沒有完全加載完成的。
  4. ApplicationFailedEvent:spring boot啟動異常時執行事件

事件監聽實現

一、Spring Boot提供的四種事件

  1、事件監聽器

  不多說,直接上代碼

  ApplicationStartedEvent事件

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.context.event.ApplicationStartedEvent;
import org.springframework.context.ApplicationListener;

/**
 * Spring Boot擴展了Spring的ApplicationContextEvent,提供了四種事件:
 * ApplicationStartedEvent :spring boot啟動開始時執行的事件
 * ApplicationEnvironmentPreparedEvent:spring boot 對應Enviroment已經準備完畢,但此時上下文context還沒有創建。
 * ApplicationPreparedEvent:spring boot上下文context創建完成,但此時spring中的bean是沒有完全加載完成的。
 * ApplicationFailedEvent:spring boot啟動異常時執行事件
 * @ClassName: CustomApplicationListenerStarted 
 * @author OnlyMate
 * @Date 2018年9月14日 下午4:22:43  
 *
 */
public class CustomApplicationListenerStarted implements ApplicationListener<ApplicationStartedEvent> {
    private Logger logger = LoggerFactory.getLogger(CustomApplicationListenerEnvironmentPrepared.class);
    
    @Override
    public void onApplicationEvent(ApplicationStartedEvent event) {
        logger.info("CustomApplicationListenerStarted ==> onApplicationEvent method");
    }

}

ApplicationEnvironmentPreparedEvent事件

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.context.event.ApplicationEnvironmentPreparedEvent;
import org.springframework.context.ApplicationListener;

/**
 * Spring Boot擴展了Spring的ApplicationContextEvent,提供了四種事件:
 * ApplicationStartedEvent :spring boot啟動開始時執行的事件
 * ApplicationEnvironmentPreparedEvent:spring boot 對應Enviroment已經準備完畢,但此時上下文context還沒有創建。
 * ApplicationPreparedEvent:spring boot上下文context創建完成,但此時spring中的bean是沒有完全加載完成的。
 * ApplicationFailedEvent:spring boot啟動異常時執行事件
 * @ClassName: CustomApplicationListenerEnvironmentPrepared 
 * @author OnlyMate
 * @Date 2018年9月14日 下午4:22:43  
 *
 */
public class CustomApplicationListenerEnvironmentPrepared implements ApplicationListener<ApplicationEnvironmentPreparedEvent> {
    private Logger logger = LoggerFactory.getLogger(CustomApplicationListenerEnvironmentPrepared.class);
    
    @Override
    public void onApplicationEvent(ApplicationEnvironmentPreparedEvent event) {
        logger.info("CustomApplicationListenerEnvironmentPrepared ==> onApplicationEvent method : {}", getClass().getSimpleName());
    }

ApplicationPreparedEvent事件

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.context.event.ApplicationPreparedEvent;
import org.springframework.context.ApplicationListener;

/**
 * Spring Boot擴展了Spring的ApplicationContextEvent,提供了四種事件:
 * ApplicationStartedEvent :spring boot啟動開始時執行的事件
 * ApplicationEnvironmentPreparedEvent:spring boot 對應Enviroment已經準備完畢,但此時上下文context還沒有創建。
 * ApplicationPreparedEvent:spring boot上下文context創建完成,但此時spring中的bean是沒有完全加載完成的。
 * ApplicationFailedEvent:spring boot啟動異常時執行事件
 * @ClassName: CustomApplicationListenerPrepared 
 * @author OnlyMate
 * @Date 2018年9月14日 下午4:22:43  
 *
 */
public class CustomApplicationListenerPrepared implements ApplicationListener<ApplicationPreparedEvent> {
    private Logger logger = LoggerFactory.getLogger(CustomApplicationListenerEnvironmentPrepared.class);
    
    @Override
    public void onApplicationEvent(ApplicationPreparedEvent event) {
        logger.info("CustomApplicationListenerPrepared ==> onApplicationEvent method : {}", getClass().getSimpleName());
    }

}

ApplicationFailedEvent事件

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.context.event.ApplicationFailedEvent;
import org.springframework.context.ApplicationListener;

/**
 * Spring Boot擴展了Spring的ApplicationContextEvent,提供了四種事件:
 * ApplicationStartedEvent :spring boot啟動開始時執行的事件
 * ApplicationEnvironmentPreparedEvent:spring boot 對應Enviroment已經準備完畢,但此時上下文context還沒有創建。
 * ApplicationPreparedEvent:spring boot上下文context創建完成,但此時spring中的bean是沒有完全加載完成的。
 * ApplicationFailedEvent:spring boot啟動異常時執行事件
 * @ClassName: CustomApplicationListenerFailed 
 * @author OnlyMate
 * @Date 2018年9月14日 下午4:22:43  
 *
 */
public class CustomApplicationListenerFailed implements ApplicationListener<ApplicationFailedEvent> {
    private Logger logger = LoggerFactory.getLogger(CustomApplicationListenerEnvironmentPrepared.class);
    
    @Override
    public void onApplicationEvent(ApplicationFailedEvent event) {
        logger.info("CustomApplicationListenerFailed ==> onApplicationEvent method : {}", getClass().getSimpleName());
    }

}

  2、註冊事件監聽器

import java.util.HashSet;
import java.util.Set;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.servlet.ServletComponentScan;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ConfigurableApplicationContext;

import com.only.mate.springboot.listener.original.CustomApplicationListenerEnvironmentPrepared;
import com.only.mate.springboot.listener.original.CustomApplicationListenerFailed;
import com.only.mate.springboot.listener.original.CustomApplicationListenerPrepared;
import com.only.mate.springboot.listener.original.CustomApplicationListenerStarted;


@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class, HibernateJpaAutoConfiguration.class})
//使用 @EnableWebMvc 註解,需要以編程的方式指定視圖文件相關配置;
//@EnableWebMvc
//使用 @EnableAutoConfiguration 註解,會讀取 application.properties 或 application.yml 文件中的配置
@EnableAutoConfiguration
@ServletComponentScan//springboot啟動類掃描servlet組件(過濾器)
public class Application {
    public static ApplicationContext applicationContext;
    
    private static final Logger logger = LoggerFactory.getLogger(Application.class);

    public static void main(String[] args) {
        startApplication(args);
    }

    public static ApplicationContext startApplication(String[] args) {
        if (applicationContext == null) {
            logger.info(" >>> Springboot Application 開始啟動...");
            SpringApplicationBuilder builder = new SpringApplicationBuilder(Application.class);
            SpringApplication application = builder.application();
            application.addListeners(new CustomApplicationListenerEnvironmentPrepared());//這裏註冊事件監聽器
            application.addListeners(new CustomApplicationListenerFailed());//這裏註冊事件監聽器
            application.addListeners(new CustomApplicationListenerPrepared());//這裏註冊事件監聽器
            application.addListeners(new CustomApplicationListenerStarted());//這裏註冊事件監聽器
            
            applicationContext = application.run(args);
            logger.info(" >>> Springboot Application 啟動完成!");
        }
        return applicationContext;
    }
    
    public static ApplicationContext getApplicationContext() {
        if (applicationContext == null) {
            logger.error(" >>> Error:Springboot Application ApplicationContext is Null.");
        }
        return applicationContext;
    }

}

@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class, HibernateJpaAutoConfiguration.class})
//使用 @EnableWebMvc 註解,需要以編程的方式指定視圖文件相關配置;
//@EnableWebMvc
//使用 @EnableAutoConfiguration 註解,會讀取 application.properties 或 application.yml 文件中的配置
@EnableAutoConfiguration
@ServletComponentScan//springboot啟動類掃描servlet組件(過濾器)
public class Application {
    public static ApplicationContext applicationContext;
    
    private static final Logger logger = LoggerFactory.getLogger(Application.class);

    public static void main(String[] args) {
        SpringApplication application = new SpringApplication(Application.class);
        application.addListeners(new CustomApplicationListenerEnvironmentPrepared());//這裏註冊事件監聽器
        application.addListeners(new CustomApplicationListenerFailed());//這裏註冊事件監聽器
        application.addListeners(new CustomApplicationListenerPrepared());//這裏註冊事件監聽器
        application.addListeners(new CustomApplicationListenerStarted());//這裏註冊事件監聽器
        application.run(args);
    }
}

註意:註冊事件監聽器一定要在啟動之前註冊。

  3、效果圖

技術分享圖片

技術分享圖片

啟動成功是只有三個事件被監聽到的。

二、自定義事件監聽

  Spring的事件遵循的流程:

  1. 自定義事件,繼承ApplicationEvent(org.springframework.context.ApplicationEvent)
  2. 自定義監聽,實現ApplicationListener<T>(org.springframework.context.ApplicationListener)接口,然後實現onApplicationEvent方法
  3. 使用容器觸發事件

  1、自定義事件

/**
 * @Description: 自定義事件 
 * @ClassName: CustomEvent 
 * @author OnlyMate
 * @Date 2018年9月14日 下午3:01:58  
 *
 */
public class CustomEvent extends ApplicationEvent {
    
    private static final long serialVersionUID = -7058371859589691525L;
    private Logger logger = LoggerFactory.getLogger(CustomEvent.class);    
    
    private String msg;
    
    public CustomEvent(Object source,String msg) {
        super(source);
        this.msg = msg;
    }

    /**
     * 自定義監聽器觸發的透傳打印方法
     * @Title: printMsg 
     * @author OnlyMate
     * @Date 2018年9月14日 下午3:10:45 
     * @param msg
     */
    public void printMsg(String msg) {
        logger.info("CustomEvent ==> printMsg method 自定義事件: {}", msg);
    }
    
    public String getMsg() {
        return msg;
    }

    public void setMsg(String msg) {
        this.msg = msg;
    }

}

  2、自定義事件發布

import javax.annotation.Resource;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Service;

/**
 * 發布消息服務
 * @ClassName: CustomListenerServie 
 * @author OnlyMate
 * @Date 2018年9月14日 下午3:18:46  
 *
 */
@Service(value="customListenerServie")
public class CustomListenerServie {
    private Logger logger = LoggerFactory.getLogger(CustomListenerServie.class);    
    
    //上下文對象
    @Resource
    private ApplicationContext applicationContext;

    /**
     * 發布消息
     * @Title: publish 
     * @author OnlyMate
     * @Date 2018年9月14日 下午3:18:35 
     * @param msg
     */
    public void publish(String msg) {
        //通過上下文對象發布監聽
        applicationContext.publishEvent(new CustomEvent(this,msg));
        logger.info("CustomListenerServie ==> publish method : {}", msg);
    }
}

  3、觸發自定義事件

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import com.only.mate.springboot.listener.CustomListenerServie;

@Controller
@RequestMapping(value="/listener")
public class CustomListenerController {
    @Autowired
    @Qualifier(value = "customListenerServie")
    private CustomListenerServie customListenerServie;

    @ResponseBody
    @RequestMapping(value="/testevent")
    public String testEvent() {
        customListenerServie.publish("測試監聽");
        return "success";
    }
}

  4、自定義事件監聽器並註冊事件監聽器

  Spring Boot進行事件監聽有四種方式:

  1. 手工向ApplicationContext中添加監聽器
  2. 在application.properties中配置監聽器
  3. 將監聽器裝載入Spring容器
  4. 通過@EventListener註解實現事件監聽

  a、手工向ApplicationContext中添加監聽器

  事件監聽器
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationListener;

/**
 * 自定義監聽器,監聽事件為CustomEvent
 * @ClassName: CustomListener 
 * @author OnlyMate
 * @Date 2018年9月14日 下午3:13:43  
 *
 */
public class CustomListener implements ApplicationListener<CustomEvent>{
    private Logger logger = LoggerFactory.getLogger(CustomAnnotationListener.class);    
    /**
     * 對監聽到的事件進行處理
     */
    @Override
    public void onApplicationEvent(CustomEvent event) {
        //這裏不做處理,只對消息進行透傳打印,實際情況,
        //可以根據項目進行邏輯進行處理
        event.printMsg(event.getMsg());
        logger.info("CustomListener ==> onApplicationEvent method : {}", event.getMsg());
    }

}
  配置
import java.util.HashSet;
import java.util.Set;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.servlet.ServletComponentScan;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ConfigurableApplicationContext;

import com.only.mate.springboot.listener.CustomListener;

@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class, HibernateJpaAutoConfiguration.class})
//使用 @EnableWebMvc 註解,需要以編程的方式指定視圖文件相關配置;
//@EnableWebMvc
//使用 @EnableAutoConfiguration 註解,會讀取 application.properties 或 application.yml 文件中的配置
@EnableAutoConfiguration
@ServletComponentScan//springboot啟動類掃描servlet組件(過濾器)
public class Application {
    public static ApplicationContext applicationContext;
    
    private static final Logger logger = LoggerFactory.getLogger(Application.class);

    public static void main(String[] args) {
        ConfigurableApplicationContext context = SpringApplication.run(Application.class, args);
        context.addApplicationListener(new CustomListener());//這裏註冊事件監聽器
    }
}

  或

import java.util.HashSet;
import java.util.Set;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.servlet.ServletComponentScan;
import org.springframework.context.ApplicationContext;

import com.only.mate.springboot.listener.CustomListener;


@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class, HibernateJpaAutoConfiguration.class})
//使用 @EnableWebMvc 註解,需要以編程的方式指定視圖文件相關配置;
//@EnableWebMvc
//使用 @EnableAutoConfiguration 註解,會讀取 application.properties 或 application.yml 文件中的配置
@EnableAutoConfiguration
@ServletComponentScan//springboot啟動類掃描servlet組件(過濾器)
public class Application {
    public static ApplicationContext applicationContext;
    
    private static final Logger logger = LoggerFactory.getLogger(Application.class);

    public static void main(String[] args) {
        startApplication(args);
    }

    public static ApplicationContext startApplication(String[] args) {
        if (applicationContext == null) {
            logger.info(" >>> Springboot Application 開始啟動...");
            SpringApplicationBuilder builder = new SpringApplicationBuilder(Application.class);
            SpringApplication application = builder.application();
            application.addListeners(new CustomListener());//這裏註冊事件監聽器
            applicationContext = application.run(args);
            logger.info(" >>> Springboot Application 啟動完成!");
        }
        return applicationContext;
    }
    
    public static ApplicationContext getApplicationContext() {
        if (applicationContext == null) {
            logger.error(" >>> Error:Springboot Application ApplicationContext is Null.");
        }
        return applicationContext;
    }

}
  效果圖

  訪問http://localhost:8088/springboot/listener/testevent

技術分享圖片

  b、在application.properties中配置監聽器

  事件監聽器
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationListener;

/**
 * 自定義監聽器,監聽事件為CustomEvent
 * @ClassName: CustomListener 
 * @author OnlyMate
 * @Date 2018年9月14日 下午3:13:43  
 *
 */
public class CustomListener implements ApplicationListener<CustomEvent>{
    private Logger logger = LoggerFactory.getLogger(CustomAnnotationListener.class);    
    /**
     * 對監聽到的事件進行處理
     */
    @Override
    public void onApplicationEvent(CustomEvent event) {
        //這裏不做處理,只對消息進行透傳打印,實際情況,
        //可以根據項目進行邏輯進行處理
        event.printMsg(event.getMsg());
        logger.info("CustomListener ==> onApplicationEvent method : {}", event.getMsg());
    }

}

  配置

  在application.properties中配置監聽

context.listener.classes=com.only.mate.springboot.listener.CustomListener
  效果圖

  訪問http://localhost:8088/springboot/listener/testevent

技術分享圖片

  c、將監聽器裝載入Spring容器

  事件監聽器
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationListener;
import org.springframework.stereotype.Component;

/**
 * 自定義監聽器,監聽事件為CustomEvent
 * @ClassName: CustomListener 
 * @author OnlyMate
 * @Date 2018年9月14日 下午3:13:43  
 *
 */
@Component
public class CustomListener implements ApplicationListener<CustomEvent>{
    private Logger logger = LoggerFactory.getLogger(CustomAnnotationListener.class);    
    /**
     * 對監聽到的事件進行處理
     */
    @Override
    public void onApplicationEvent(CustomEvent event) {
        //這裏不做處理,只對消息進行透傳打印,實際情況,
        //可以根據項目進行邏輯進行處理
        event.printMsg(event.getMsg());
        logger.info("CustomListener ==> onApplicationEvent method : {}", event.getMsg());
    }

}

這裏用@Component註解將事件監聽器註冊到Spring容器中

  效果圖

  訪問http://localhost:8088/springboot/listener/testevent

技術分享圖片

  d、通過@EventListener註解實現事件監聽

  事件監聽器
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Component;

@Component
public class CustomAnnotationListener {
    private Logger logger = LoggerFactory.getLogger(CustomAnnotationListener.class);    
    
    @EventListener
    public void listener1(CustomEvent event) {
        event.printMsg(event.getMsg());
        logger.info("CustomAnnotationListener ==> listener1 method : {}", event.getMsg());
    }

    @EventListener
    public void listener2(CustomEvent event) {
        event.printMsg(event.getMsg());
        logger.info("CustomAnnotationListener ==> listener2 method : {}", event.getMsg());
    }
}
  效果圖

  訪問http://localhost:8088/springboot/listener/testevent

技術分享圖片


  如果是使用配置文件來註冊的話,ApplicationStartedEvent這種事件是監聽不到的,因為配置文件加載代表著Spring Boot已經啟動,不過其他兩種事件已經足夠給項目上使用了。

Spring Boot實踐——事件監聽