欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Springboot事件監(jiān)聽與@Async注解詳解

 更新時間:2024年01月10日 10:29:57   作者:苦糖果與忍冬  
這篇文章主要介紹了Springboot事件監(jiān)聽與@Async注解詳解,在開發(fā)中經(jīng)??梢岳肧pring事件監(jiān)聽來實現(xiàn)觀察者模式,進行一些非事務(wù)性的操作,如記錄日志之類的,需要的朋友可以參考下

一、不求甚解

在開發(fā)中經(jīng)常可以利用Spring事件監(jiān)聽來實現(xiàn)觀察者模式,進行一些非事務(wù)性的操作,如記錄日志之類的。

Controller

Controller中注入ApplicationEventPublisher,并利用它發(fā)布事件即可。

import org.springframework.context.ApplicationEventPublisher;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
@RestController
@RequestMapping("/controller")
public class TestController {
    @Resource
    private ApplicationEventPublisher applicationEventPublisher;
    @GetMapping("/test")
    public String test(@RequestParam String name){
        System.out.println("請求進來了");
        TestEvent event = new TestEvent(this,name);
        applicationEventPublisher.publishEvent(event);
        return "success";
    }
}

Event

event繼承ApplicationEvent即可。

import org.springframework.context.ApplicationEvent;
public class TestEvent extends ApplicationEvent {
    private String name;
    public TestEvent(Object source,String name) {
        super(source);
        this.name=name;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
}

Listener

Listener實現(xiàn)ApplicationListener接口即可?;蛘呤褂聾EventListener注解

接口方式

import org.springframework.context.ApplicationListener;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;
@Component
@Async
public class TestListener implements ApplicationListener<TestEvent> {
    @Override
    public void onApplicationEvent(TestEvent testEvent) {
        System.out.println(testEvent.getName());
    }
}

注解方式

import org.springframework.context.event.EventListener;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;
@Component
@Async
public class TestListener {
    @EventListener
    public void onApplicationEvent(TestEvent testEvent) {
        System.out.println("TestListener:"+Thread.currentThread().getName());
        System.out.println("TestListener:"+testEvent.getName());
    }
}

Postman測試 //localhost:8080/controller/test?name=lisi

在這里插入圖片描述

控制臺打?。?/p>

請求進來了
lisi

曾經(jīng),我一直以為這樣就實現(xiàn)了異步,因為我看公司的代碼都是這樣寫的,現(xiàn)網(wǎng)也沒什么問題。每次照著前輩們的代碼CV一下就可以了,也沒太多想。

二、人云亦云

@Async注解

以前一直用@Async注解,但我好像沒有去深入了解過她。使用她就像使用@Resource一樣自然一樣隨心所欲。

直到某天閑了下來,突發(fā)奇想,想要深入了解一下她。

@Async注解很容易踩坑,首先是必須在啟動類上開啟異步配置@EnableAsync才行,否則還是同步執(zhí)行。如果不指定線程池,則使用Spring默認的線程池 SimpleAsyncTaskExecutor。

方法上一旦標(biāo)記了@Async注解,當(dāng)其它線程調(diào)用這個方法時,就會開啟一個新的子線程去異步處理該業(yè)務(wù)邏輯。

1)在方法上使用該@Async注解,申明該方法是一個異步任務(wù);在類上面使用該@Async注解,申明該類中的所有方法都是異步任務(wù);

2)使用此注解的方法的類對象,必須是Spring管理下的bean對象; 所以需要在類上加上@Component注解。

3)要想使用異步任務(wù),需要在主類上開啟異步配置,即,配置上@EnableAsync注解; 

4)如果不指定線程池的名稱,則使用Spring默認的線程池SimpleAsyncTaskExecutor。

SimpleAsyncTaskExecutor特性:

  • 1)為每個任務(wù)啟動一個新線程,異步執(zhí)行它。
  • 2)支持通過“concurrencyLimit” bean 屬性限制并發(fā)線程。默認情況下,并發(fā)線程數(shù)是無限的。
  • 3)注意:此實現(xiàn)不重用線程!
  • 4)考慮一個線程池 TaskExecutor 實現(xiàn),特別是用于執(zhí)行大量短期任務(wù)。

以上內(nèi)容是我百度后所得,到底對不對呢?我決定親自驗證一下。

所以,使用@Async注解的時候一定要指定自己的線程池?。?!

在啟動類沒有指定注解@EnableAsync的情況下,測試一下打印出當(dāng)前的線程

 @GetMapping("/test")
    public String test(@RequestParam String name){
        System.out.println("TestController請求進來了:"+Thread.currentThread().getName());
        TestEvent event = new TestEvent(this,name);
        applicationEventPublisher.publishEvent(event);
        System.out.println("TestController請求出去了:"+Thread.currentThread().getName());
        return "success";
    }
    @Override
    public void onApplicationEvent(TestEvent testEvent) {
        System.out.println("TestListener:"+Thread.currentThread().getName());
        System.out.println("TestListener:"+testEvent.getName());
    }

在這里插入圖片描述

根據(jù)上述結(jié)果可證明在沒有開啟異步配置@EnableAsync的情況下還是同步執(zhí)行!

三、刨根問底

Springboot中異步默認使用的線程池真的是SimpleAsyncTaskExecutor嗎???

在不指定線程池的情況下,debug查看spring中異步默認的線程池。

開啟異步 在啟動類上添加該注解 @EnableAsync

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableAsync;
@SpringBootApplication
@EnableAsync
public class TestApplication {
    public static void main(String[] args) {
        SpringApplication.run(TestApplication.class, args);
    }
}

獲取spring管理的bean實例,實現(xiàn)這個接口即可: ApplicationContextAware

import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.util.CustomizableThreadCreator;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
@RestController
@RequestMapping("/controller")
public class TestController implements ApplicationContextAware {
    private static ApplicationContext applicationContext;
    @Resource
    private ApplicationEventPublisher applicationEventPublisher;
    @GetMapping("/test")
    public String test(@RequestParam String name){
        System.out.println("TestController請求進來了:"+Thread.currentThread().getName());
        TestEvent event = new TestEvent(this,name);
        // 獲取spring管理的所有的bean的名稱
        String[] beanDefinitionNames = applicationContext.getBeanDefinitionNames();
        for (int i = 0; i <beanDefinitionNames.length ; i++) {
            System.out.println(beanDefinitionNames[i]);
        }
        applicationEventPublisher.publishEvent(event);
        System.out.println("TestController請求出去了:"+Thread.currentThread().getName());
        // 根據(jù)class對象獲取spring管理的bean實例
        CustomizableThreadCreator bean = applicationContext.getBean(CustomizableThreadCreator.class);
        System.out.println("CustomizableThreadCreator:"+bean.getThreadNamePrefix());
        return "success";
    }
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        TestController.applicationContext=applicationContext;
    }
}

在TestListener中打上斷點。

在這里插入圖片描述

當(dāng)前spring版本為5.2.12,可能與spring版本有關(guān),當(dāng)前版本的線程池默認是ThreadPoolTaskExecutor??梢钥吹骄€程池最大容量是Integer的最大值,在高并發(fā)場景下可能導(dǎo)致OOM。因此需要自定義線程池,并在@Async上指定為自定義線程池。

打印出了spring中所管理的bean的名稱,applicationTaskExecutor果然也在。

在這里插入圖片描述

打印出線程池的前綴,再一次驗證確認線程池默認是ThreadPoolTaskExecutor。

在這里插入圖片描述

四、曲突徙薪

最近寫了一個接口,要求響應(yīng)時間1s以內(nèi),并且請求量很大,明確要求一些非重要業(yè)務(wù)的操作都必須異步操作。

按著以前的套路,我還是照著上面一操作了一遍。還好今天研究了一下,否則以后的某天怕是要背一口大鍋。

保持好奇,富有探索,始終對技術(shù)有敏感性?。?!

自定義線程池

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import java.util.concurrent.Executor;
import java.util.concurrent.ThreadPoolExecutor;
@Configuration
public class MyExecutorConfig {
    @Bean("MyExecutor")
    public Executor myExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(10);
        executor.setMaxPoolSize(50);
        executor.setQueueCapacity(2000);
        executor.setKeepAliveSeconds(60);
        executor.setThreadNamePrefix("myExecutor");
        executor.setRejectedExecutionHandler( new ThreadPoolExecutor.CallerRunsPolicy());
        executor.initialize();
        return executor;
    }
}

在異步注解上標(biāo)明使用自定義線程池 @Async(“MyExecutor”)

Jmeter壓測

在這里插入圖片描述

在這里插入圖片描述

在這里插入圖片描述

壓測結(jié)果表明確實切換了線程池,使用了自定義的線程池,并且阻塞隊列已滿,開始朝著最大線程數(shù)邁進!

到此這篇關(guān)于Springboot事件監(jiān)聽與@Async注解詳解的文章就介紹到這了,更多相關(guān)Springboot監(jiān)聽與@Async內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 你知道怎么從Python角度學(xué)習(xí)Java基礎(chǔ)

    你知道怎么從Python角度學(xué)習(xí)Java基礎(chǔ)

    這篇文章主要為大家詳細介紹了Python角度學(xué)習(xí)Java基礎(chǔ)的方法,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來幫助
    2022-02-02
  • 一文秒懂java到底是值傳遞還是引用傳遞

    一文秒懂java到底是值傳遞還是引用傳遞

    這篇文章主要介紹了java到底是值傳遞還是引用傳遞的相關(guān)知識,本文通過幾個例子給大家介紹的非常詳細,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2020-06-06
  • Java利用Picocli開發(fā)一個簡化命令行工具

    Java利用Picocli開發(fā)一個簡化命令行工具

    Picocli 是一個強大、易用且功能豐富的 Java 庫,用于開發(fā)命令行工具,本文我們就來為大家介紹一下Java如何利用Picocli進行命令行簡化功能的吧
    2025-03-03
  • 詳解如何保護SpringBoot配置文件中的敏感信息

    詳解如何保護SpringBoot配置文件中的敏感信息

    使用過SpringBoot配置文件的朋友都知道,資源文件中的內(nèi)容通常情況下是明文顯示,安全性就比較低一些,所以為了提高安全性,就需要對配置文件中的敏感信息進行保護,下面就為大家介紹一下實現(xiàn)方法吧
    2023-07-07
  • Spring數(shù)據(jù)庫連接池實現(xiàn)原理深入刨析

    Spring數(shù)據(jù)庫連接池實現(xiàn)原理深入刨析

    開發(fā)web項目,我們肯定會和數(shù)據(jù)庫打交道,因此就會涉及到數(shù)據(jù)庫鏈接的問題。在以前我們開發(fā)傳統(tǒng)的SSM結(jié)構(gòu)的項目時進行數(shù)據(jù)庫鏈接都是通過JDBC進行數(shù)據(jù)鏈接,我們每和數(shù)據(jù)庫打一次交道都需要先獲取一次鏈接,操作完后再關(guān)閉鏈接,這樣子效率很低,因此就出現(xiàn)了連接池
    2022-11-11
  • MultipartFile中transferTo(File file)的路徑問題及解決

    MultipartFile中transferTo(File file)的路徑問題及解決

    這篇文章主要介紹了MultipartFile中transferTo(File file)的路徑問題及解決方案,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-07-07
  • Springboot項目對數(shù)據(jù)庫用戶名密碼實現(xiàn)加密過程解析

    Springboot項目對數(shù)據(jù)庫用戶名密碼實現(xiàn)加密過程解析

    這篇文章主要介紹了Springboot項目對數(shù)據(jù)庫用戶名密碼實現(xiàn)加密過程解析,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2020-06-06
  • java實現(xiàn)賬號登錄時發(fā)送郵件通知

    java實現(xiàn)賬號登錄時發(fā)送郵件通知

    這篇文章主要為大家詳細介紹了java如何實現(xiàn)在賬號登錄時發(fā)送郵件通知的功能,文中的示例代碼講解詳細,感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下
    2023-09-09
  • springboot3.X版本集成mybatis遇到的問題及解決

    springboot3.X版本集成mybatis遇到的問題及解決

    在將SpringBoot3.X版本與MyBatis集成時,直接參考基于SpringBoot2.X的配置方法會導(dǎo)致各種報錯,尤其是無法注入mapper的bean問題,這主要是因為SpringBoot3.X版本需要搭配MyBatis3.0.3及以上版本才能正常工作,通過更新maven配置至MyBatis3.0.3版本,可以解決這一問題
    2024-09-09
  • 詳解Java分布式IP限流和防止惡意IP攻擊方案

    詳解Java分布式IP限流和防止惡意IP攻擊方案

    這篇文章主要介紹了詳解Java分布式IP限流和防止惡意IP攻擊方案,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-03-03

最新評論