返回

在Spring JavaConfig中配置类路径扫描时,必须格外留意的是根路径包与子模块扫描路径包重复的问题

后端

前言

为了简化开发,我们部门经常会封装一些通用的类库给业务研发使用,因为业务方的根包路径很经常和我们部门项目的根包是不一样的,因此我们会让业务方在使用我们封装的包时,扫描一下我们的根包,形如下:

@SpringBootApplication
@ComponentScan({"com.xxx.xxx", "com.xxx.yyy"})
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

这样一来,业务方就可以直接使用我们封装的类库了,而无需关心类库的具体实现细节。

踩坑经历

然而,在一次使用Spring JavaConfig配置类路径扫描时,我们遇到了一个坑。在我们的项目中,我们使用到了两个子模块,这两个子模块分别位于com.xxx.xxxcom.xxx.yyy包下。在我们的根包com.xxx下,我们有一个Application类,该类使用了@SpringBootApplication@ComponentScan注解。我们希望@ComponentScan注解能够扫描com.xxx.xxxcom.xxx.yyy这两个子模块。

@SpringBootApplication
@ComponentScan({"com.xxx.xxx", "com.xxx.yyy"})
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

但是,当我们运行项目时,却遇到了一个循环依赖的错误。经过排查,我们发现,这是因为com.xxx.xxxcom.xxx.yyy这两个子模块都扫描到了com.xxx这个根包。这样一来,com.xxx这个根包又扫描到了com.xxx.xxxcom.xxx.yyy这两个子模块,从而形成了一个循环依赖。

解决办法

为了解决这个问题,我们可以将根路径包从子模块扫描路径包中排除,或者将子模块扫描路径包从根路径包中排除。

方法一:将根路径包从子模块扫描路径包中排除

@SpringBootApplication
@ComponentScan({"com.xxx.xxx", "com.xxx.yyy"}, excludeFilters = {@ComponentScan.Filter(type = FilterType.REGEX, pattern = "com.xxx")})
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

方法二:将子模块扫描路径包从根路径包中排除

@SpringBootApplication
@ComponentScan({"com.xxx.xxx"})
@ComponentScan({"com.xxx.yyy"}, excludeFilters = {@ComponentScan.Filter(type = FilterType.REGEX, pattern = "com.xxx")})
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

总结

在Spring JavaConfig中配置类路径扫描时,必须格外留意的是根路径包与子模块扫描路径包重复的问题。如果根路径包和子模块扫描路径包重复,则会导致循环依赖和错误。为了解决这个问题,可以将根路径包从子模块扫描路径包中排除,或者将子模块扫描路径包从根路径包中排除。