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

SpringBoot中@EnableAsync和@Async注解的使用小結(jié)

 更新時間:2023年11月16日 10:00:28   作者:ACGkaka_  
在SpringBoot中,可以通過@EnableAsync注解來啟動異步方法調(diào)用的支持,通過@Async注解來標識異步方法,讓方法能夠在異步線程中執(zhí)行,本文就來介紹一下,感興趣的可以了解一下

異步的優(yōu)點:

  • 提高應(yīng)用程序的響應(yīng)能力
  • 提高系統(tǒng)的吞吐量
  • 節(jié)約資源:異步操作可以避免在請求處理期間占用過多的線程資源,減少服務(wù)器的負載。
  • 優(yōu)化用戶體驗

需要注意的問題:

  • 事務(wù)問題:異步處理時,需要注意在事務(wù)沒有結(jié)束時做異步操作,可能會導(dǎo)致讀取不到甚至覆蓋事務(wù)中新增或更新的數(shù)據(jù)內(nèi)容。

在 Spring Boot 中,可以通過 @EnableAsync 注解來啟動異步方法調(diào)用的支持,通過 @Async 注解來標識異步方法,讓方法能夠在異步線程中執(zhí)行。下面分別介紹它們的使用方法。

1.@EnableAsync 注解

@EnableAsync 是一個 Spring Boot 中用于啟動異步方法調(diào)用的注解。使用 @EnableAsync 注解時,需要將其放置在一個配置類上,并且在配置類中通過 @Bean 方法創(chuàng)建一個線程池。

下面舉個例子:

1.1 配置類使用示例

AsyncTaskExecutorConfig 類通過 @EnableAsync 注解來啟用異步方法調(diào)用,然后在配置類中通過 @Bean 方法創(chuàng)建了一個名為 asyncExecutor 的線程池,用于執(zhí)行異步方法。

import com.demo.async.ContextCopyingDecorator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.task.TaskExecutor;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

import java.util.concurrent.ThreadPoolExecutor;

/**
 * <p> @Title AsyncTaskExecutorConfig
 * <p> @Description 異步線程池配置
 *
 * @author ACGkaka
 * @date 2023/4/24 19:48
 */
@EnableAsync
@Configuration
public class AsyncTaskExecutorConfig {

    /**
     * 核心線程數(shù)(線程池維護線程的最小數(shù)量)
     */
    private int corePoolSize = 10;
    /**
     * 最大線程數(shù)(線程池維護線程的最大數(shù)量)
     */
    private int maxPoolSize = 200;
    /**
     * 隊列最大長度
     */
    private int queueCapacity = 10;

    @Bean
    public TaskExecutor taskExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(corePoolSize);
        executor.setMaxPoolSize(maxPoolSize);
        executor.setQueueCapacity(queueCapacity);
        executor.setThreadNamePrefix("MyExecutor-");
        // for passing in request scope context 轉(zhuǎn)換請求范圍的上下文
        executor.setTaskDecorator(new ContextCopyingDecorator());
        // rejection-policy:當pool已經(jīng)達到max size的時候,如何處理新任務(wù)
        // CALLER_RUNS:不在新線程中執(zhí)行任務(wù),而是有調(diào)用者所在的線程來執(zhí)行
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        executor.setWaitForTasksToCompleteOnShutdown(true);
        executor.initialize();
        return executor;
    }
}

1.2 復(fù)制請求上下文

ContextCopyingDecorator 類使用了裝飾者模式,用于將主線程中的請求上下文拷貝到異步子線程中,并且在異步子線程執(zhí)行之后清空請求的上下文。

import org.slf4j.MDC;
import org.springframework.core.task.TaskDecorator;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;

import java.util.Map;

/**
 * <p> @Title ContextCopyingDecorator
 * <p> @Description 上下文拷貝裝飾者模式
 *
 * @author ACGkaka
 * @date 2023/4/24 20:20
 */
public class ContextCopyingDecorator implements TaskDecorator {
    @Override
    public Runnable decorate(Runnable runnable) {
        try {
            // 從父線程中獲取上下文,然后應(yīng)用到子線程中
            RequestAttributes requestAttributes = RequestContextHolder.currentRequestAttributes();
            Map<String, String> previous = MDC.getCopyOfContextMap();
            SecurityContext securityContext = SecurityContextHolder.getContext();
            return () -> {
                try {
                    if (previous == null) {
                        MDC.clear();
                    } else {
                        MDC.setContextMap(previous);
                    }
                    RequestContextHolder.setRequestAttributes(requestAttributes);
                    SecurityContextHolder.setContext(securityContext);
                    runnable.run();
                } finally {
                    // 清除請求數(shù)據(jù)
                    MDC.clear();
                    RequestContextHolder.resetRequestAttributes();
                    SecurityContextHolder.clearContext();
                }
            };
        } catch (IllegalStateException e) {
            return runnable;
        }
    }
}

2.用法1:@Async 注解

@Async 注解是一個 Spring Boot 中用于標識異步方法的注解,通過在方法上添加 @Async 注解,可以讓該方法在異步線程中執(zhí)行。

下面舉個例子:

2.1 測試Controller

DemoController 類中聲明了 /demo/test 接口,接口中調(diào)用了 demoService.testError() 方法。

import com.demo.common.Result;
import com.demo.service.DemoService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * <p> @Title DemoController
 * <p> @Description 測試Controller
 *
 * @author ACGkaka
 * @date 2023/4/24 18:02
 */
@RestController
@RequestMapping("/demo")
public class DemoController {

    @Autowired
    private DemoService demoService;

    @RequestMapping("/test")
    public Result<Object> test() {
        Result<Object> result = Result.succeed();
        System.out.println("start...");
        demoService.testError();
        System.out.println("end...");
        return result;
    }
}

2.2 測試Service

/**
 * <p> @Title DemoService
 * <p> @Description 測試Service
 *
 * @author ACGkaka
 * @date 2023/4/24 18:13
 */
public interface DemoService {

    /**
     * 測試異常
     */
    void testError() throws InterruptedException;
}

2.3 測試ServiceImpl

DemoServiceImpl 類使用了 @Async 注解,用于異步調(diào)用,testError() 方法中拋出了異常,用于測試異步執(zhí)行。

這里 @Async 注解的 value 值指定了我們在配置類中聲明的 taskExecutor 線程池。

  • 假如只配置了一個線程池,直接用 @Async 注解就會用自定義的線程池執(zhí)行。
  • 假如配置了多個線程池,用 @Async("name") 來指定使用哪個線程池,如果沒有指定,會用默認的 SimpleAsyncTaskExecutor 來處理。
import com.demo.service.DemoService;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

/**
 * <p> @Title DemoServiceImpl
 * <p> @Description 測試ServiceImpl
 *
 * @author ACGkaka
 * @date 2023/4/24 18:14
 */
@Service
public class DemoServiceImpl implements DemoService {
    @Async("taskExecutor")
    @Override
    public void testError() throws InterruptedException {
        throw new RuntimeException("測試異常");
    }
}

2.4.測試

訪問接口:http://localhost:8080/demo/test

訪問結(jié)果如下,可見異常并沒有接口返回正常的結(jié)果,異步測試成功。

在這里插入圖片描述

3.用法2:直接使用 taskExecutor 做異步

由于我們在第1步中,將異步線程池注入到了 taskExecutor Bean 容器中,我們就可以直接通過 @Autowired 或者 @Resource 獲取到線程池,然后使用。

我們通過直接使用 taskExecutor 線程池的方式,重新實現(xiàn) DemoServiceImpl.java:

3.1 重新實現(xiàn):測試ServiceImpl

import com.demo.service.DemoService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.core.task.TaskExecutor;
import org.springframework.stereotype.Service;

/**
 * <p> @Title DemoServiceImpl
 * <p> @Description 測試ServiceImpl
 *
 * @author ACGkaka
 * @date 2023/4/24 18:14
 */
@Service
public class DemoServiceImpl implements DemoService {

    @Qualifier("taskExecutor")
    @Autowired
    private TaskExecutor taskExecutor;

    @Override
    public void testError() {
        taskExecutor.execute(() -> {
            throw new RuntimeException("測試異常");
        });
    }
}

3.2 測試

訪問接口:http://localhost:8080/demo/test

訪問結(jié)果如下,可見異常并沒有接口返回正常的結(jié)果,異步測試成功,直接使用線程池的方式也可行。

在這里插入圖片描述

在這里插入圖片描述

4.@Async異步不生效原因

1)@SpringBootApplication 啟動類或配置類當中沒有添加 @EnableAsync 注解。

(補充:項目中除了啟動類和配置類外,任何一個注入到 Bean 容器中的類添加 @EnableAsync 注解都可以,但是規(guī)范用法是在啟動類和配置類中添加注解。)

2)異步方法使用注解@Async的返回值只能為void或者Future。

3)異步方法不能使用static修飾

4)異步類沒有使用 @Component 注解(或其他注解)導(dǎo)致spring無法掃描到異步類

5)異步方法不能與異步方法在同一個類中

6)類中需要使用@Autowired或@Resource等注解自動注入,不能自己手動new對象

7)在 @Async 方法上標注 @Transactional 是沒用的。 在 @Async 方法調(diào)用的方法上標注@Transactional 有效。

8)調(diào)用被 @Async 標記的方法的調(diào)用者不能和被調(diào)用的方法在同一類中不然不會起作用!?。。。。?!

9)使用 @Async 時是獲取不到方法的返回值的,拿到的值為 null,如果返回的值是原始類型int、double、long等(不能為 null),就會報錯。

在這里插入圖片描述

5.補充:使用@Async后項目啟動報Bean注入異常

使用 @Async 后項目啟動報Bean注入異常,提示 in its raw version as part of a circular reference, but has eventually been wrap

詳細報錯信息如下:

Caused by: org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'userInfoServiceImpl': Bean with name 'userInfoServiceImpl' has been injected into other beans [authServiceImpl, loginLogServiceImpl] in its raw version as part of a circular reference, but has eventually been wrapped. This means that said other beans do not use the final version of the bean. This is often the result of over-eager type matching - consider using 'getBeanNamesForType' with the 'allowEagerInit' flag turned off, for example.
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:623)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:516)
    at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:324)
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234)
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:322)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:202)
    at org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:276)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1307)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1227)
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:640)
    ... 74 common frames omitted

Disconnected from the target VM, address: '127.0.0.1:61563', transport: 'socket'

Process finished with exit code 1

主要是因為被 @Async 修飾后,項目啟動時會生成一個代理對象,這個代理對象產(chǎn)生的實例和 Spring 注解的實例不一致,就會拋出這個異常。可以嘗試使用 @Lazy 注解通過懶加載的方式進行修復(fù),或者直接使用自定義線程池的方式進行異步操作。

整理完畢,完結(jié)撒花~ ??

參考地址:

1.@EnableAsync@Async基本使用方法

2.spring boot- @EnableAsync和@Async(Spring boot 注解@Async不生效 無效 不起作用)

到此這篇關(guān)于SpringBoot中@EnableAsync和@Async注解的使用小結(jié)的文章就介紹到這了,更多相關(guān)SpringBoot @EnableAsync和@Async內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Java中enum枚舉類型的基本特性詳解

    Java中enum枚舉類型的基本特性詳解

    這篇文章主要介紹了Java中enum枚舉類型的基本特性詳解,enum關(guān)鍵字用于創(chuàng)建一個新類型,其中包含一組數(shù)量有限的命名變量,并視這些變量為常規(guī)程序組件,實踐表明這是一種非常有用的類型,需要的朋友可以參考下
    2023-11-11
  • MyBatis深入分析數(shù)據(jù)庫交互與關(guān)系映射

    MyBatis深入分析數(shù)據(jù)庫交互與關(guān)系映射

    這篇文章主要介紹了MyBatis中的數(shù)據(jù)庫交互與關(guān)系映射,MyBatis是一款優(yōu)秀的持久層框架,它支持定制化SQL、存儲過程以及高級映射,MyBatis避免了幾乎所有的JDBC代碼和手動設(shè)置參數(shù)以及獲取結(jié)果集,需要的朋友可以參考下
    2024-05-05
  • 詳解SpringMVC的類型轉(zhuǎn)換及驗證方法

    詳解SpringMVC的類型轉(zhuǎn)換及驗證方法

    在本篇文章里面我們給大家詳細分析了SpringMVC的類型轉(zhuǎn)換及驗證方法的相關(guān)知識,對此有需要的朋友們學(xué)習(xí)下吧。
    2018-10-10
  • eclipse創(chuàng)建springboot項目的三種方式總結(jié)

    eclipse創(chuàng)建springboot項目的三種方式總結(jié)

    這篇文章主要介紹了eclipse創(chuàng)建springboot項目的三種方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-07-07
  • Java實現(xiàn)局域網(wǎng)聊天室功能(私聊、群聊)

    Java實現(xiàn)局域網(wǎng)聊天室功能(私聊、群聊)

    這篇文章主要為大家詳細介紹了Java實現(xiàn)局域網(wǎng)聊天室功能,包括私聊、群聊,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-05-05
  • ThreadLocal導(dǎo)致JVM內(nèi)存泄漏原因探究

    ThreadLocal導(dǎo)致JVM內(nèi)存泄漏原因探究

    ThreadLocal是JDK提供的線程本地變量機制,但若使用不當可能導(dǎo)致內(nèi)存泄漏。正確的使用方式是在使用完后及時remove,或者使用弱引用等手段避免強引用導(dǎo)致的內(nèi)存泄漏。在多線程編程中,合理使用ThreadLocal可以提高并發(fā)性能,但也需要注意其潛在的內(nèi)存泄漏問題
    2023-04-04
  • SpringBoot項目開發(fā)中常用的依賴

    SpringBoot項目開發(fā)中常用的依賴

    這篇文章主要介紹了SpringBoot項目開發(fā)中常用的依賴詳解,本文通過示例代碼給大家介紹的非常詳細,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2023-06-06
  • 詳談Java泛型中T和問號(通配符)的區(qū)別

    詳談Java泛型中T和問號(通配符)的區(qū)別

    下面小編就為大家?guī)硪黄斦凧ava泛型中T和問號(通配符)的區(qū)別。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-10-10
  • intellij idea自動生成類注釋和方法注釋配置方法

    intellij idea自動生成類注釋和方法注釋配置方法

    這篇文章主要介紹了intellij idea自動生成類注釋和方法注釋設(shè)置方法,需要的朋友可以參考下
    2023-01-01
  • Spring框架初始化解析

    Spring框架初始化解析

    這篇文章主要介紹了Spring框架初始化解析,具有一定參考價值,需要的朋友可以了解下。
    2017-11-11

最新評論