[WIP]類之間的循環依賴,你頭疼了嗎?

類之間的循環依賴指的的A依賴B,B也依賴A,這就出現循環依賴。如果是spring容器中的兩個bean出現循環依賴,則在容器啓動時,可能會報錯,導致無法啓動。

 

如果解決循環依賴?

首先要理清各類的職責,尤其是分層職責————相同層級不要相互調用,調用下級API。

下面是職責不清晰導致的循環依賴。解決方案是,調用下層方法。UserService和LoginAccountService是同一層服務,那麼,他們在調用對方的數據時,應調用其下層的方法。例如:UserService#selectUserInfo在獲取LoginAccount數據時,改爲調用loginAccountMapper#selectByUserId。這樣就解決了bean直接的循環依賴。

// -------------------------  UserService  ------------------------------------
@Service
public class UserService {
    @Resource
    private UserMapper userMapper;
    @Resource
    private LoginAccountService loginAccountService;


    public UserVO selectUserInfo(int userId) {
        User user = userMapper.selectByUserId(userId);
        if (user == null) {
            throw new ResponseException("用戶不存在");
        }
        UserVO userVO = BeanMapper.map(user, UserVO.class);
        LoginAccount loginAccount= loginAccountService.selectByUserId(userId);
        if (loginAccount!=null){
            userVO.setLoginAccount(loginAccount.getLoginAccount());
        }
        return userVO;
    }

    public void validUser(int userId) {
        User user = userMapper.selectByUserId(userId);
        if (user == null) {
            throw new ResponseException("用戶不存在");
        }
        if (!"NORMAL".equalsIgnoreCase(user.getStatus())) {
            throw new ResponseException("用戶已禁用");
        }
    }
}

// ---------------------------  LoginAccountService ----------------------------------
@Service
public class LoginAccountService {
    @Resource
    private UserService userService;
    @Resource
    private LoginAccountMapper loginAccountMapper;

    public LoginAccount login(String loginAccount, String password) {
        // 獲取登陸賬號
        LoginAccount entity = loginAccountMapper.selectByAccount(loginAccount);
        if (entity == null) {
            throw new ResponseException("賬號不存在");
        }
        if (!password.equals(entity.getPassword())) {
            throw new ResponseException("用戶密碼錯誤");
        }
        userService.validUser(entity.getUserId());
        return entity;

    }

    public LoginAccount selectByUserId(int userId) {
        return loginAccountMapper.selectByUserId(userId);
    }
}
View Code

當然,上面的循環依賴,單從技術層面,加@Lasy是可以解決的,但還是應該從類的職責方面來進行改進。職責不清晰會帶來諸多問題,絕不僅僅是重複依賴的問題。

 

還有一種情況,也是我今天碰到的一個情況。跟大家分享一下。
我們的中臺channel服務,對接了數家銀行通道。其中的一個YiLian通道有個特殊需求,在支付時需要對收款人進行報備,報備完成纔可下發。見下圖示意圖,YiLianPayStrategy 有注入PayUserSignService,PayUserSignService有注入YiLianSignStrategy,YiLianSignStrategy有注入YiLianPayStrategy。 這就導致了YiLianPayStrategy 與YiLianSignStrategy的相互循環依賴。

 

這在企業應用開發中是個比較典型的正常案例。那麼,如果解決這種循環依賴呢?
解決方案有二:
1. 不使用bean注入的方式,改爲需要時才獲取bean。


2. 使用spring的事件監聽器,實現類之間的解耦。

 

感謝閱讀!正在編寫,尚未完成。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章