文章

maven模块循环依赖解决方案

maven模块循环依赖解决方案

maven模块循环依赖解决方案

模块循环依赖场景

在大型java工程中,通常使用maven module划分不同模块,并使用<dependency>标签引用模块。
A模块已经依赖了B模块,后续开发时,又想在B模块中使用A模块的service,此时引入A模块,在启动时就会出现循环依赖报错。此处AB模块都是项目自开发的模块。

出现原因

通常由于前期的模块划分不合理。

解决方案

重新划分模块,相当于重构,但在大型项目中代价较大。 轻量级的方案,可以使用spring上下文容器读取其他模块的beanName解决。如需要动态加载不同模块,可以增加接口定义+不同实现的方式。

具体编码案例

接口定义

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
// 在B模块定义接口
public interface BModuleHandler {

    // 在接口中使用枚举类,定义业务编码和回调的spring bean名称。关联的内容相对内聚,实现在一处地方统一定义和使用,避免使用额外的常量类定义
    public enum HdlEnum {

        // 其他模块,实现BModuleHandler接口的方法handle,并以硬编码方式,在B模块此处添加注册自定义处理器
        A_MODULE_HDL("a1", "aModuleService");
        private String code;
        private String beanName;

        HdlEnum(String code, String beanName) {
            this.code = code;
            this.beanName = beanName;
        }

        // 回调:在B模块中,使用BModuleHandler.HdlEnum.getHdlByCode(code).handle()方式,调用其他模块
        public static BModuleHandler getHdlByCode(String code) {
            for (BModuleHandler.HdlEnum v : values()) {
                if (v.code.equals(code)) {
                    // 从上下文获取service,规避模块划分和引用不合理导致的循环依赖冲突问题
                    return SpringBeanUtils.getBean(v.beanName);
                }
            }
            return null;
        }
    }

    // 处理方法,具体实现在其他模块
    Boolean handle();
}

调用者

1
2
3
4
5
6
7
8
9
// B模块已经被A模块依赖,但又想使用A模块的service资源,再次引用会出现循环依赖报错。可以使用回调方式解决。
@Service
public class BModuleService {

    public void do() {
        BModuleHandler someModuleHdl = BModuleHandler.HdlEnum.getHdlByCode(code);
        someModuleHdl.handle();
    }
}

实现者

1
2
3
4
5
6
7
8
9
// A模块依赖B模块,实现BModuleHandler接口和handle方法
@Service("aModuleService")
public class AModuleService implements BModuleHandler {

    @Override
    Boolean handle() {
        // 在B模块中进入该方法后,即可使用A模块的其他service
    }
}
本文由作者按照 CC BY 4.0 进行授权