自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

@Async注解失效的九種場景

開發(fā) 前端
在Spring中要開啟@Async注解異步的功能,需要在項目的啟動類,或者配置類上,使用@EnableAsync注解。

前言

最近有粉絲問了我一個問題:他在項目某個方法使用@Async注解,但是該方法還是同步執(zhí)行了,異步不起作用,到底是什么原因呢?

偽代碼如下:

@Slf4j
@Service
public class UserService {

    @Async
    public void async(String value) {
        log.info("async:" + value);
    }
}

這個問題還是比較有意思的,今天這篇文章總結了@Async注解失效的9種場景,希望對你會有所幫助。

圖片圖片

1 未使用@EnableAsync注解

在Spring中要開啟@Async注解異步的功能,需要在項目的啟動類,或者配置類上,使用@EnableAsync注解。

例如:

@EnableAsync
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})
public class Application {

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

@EnableAsync注解相當于一個開關,控制是否開啟@Async注解異步的功能,默認是關閉的。

如果在項目的啟動類上沒使用@EnableAsync注解,則@Async注解異步的功能不生效。

2 內部方法調用

我們在日常開發(fā)中,經(jīng)常需要在一個方法中調用另外一個方法,例如:

@Slf4j
@Service
public class UserService {

    public void test() {
        async("test");
    }

    @Async
    public void async(String value) {
        log.info("async:{}", value);
    }
}

這個示例中,在UserService類中的test()方法中調用了async()方法。

如果在controller中@Autowired了UserService類的對象,調用了它的test()方法,則async()異步的功能會失效。

我們知道Spring通過@Async注解實現(xiàn)異步的功能,底層其實是通過Spring的AOP實現(xiàn)的,也就是說它需要通過JDK動態(tài)代理或者cglib,生成代理對象。

異步的功能,是在代理對象中增加的,我們必須調用代理對象的test()方法才行。

而在類中直接進行方法的內部調用,在test()方法中調用async()方法,調用的是該類原對象的async方法,相當于調用了this.async()方法,而并非UserService代理類的async()方法。

因此,像這種內部方法調用,@Async注解的異步功能會失效。

3 方法非public

在Java中有4種權限修飾符

  • public:所有類都可以訪問。
  • private:只能同一個類訪問。
  • protected:同一個類,同一個包下的其他類,不同包下的子類可以訪問。
  • 默認修飾符:同一個類,同一個包下的其他類可以訪問。

在實際工作中,我們使用頻率最高的可能是public和private了。

如果我在定義Service類中的某個方法時,有時把權限修飾符定義錯了,例如:

@Slf4j
@Service
public class UserService {

    @Async
    private void async(String value) {
        log.info("async:{}", value);
    }
}

這個例子中將UserService類的async()方法的權限修飾符定義成了private的,這樣@Async注解也會失效。

因為private修飾的方法,只能在UserService類的對象中使用。

而@Async注解的異步功能,需要使用Spring的AOP生成UserService類的代理對象,該代理對象沒法訪問UserService類的private方法,因此會出現(xiàn)@Async注解失效的問題。

4 方法返回值錯誤

我們在寫一個新的方法時,經(jīng)常需要定義方法的返回值。

返回值可以是void、int、String、User等等,但如果返回值定義錯誤,也可能會導致@Async注解的異步功能失效。

例如:

@Service
public class UserService {

    @Async
    public String async(String value) {
        log.info("async:{}", value);
        return value;
    }
}

UserService類的async方法的返回值是String,這種情況竟然會導致@Async注解的異步功能失效。

在AsyncExecutionInterceptor類的invoke()方法,會調用它的父類AsyncExecutionAspectSupport中的doSubmit方法,該方法時異步功能的核心代碼,如下:

圖片圖片

從圖中看出,@Async注解的異步方法的返回值,要么是Future,要么是null。

因此,在實際項目中,如果想要使用@Async注解的異步功能,相關方法的返回值必須是void或者Future。

5 方法用static修飾了

有時候,我們的方法會使用static修飾,這樣在調用的地方,可以直接使用類名.方法名,訪問該方法了。

但如果在@Async方法上加了static修飾符,例如:

@Slf4j
@Service
public class UserService {

    @Async
    public static void async(String value) {
        log.info("async:{}", value);
    }
}

這時@Async的異步功能會失效,因為這種情況idea會直接報錯:Methods annotated with '@Async' must be overridable 。

使用@Async注解聲明的方法,必須是能被重寫的,很顯然static修飾的方法,是類的靜態(tài)方法,是不允許被重寫的。

因此這種情況下,@Async注解的異步功能會失效。

6 方法用final修飾

在Java種final關鍵字,是一個非常特別的存在。

用final修飾的類,沒法被繼承。

用final修飾的方法,沒法被重寫。

用final修飾的變量,沒法被修改。

如果final使用不當,也會導致@Async注解的異步功能失效,例如:

@Slf4j
@Service
public class UserService {

    public void test() {
        async("test");
    }

    @Async
    public  final void async(String value) {
        log.info("async:{}", value);
    }
}

這種情況下idea也會直接報錯:Methods annotated with '@Async' must be overridable 。

因為使用final關鍵字修飾的方法,是沒法被子類重寫的。

因此這種情況下,@Async注解的異步功能會失效。

7 業(yè)務類沒加@Service注解

有時候,我們在新加Service類時,會忘了加@Service注解,例如:

@Slf4j
//@Service
public class UserService {

    @Async
    public void async(String value) {
        log.info("async:{}", value);
    }
}

@Service
public class TestService {

   @Autowired
   private UserService userService;

    public void test() {
        userService.async("test");
    }
}

這種情況下,@Async注解異步的功能也不會生效。因為UserService類沒有使用@Service、@Component或者@Controller等注解聲明,該類不會被Spring管理,因此也就無法使用Spring的異步功能。

8 自己new的對象

在項目中,我們經(jīng)常需要new一個對象,然后對他賦值,或者調用它的方法。

但如果new了一個Service類的對象,可能會出現(xiàn)一些意想不到的問題,例如:

@Slf4j
@Service
public class UserService {

    @Async
    public void async(String value) {
        log.info("async:{}", value);
    }
}

@Service
public class TestService {

    public void test() {
        UserService userService = new UserService();
        userService.async("test");
    }
}

在TestService類的test()方法中,new了一個UserService類的對象,然后調用該對象的async()方法。

很顯然這種情況下,async()方法只能同步執(zhí)行,沒法異步執(zhí)行。

因為在項目中,我們自己new的對象,不會被Spring管理,因此也就無法使用Spring的異步功能。

不過我們可以通過BeanPostProcessor類,將創(chuàng)建的對象手動注入到Spring容器中。

9 Spring無法掃描異步類

我們在Spring項目中可以使用@ComponentScan注解指定項目中掃描的包路徑,例如:

@ComponentScan({"com.susan.demo.service1"})
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})
public class Application {

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

項目中com.susan.demo.service1這個路徑是不存在的,會導致@Async注解異步的功能失效。

同時如果@ComponentScan注解定義的路徑,沒有包含你新加的Servcie類的路徑,@Async注解異步的功能也會失效。

好了,今天的文章內容先到這里。

責任編輯:武曉燕 來源: 蘇三說技術
相關推薦

2024-06-18 08:37:25

場景異步編程代碼

2021-04-14 15:17:08

Transaction代碼語言

2023-09-28 09:07:54

注解失效場景

2020-04-14 13:32:56

@Transacti失效場景

2024-04-19 13:57:30

索引數(shù)據(jù)庫查詢

2024-09-09 08:29:25

2025-02-10 00:27:54

2021-09-04 07:56:44

Spring事務失效

2022-01-09 18:32:03

MySQL SQL 語句數(shù)據(jù)庫

2021-08-04 00:10:49

場景版本大文件

2023-07-05 08:45:18

Spring事務失效場景

2022-05-26 08:23:05

MySQL索引數(shù)據(jù)庫

2022-02-14 16:53:57

Spring項目數(shù)據(jù)庫

2024-05-08 08:18:05

索引失效場景

2024-07-12 14:46:20

2024-12-17 00:00:00

Spring線程

2024-06-19 19:17:04

2022-08-29 09:06:43

hippo4j動態(tài)線程池

2023-09-27 16:22:51

SpringMySQL原子性

2022-12-06 10:39:43

Spring事務失效
點贊
收藏

51CTO技術棧公眾號