最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

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

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

一、不求甚解

在開發(fā)中經(jīng)??梢岳肧pring事件監(jiān)聽來實現(xiàn)觀察者模式,進行一些非事務性的操作,如記錄日志之類的。

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

在這里插入圖片描述

控制臺打印:

請求進來了
lisi

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

二、人云亦云

@Async注解

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

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

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

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

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

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

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

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

SimpleAsyncTaskExecutor特性:

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

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

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

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

 @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中打上斷點。

在這里插入圖片描述

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

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

在這里插入圖片描述

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

在這里插入圖片描述

四、曲突徙薪

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

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

保持好奇,富有探索,始終對技術(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;
    }
}

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

Jmeter壓測

在這里插入圖片描述

在這里插入圖片描述

在這里插入圖片描述

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

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

相關(guān)文章

  • dubbo擴展點AOP切面功能擴展示例詳解

    dubbo擴展點AOP切面功能擴展示例詳解

    這篇文章主要為大家介紹了dubbo擴展點AOP切面功能擴展示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-08-08
  • 詳解java中產(chǎn)生死鎖的原因及如何避免

    詳解java中產(chǎn)生死鎖的原因及如何避免

    這篇文章主要介紹了java中產(chǎn)生死鎖的原因及如何避免,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2019-04-04
  • Java請求流量合并和拆分提高系統(tǒng)的并發(fā)量示例

    Java請求流量合并和拆分提高系統(tǒng)的并發(fā)量示例

    這篇文章主要為大家介紹了Java請求流量合并和拆分提高系統(tǒng)的并發(fā)量示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步早日升職加薪
    2022-04-04
  • java 字節(jié)流和字符流的區(qū)別詳解

    java 字節(jié)流和字符流的區(qū)別詳解

    這篇文章主要介紹了java 字節(jié)流和字符流的區(qū)別詳解,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2019-09-09
  • Springboot?Mybatis使用pageHelper如何實現(xiàn)分頁查詢

    Springboot?Mybatis使用pageHelper如何實現(xiàn)分頁查詢

    這篇文章主要介紹了Springboot?Mybatis使用pageHelper如何實現(xiàn)分頁查詢問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-05-05
  • SpringBoot2.3集成ELK7.1.0的示例代碼

    SpringBoot2.3集成ELK7.1.0的示例代碼

    這篇文章主要介紹了SpringBoot2.3集成ELK7.1.0的示例代碼,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2020-08-08
  • java入門概念個人理解之package與import淺析

    java入門概念個人理解之package與import淺析

    下面小編就為大家?guī)硪黄猨ava入門概念個人理解之package與import淺析。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2016-08-08
  • 三種Spring BeanName生成器,你了解嗎

    三種Spring BeanName生成器,你了解嗎

    無論我們是通過 XML 文件,還是 Java 代碼,亦或是包掃描的方式去注冊 Bean,都可以不設置BeanName,而Spring均會為之提供默認的 beanName,本文我們就來看看 Spring 中三種處理不同情況的 beanName生成器吧
    2023-09-09
  • 設置tomcat啟用gzip壓縮的具體操作方法

    設置tomcat啟用gzip壓縮的具體操作方法

    如果發(fā)現(xiàn)內(nèi)容沒有被壓縮,可以考慮調(diào)整compressionMinSize大小,如果請求資源小于這個數(shù)值,則不會啟用壓縮
    2013-08-08
  • 淺析Java編程中枚舉類型的定義與使用

    淺析Java編程中枚舉類型的定義與使用

    這篇文章主要介紹了Java編程中枚舉類型的定義與使用,簡單講解了enum關(guān)鍵字與枚舉類的用法,需要的朋友可以參考下
    2016-05-05

最新評論

中卫市| 沅陵县| 乌兰浩特市| 万全县| 固阳县| 闸北区| 宁波市| 东平县| 玉环县| 科技| 平南县| 郴州市| 米林县| 儋州市| 瓮安县| 墨江| 古交市| 德昌县| 阿荣旗| 青神县| SHOW| 内乡县| 台南县| 岗巴县| 哈巴河县| 交城县| 靖远县| 荃湾区| 招远市| 安达市| 达拉特旗| 通海县| 石屏县| 茌平县| 丹棱县| 乌什县| 札达县| 榆社县| 博野县| 麻栗坡县| 苏尼特右旗|