Spring Boot實踐——事件監聽
借鑒: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種標準的事件監聽:
- 上下文更新事件(ContextRefreshedEvent):該事件會在ApplicationContext被初始化或者更新時發布。也可以在調用ConfigurableApplicationContext接口中的refresh()方法時被觸發。
- 上下文開始事件(ContextStartedEvent):當容器ConfigurableApplicationContext的Start()方法開始/重新開始容器時觸發該事件。
- 上下文停止事件(ContextStoppedEvent):當容ConfigurableApplicationContext的Stop()方法停止容器時觸發該事件。
- 上下文關閉事件(ContextClosedEvent):當ApplicationContext被關閉時觸發該事件。容器被關閉時,其管理的所有單例Bean都被銷毀。
- 請求處理事件(RequestHandledEvent):在Web應用中,當一個http請求(request)結束觸發該事件。
Spring Boot擴展了Spring的ApplicationContextEvent,提供了四種事件:
- ApplicationStartedEvent :spring boot啟動開始時執行的事件
- ApplicationEnvironmentPreparedEvent:spring boot 對應Enviroment已經準備完畢,但此時上下文context還沒有創建。
- ApplicationPreparedEvent:spring boot上下文context創建完成,但此時spring中的bean是沒有完全加載完成的。
- 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的事件遵循的流程:
- 自定義事件,繼承ApplicationEvent(org.springframework.context.ApplicationEvent)
- 自定義監聽,實現ApplicationListener<T>(org.springframework.context.ApplicationListener)接口,然後實現onApplicationEvent方法
- 使用容器觸發事件
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進行事件監聽有四種方式:
- 手工向ApplicationContext中添加監聽器
- 在application.properties中配置監聽器
- 將監聽器裝載入Spring容器
- 通過@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實踐——事件監聽