宅男在线永久免费观看网直播,亚洲欧洲日产国码无码久久99,野花社区在线观看视频,亚洲人交乣女bbw,一本一本久久a久久精品综合不卡

全部
常見問題
產(chǎn)品動(dòng)態(tài)
精選推薦

解決循環(huán)依賴的方法

管理 管理 編輯 刪除

一、什么是循環(huán)依賴呢?

類A依賴類B,類B也依賴類A,這種情況就會(huì)出現(xiàn)循環(huán)依賴。

Bean A → Bean B → Bean A

上面是比較容易發(fā)現(xiàn)的循環(huán)依賴,也有更深層次的循環(huán)依賴。

Bean A → Bean B → Bean C → Bean D → Bean E → Bean A

二、Spring 的循環(huán)依賴

當(dāng)Spring上下文在加載所有的bean時(shí),會(huì)嘗試按照他們他們關(guān)聯(lián)關(guān)系的順序進(jìn)行創(chuàng)建。如果不存在循環(huán)依賴時(shí),例如:

Bean A → Bean B → Bean C

Spring會(huì)先創(chuàng)建Bean C,再創(chuàng)建Bean B(并將Bean C注入到Bean B中),最后再創(chuàng)建Bean A(并將Bean B注入到Bean A中)。

但是,如果我們存在循環(huán)依賴,Spring上下文不知道應(yīng)該先創(chuàng)建哪個(gè)Bean,因?yàn)樗鼈円蕾囉诒舜?。在這種情況下,Spring會(huì)在加載上下文時(shí),拋出一個(gè)BeanCurrentlyInCreationException。

當(dāng)我們使用構(gòu)造方法進(jìn)行注入時(shí),會(huì)遇到這種情況。因?yàn)樗巧舷挛募虞d就被要求注入。

三、舉個(gè)栗子

用戶類需要調(diào)用組織類中的方法,于是通過(guò)構(gòu)造方法注入組織類。

@Service
public class UserService {
    
    private final DepartmentService departmentSerivce;
 
    /**
     * 通過(guò)構(gòu)造方法注入DepartmentService類
     */
    @Autowired
    public UserSerivce(DepartmentService departmentService) {
        this.departmentService = departmentService;
    }
 
    public List<Department> list() {
        retern departmentService.list();
    }    
 
}

而組織類也剛好需要調(diào)用用戶類里的方法,于是它也通過(guò)構(gòu)造方法注入用戶類。

@Service
public class DepartmentService {
    
    private final UserService userSerivce;
 
    /**
     * 通過(guò)構(gòu)造方法注入U(xiǎn)serService類
     */
    @Autowired
    public DepartmentSerivce(UserService userSerivce) {
        this.userSerivce = userSerivce;
    }
    
}

這種情況程序在編譯時(shí),就會(huì)報(bào)下面的錯(cuò)誤

Description:
 
The dependencies of some of the beans in the application context form a cycle:
 
┌─────┐
|  userService defined in file [D:\Java\IdeaProjects\UserService.class]
↑     ↓
|  departmentService defined in file [D:\Java\IdeaProjects\DepartmentService.class]
└─────┘

現(xiàn)在我們可以為測(cè)試編寫一個(gè)配置類,讓我們稱之為??TestConfig??,它指定要掃描組件的基本包。讓我們假設(shè)我們的bean在包"??com.baeldung.circulardependency??"中定義:?

@Configuration
@ComponentScan(basePackages = { "com.baeldung.circulardependency" })
public class TestConfig {
}

最后,我們可以編寫一個(gè) JUnit 測(cè)試來(lái)檢查循環(huán)依賴關(guān)系。測(cè)試可以為空,因?yàn)樵谏舷挛募虞d期間將檢測(cè)到循環(huán)依賴關(guān)系。?

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = { TestConfig.class })
public class CircularDependencyTest {
 
    @Test
    public void givenCircularDependency_whenConstructorInjection_thenItFails() {
        // Empty test; we just want the context to load
    }
}

如果您嘗試運(yùn)行此測(cè)試,您將得到以下異常:?

BeanCurrentlyInCreationException: Error creating bean with name 'UserService':
Requested bean is currently in creation: Is there an unresolvable circular reference?

四、解決辦法

4.1 重新設(shè)計(jì)

當(dāng)出現(xiàn)這種循環(huán)依賴時(shí),很可能是在設(shè)計(jì)方面存在問題,沒有把每個(gè)類的職責(zé)很好的區(qū)分開。應(yīng)該嘗試正確重新設(shè)計(jì)組件,以便其層次結(jié)構(gòu)設(shè)計(jì)良好,并且不需要循環(huán)依賴項(xiàng)。?

如果無(wú)法重新設(shè)計(jì),那么可以考慮其他解決辦法。


4.2 使用 setter/field 方法注入

上面說(shuō)到,只有構(gòu)造方法是在上下文加載時(shí)就要求被注入,容易出現(xiàn)依賴循環(huán)。所以可以用其他的方式進(jìn)行依賴注入,setter 和 field 方法注入與構(gòu)造方法不同,它們不會(huì)在創(chuàng)Bean時(shí)就注入依賴,而是在被需要時(shí)才注入。

setter方法注入

@Service
public class UserService {
    
    private DepartmentService departmentSerivce;
 
   
    @Autowired
    public void setDepartmentSerivce(DepartmentService departmentService) {
        this.departmentService = departmentService;
    }
 
    public List<Department> list() {
        retern departmentService.list();
    }    
 
}

另一個(gè)類也是同理使用setter方法注入

field方法注入

(使用@Autowired)

@Service
public class UserService {
    
    @Autowired
    private DepartmentService departmentSerivce;
 
 
    public List<Department> list() {
        retern departmentService.list();
    }    
 
}

4.3 使用 @Lazy

解決Spring 循環(huán)依賴的一個(gè)簡(jiǎn)單方法就是對(duì)一個(gè)Bean使用延時(shí)加載。也就是說(shuō):這個(gè)Bean并沒有完全的初始化完,實(shí)際上他注入的是一個(gè)代理,只有當(dāng)他首次被使用的時(shí)候才會(huì)被完全的初始化。
我們對(duì) UserService 進(jìn)行修改,結(jié)果如下:

@Service
public class UserService {
    
    private DepartmentService departmentSerivce;
 
    @Autowired
    public UserSerivce(@Lazy DepartmentService departmentService) {
        this.departmentService = departmentService;
    }
 
    public List<Department> list() {
        retern departmentService.list();
    }    
 
}

如果你現(xiàn)在運(yùn)行測(cè)試,你會(huì)發(fā)現(xiàn)之前的錯(cuò)誤不存在了。

4.4 使用 @PostConstruct

打破循環(huán)的另一種方式是,在要注入的屬性(該屬性是一個(gè)bean)上使用 @Autowired,并使用@PostConstruct 標(biāo)注在另一個(gè)方法,且該方法里設(shè)置對(duì)其他的依賴。

我們的Bean將修改成下面的代碼:

@Service
public class UserService {
 
    @Autowired
    private DepartmentService departmentService;
 
    @PostConstruct
    public void init() {
        departmentService.setUserService(this);
    }
 
    public DepartmentService getDepartmentService() {
        return departmentService;
    }
}
@Service
public class DepartmentService {
 
    private UserService userService;
     
    private String message = "Hi!";
 
    public void setUserService(UserService userService) {
        this.userService = userService;
    }
     
    public String getMessage() {
        return message;
    }
}

現(xiàn)在我們運(yùn)行我們修改后的代碼,發(fā)現(xiàn)并沒有拋出異常,并且依賴正確注入進(jìn)來(lái)。

4.5 實(shí)現(xiàn)ApplicationContextAware and InitializingBean接口

如果一個(gè)Bean實(shí)現(xiàn)了ApplicationContextAware,該Bean可以訪問Spring上下文,并可以從那里獲取到其他的bean。實(shí)現(xiàn)InitializingBean接口,表明這個(gè)bean在所有的屬性設(shè)置完后做一些后置處理操作(調(diào)用的順序?yàn)閕nit-method后調(diào)用);在這種情況下,我們需要手動(dòng)設(shè)置依賴。

@Service
public class UserService implements ApplicationContextAware, InitializingBean {
 
    private DepartmentService departmentService;
 
    private ApplicationContext context;
 
    public DepartmentService getDepartmentService() {
        return departmentService;
    }
 
    @Override
    public void afterPropertiesSet() throws Exception {
        circB = context.getBean(DepartmentService.class);
    }
 
    @Override
    public void setApplicationContext(final ApplicationContext ctx) throws BeansException {
        context = ctx;
    }
}
public class DepartmentService {
 
    private UserService userService;
 
    private String message = "Hi!";
 
    @Autowired
    public void setUserService(UserService userService) {
        this.userService = userService;
    }
 
    public String getMessage() {
        return message;
    }
}

同樣,我們可以運(yùn)行之前的測(cè)試,看看有沒有異常拋出,程序結(jié)果是否是我們所期望的那樣。

4.6 其他辦法

我遇到的這個(gè)問題的情況,是 Service 之間互相依賴導(dǎo)致了深層次的循環(huán)依賴。但是我真正想調(diào)用的是 Mybatis Plus 提供的基礎(chǔ)方法,所以可以將依賴 Service 換成依賴 Mapper,因?yàn)?Mapper 中也有這些基礎(chǔ)方法。

@Service
public class UserService {
    
    private final DepartmentMapper departmentMapper;
 
    @Autowired
    public UserSerivce(DepartmentMapper departmentMapper) {
        this.departmentMapper = departmentMapper;
    }
 
    public List<Department> list() {
        retern departmentMapper.selectList();
    }    
 
}

五、總結(jié)

?在Spring中,有很多方法可以處理循環(huán)依賴關(guān)系。首先要考慮的是重新設(shè)計(jì)你的bean,這樣就不需要循環(huán)依賴關(guān)系:它們通常是可以改進(jìn)的設(shè)計(jì)的癥狀。??但是,如果您絕對(duì)需要在項(xiàng)目中具有循環(huán)依賴項(xiàng),則可以按照此處建議的一些解決方法進(jìn)行操作。


請(qǐng)登錄后查看

CRMEB-慕白寒窗雪 最后編輯于2023-03-06 11:07:33

快捷回復(fù)
回復(fù)
回復(fù)
回復(fù)({{post_count}}) {{!is_user ? '我的回復(fù)' :'全部回復(fù)'}}
排序 默認(rèn)正序 回復(fù)倒序 點(diǎn)贊倒序

{{item.user_info.nickname ? item.user_info.nickname : item.user_name}} LV.{{ item.user_info.bbs_level || item.bbs_level }}

作者 管理員 企業(yè)

{{item.floor}}# 同步到gitee 已同步到gitee {{item.is_suggest == 1? '取消推薦': '推薦'}}
{{item.is_suggest == 1? '取消推薦': '推薦'}}
沙發(fā) 板凳 地板 {{item.floor}}#
{{item.user_info.title || '暫無(wú)簡(jiǎn)介'}}
附件

{{itemf.name}}

{{item.created_at}}  {{item.ip_address}}
打賞
已打賞¥{{item.reward_price}}
{{item.like_count}}
{{item.showReply ? '取消回復(fù)' : '回復(fù)'}}
刪除
回復(fù)
回復(fù)

{{itemc.user_info.nickname}}

{{itemc.user_name}}

回復(fù) {{itemc.comment_user_info.nickname}}

附件

{{itemf.name}}

{{itemc.created_at}}
打賞
已打賞¥{{itemc.reward_price}}
{{itemc.like_count}}
{{itemc.showReply ? '取消回復(fù)' : '回復(fù)'}}
刪除
回復(fù)
回復(fù)
查看更多
打賞
已打賞¥{{reward_price}}
1367
{{like_count}}
{{collect_count}}
添加回復(fù) ({{post_count}})

相關(guān)推薦

快速安全登錄

使用微信掃碼登錄
{{item.label}} 加精
{{item.label}} {{item.label}} 板塊推薦 常見問題 產(chǎn)品動(dòng)態(tài) 精選推薦 首頁(yè)頭條 首頁(yè)動(dòng)態(tài) 首頁(yè)推薦
取 消 確 定
回復(fù)
回復(fù)
問題:
問題自動(dòng)獲取的帖子內(nèi)容,不準(zhǔn)確時(shí)需要手動(dòng)修改. [獲取答案]
答案:
提交
bug 需求 取 消 確 定
打賞金額
當(dāng)前余額:¥{{rewardUserInfo.reward_price}}
{{item.price}}元
請(qǐng)輸入 0.1-{{reward_max_price}} 范圍內(nèi)的數(shù)值
打賞成功
¥{{price}}
完成 確認(rèn)打賞

微信登錄/注冊(cè)

切換手機(jī)號(hào)登錄

{{ bind_phone ? '綁定手機(jī)' : '手機(jī)登錄'}}

{{codeText}}
切換微信登錄/注冊(cè)
暫不綁定
CRMEB客服

CRMEB咨詢熱線 咨詢熱線

400-8888-794

微信掃碼咨詢

CRMEB開源商城下載 源碼下載 CRMEB幫助文檔 幫助文檔
返回頂部 返回頂部
CRMEB客服