初現端倪
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;
- 使用基於 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。