SpringBoot下使用自定義監(jiān)聽事件的流程分析
事件機制是Spring的一個功能,目前我們使用了SpringBoot框架,所以記錄下事件機制在SpringBoot框架下的使用,同時實現(xiàn)異步處理。事件機制其實就是使用了觀察者模式(發(fā)布-訂閱模式)。
Spring的事件機制經(jīng)過如下流程:
- 1、自定義事件,繼承org.springframework.context.ApplicationEvent抽象類
- 2、定義事件監(jiān)聽器,實現(xiàn)org.springframework.context.ApplicationListener接口
- 3、在Spring容器中發(fā)布事件
SpringBoot的實例程序
實現(xiàn)一個保存用戶的時候,向用戶提供的郵箱發(fā)送一封郵件的功能,同時采用異步處理。
自定義事件
import org.springframework.context.ApplicationEvent; public class EmailEvent extends ApplicationEvent { private static final long serialVersionUID = 3733891603598996786L; private String emailAddress; public EmailEvent(String emailAddress) { super(emailAddress); this.emailAddress = emailAddress; } public String getEmailAddress() { return emailAddress; } public void setEmailAddress(String emailAddress) { this.emailAddress = emailAddress; } }
定義事件監(jiān)聽器
import java.util.concurrent.TimeUnit; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.context.ApplicationListener; import org.springframework.scheduling.annotation.Async; import org.springframework.stereotype.Component; @Component public class EmailEventListener implements ApplicationListener<EmailEvent> { private static Logger log = LoggerFactory.getLogger(EmailEventListener.class); // 異步處理 @Async @Override public void onApplicationEvent(EmailEvent event) { log.info("監(jiān)聽到事件--郵箱地址:" + event.getEmailAddress()); //模擬處理的耗時3s try { TimeUnit.SECONDS.sleep(3); } catch (InterruptedException e) { e.printStackTrace(); } log.info("事件處理完成"); } }
發(fā)布事件
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationContext; import org.springframework.stereotype.Component; @Component public class EmailEventPublish { @Autowired private ApplicationContext applicationContext; public void publishEvent(String emailAddress) { EmailEvent event = new EmailEvent(emailAddress); applicationContext.publishEvent(event); } }
調(diào)用事件
import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import com.example.demo.event.EmailEventPublish; @RestController public class EventController { private static Logger log = LoggerFactory.getLogger(EventController.class); @Autowired private EmailEventPublish emailEventPublish; @RequestMapping("/event") public void publishEvent(@RequestParam String emailAddress) { // 發(fā)布事件 -- 采用異步處理 emailEventPublish.publishEvent(emailAddress); // 正常該語句先執(zhí)行 log.info("Controller業(yè)務(wù)處理"); } }
結(jié)果
訪問如下地址
http://localhost:8080/event?emailAddress=plf@163.com
結(jié)果為
2023-08-04 21:21:14.338 INFO 6400 --- [nio-8080-exec-1] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring FrameworkServlet 'dispatcherServlet'
2023-08-04 21:21:14.338 INFO 6400 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : FrameworkServlet 'dispatcherServlet': initialization started
2023-08-04 21:21:14.370 INFO 6400 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : FrameworkServlet 'dispatcherServlet': initialization completed in 32 ms
2023-08-04 21:21:14.429 INFO 6400 --- [nio-8080-exec-1] .s.a.AnnotationAsyncExecutionInterceptor : No task executor bean found for async processing: no bean of type TaskExecutor and no bean named 'taskExecutor' either
2023-08-04 21:21:14.534 INFO 6400 --- [nio-8080-exec-1] c.e.demo.controller.EventController : Controller業(yè)務(wù)處理
2023-08-04 21:21:14.535 INFO 6400 --- [cTaskExecutor-1] c.example.demo.event.EmailEventListener : 監(jiān)聽到事件--郵箱地址:plf@163.com
2023-08-04 21:21:17.536 INFO 6400 --- [cTaskExecutor-1] c.example.demo.event.EmailEventListener : 事件處理完成
上述結(jié)果可知是實現(xiàn)了異步處理,先打印了事件之后的程序,等時間到再執(zhí)行監(jiān)聽程序的代碼。
實現(xiàn)異步處理就是在監(jiān)聽事件執(zhí)行業(yè)務(wù)代碼的方法上添加 @Async
注解,同時在啟動類上添加 @EnableAsync
即可。
上面的日志還提到了 TaskExecutor
,這是如果有自定義的線程池就會去調(diào)用,如果沒有就用默認的。我們也可以自己定義一個 TaskExecutor
。
import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.lang.Nullable; import org.springframework.scheduling.annotation.AsyncConfigurer; import org.springframework.scheduling.annotation.EnableAsync; import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; import java.util.concurrent.Executor; import java.util.concurrent.ThreadPoolExecutor; @EnableAsync @Configuration public class ThreadPool implements AsyncConfigurer { @Nullable @Override @Bean("taskExecutor") public Executor getAsyncExecutor() { ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); // 線程池創(chuàng)建時候初始化的線程數(shù) executor.setCorePoolSize(10); // 線程池最大的線程數(shù),只有在緩沖隊列滿了之后才會申請超過核心線程數(shù)的線程 executor.setMaxPoolSize(20); // 用來緩沖執(zhí)行任務(wù)的隊列 executor.setQueueCapacity(200); // 允許線程的空閑時間60秒 executor.setKeepAliveSeconds(60); // 線程池名的前綴 executor.setThreadNamePrefix("taskExecutor-"); // 線程池對拒絕任務(wù)的處理策略 executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy()); executor.initialize(); return executor; } @Nullable @Override public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() { return null; } }
結(jié)果
2023-08-04 21:27:36.507 INFO 7848 --- [nio-8080-exec-2] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring FrameworkServlet 'dispatcherServlet'
2023-08-04 21:27:36.507 INFO 7848 --- [nio-8080-exec-2] o.s.web.servlet.DispatcherServlet : FrameworkServlet 'dispatcherServlet': initialization started
2023-08-04 21:27:36.537 INFO 7848 --- [nio-8080-exec-2] o.s.web.servlet.DispatcherServlet : FrameworkServlet 'dispatcherServlet': initialization completed in 30 ms
2023-08-04 21:27:36.757 INFO 7848 --- [nio-8080-exec-2] c.e.demo.controller.EventController : Controller業(yè)務(wù)處理
2023-08-04 21:27:36.757 INFO 7848 --- [ taskExecutor-1] c.example.demo.event.EmailEventListener : 監(jiān)聽到事件--郵箱地址:plf@163.com
2023-08-04 21:27:39.757 INFO 7848 --- [ taskExecutor-1] c.example.demo.event.EmailEventListener : 事件處理完成
可知是使用我們定義的線程池[ taskExecutor-1]
。
總結(jié)
Spring的事件機制是一個很實用的一個功能,在監(jiān)聽和異步處理相關(guān)的功能比較適合。
到此這篇關(guān)于SpringBoot下使用自定義監(jiān)聽事件的文章就介紹到這了,更多相關(guān)SpringBoot自定義監(jiān)聽事件內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
java調(diào)用python代碼的兩種實現(xiàn)方式:Runtime.exec()和Jython
在Java中調(diào)用Python代碼有多種方法,包括使用Runtime.exec()和第三方庫如Jython,Runtime.exec()通過系統(tǒng)命令執(zhí)行Python腳本,適用于簡單的調(diào)用場景,Jython則是一個Python的Java實現(xiàn),允許在Java中直接運行Python代碼,適用于更深層次的集成需求2025-01-01SpringBoot項目啟動報錯:命令行太長解決的兩種解決方法
SpringBoot項目啟動時可能會遇到命令行太長的錯誤,本文介紹兩種解決方法修改.idea\workspace.xml文件和執(zhí)行maven的clean命令或重啟IDEA,這些操作可以有效解決啟動問題,需要的朋友可以參考下2024-10-10java中jdbcTemplate的queryForList(坑)
本文主要介紹了java中jdbcTemplate的queryForList,文中通過示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下2021-09-09解決Spring Cloud Gateway獲取body內(nèi)容,不影響GET請求的操作
這篇文章主要介紹了解決Spring Cloud Gateway獲取body內(nèi)容,不影響GET請求的操作,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-12-12mybatis寫xml時數(shù)字類型千萬別用 !=‘‘(不為空串)進行判斷的示例詳解
這篇文章主要介紹了mybatis寫xml時數(shù)字類型千萬別用 !=‘‘(不為空串)進行判斷的示例詳解,本文給大家介紹的非常詳細,對大家的學(xué)習或工作具有一定的參考借鑒價值,需要的朋友可以參考下2020-09-09SpringBoot過濾器如何獲取POST請求的JSON參數(shù)
這篇文章主要介紹了SpringBoot過濾器如何獲取POST請求的JSON參數(shù)操作,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-08-08Java之MultipartFile和File類型互轉(zhuǎn)方式
這篇文章主要介紹了Java之MultipartFile和File類型互轉(zhuǎn)方式,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2023-09-09Java多線程編程之使用Exchanger數(shù)據(jù)交換實例
這篇文章主要介紹了Java多線程編程之使用Exchanger數(shù)據(jù)交換實例,本文直接給出實例代碼,需要的朋友可以參考下2015-05-05