Spring 使用@Async出現循環依賴Bean報錯的解決方案


初現端倪

Caused by:org.springframework.beans.factory.BeanCurrentlyInCreationException: Errorcreating bean with name 'asyncUpdate': Bean with name 'asyncUpdate' has beeninjected into other beans [dealerService,userService] in its raw version aspart of a circular reference, but has eventually been wrapped. This means thatsaid other beans do not use the final version of the bean. This is often theresult of over-eager type matching - consider using 'getBeanNamesOfType' withthe 'allowEagerInit' flag turned off, for example.
以上這一長串大概的意思就是說,'asyncUpdate' bean已經注入了一個版本,程序中出現了循環依賴的可能性。
就如:在創建A類時,構造器需要B類,那將去創建B,在創建B類時又發現需要C類,則又去創建C,最終在創建C時發現又需要A,從而形成一個環,沒辦法創建。

分析問題

首先來看看這里的AsyncUpdate類是用來做什么的:

@Component
@EnableAsync
public classAsyncUpdate {
 
   @Autowired
   private DealerMemberMapper dealerMemberMapper;
 
   @Autowired
   private UserService userService;
 
   @Autowired
   private GoodsSubscribeService goodsSubscribeService;
 
   /**
    *異步更新
    */
   @Async
   public void updateDealerAsync(Dealer  dealer, String mobilephone, Integer type) throwsException {
       //篇幅有限就不貼代碼
   }
}

@Async注解:表示當前是一個異步方法。
@Component:表示把普通pojo實例化到spring容器中,相當於配置文件中的
@EnableAsync注解:表示開啟異步線程。

@Service
public classDealerService {
 
   @Autowired
   private DealerMapper dealerMapper;
 
   @Autowired
   private UserService userService;
 
   @Autowired
   private AsyncUpdate asyncUpdate;
 
   //一些代碼
}
 

通過以上兩段程序能夠得到,問題出現的原因:簡單的講就是在啟動程序的時候,Spring已經對DealerService里的asyncUpdate、userService加載完成,當准備創建AsyncUpdate類的時候發現使用了@Async注解,即spring又需將該Bean代理一次,然后Spring發現該Bean已經被其他對象注入,這里就是問題的關鍵所在了。

即:在創建A類時,構造器需要B類,那將去創建B,在創建B類時又發現需要C類,則又去創建C,最終在創建C時發現又需要A,從而形成一個環,沒辦法創建

解決方案

大量查找解決方案后發現解決方案有三:

1.使用 @Lazy 或者 @ComponentScan(lazyInit = true) 來解決該問題,經過我實驗,@Lazy必須和@Autowired聯合使用才能生效,單純在類上添加 @Lazy 並無意義。

@Autowired
@Lazy
private AsyncUpdate asyncUpdate;
 
  1. 使用基於 Setter 的注入
@Component
public classDealerService {
 
    private AsyncUpdate a;
 
    public void setA(AsyncUpdate a) {
        this.a = a;
    }
}
 
 
 
@Component
public classAsyncUpdate {
 
    private DealerService ds;
 
    public void setDs(DealerService ds) {
        this.ds = ds;
    }
}

3.使用@Autowired注解防止循環注入,如:

@Component
public classDealerService {
 
    @Autowired
    private AsyncUpdate a;
} 
 
@Component
public classAsyncUpdate {
 
    private DealerService ds;
 
    @Autowired
    public void foo(DealerService ds) {
        this.ds= ds;
    }
}

注:當@Autowired 對方法或構造函數進行標注時,表示如果構造函數有兩個入參,分別是 bean1 和bean2,@Autowired 將分別尋找和它們類型匹配的 Bean,將它們作為 baanService (Bean1 bean1 ,Bean2 bean2) 的入參來創建baanService Bean。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM