一、问题说明
现在很多分布式项目中,会使用Maven进行分模块开发。在多模块分包管理的情况下,模块依赖之间存在相互引用,有些模块是不需要启动类的,例如xxx-common模块,甚至一个项目只有一个启动类,在这种情况下,我们应该如何将无启动类的其他模块中的类,注册为Spring管理的Bean对象呢?
二、场景案例分析
假设现在有个场景,admin模块的pom引入了common模块,我们想要将AliOSSUtils注册为bean对象。但启动类不在common模块下,这种情况如何保证其他模块中加了@Component、@Configuration这种类被SpringBoot扫描到?
三、问题解决方案
1、常规解决方案
我们首先要知道SpringBoot启动类的默认包扫描规则:
SpringBootApplication启动时会默认扫描启动类当前所在包及其子包。
在启动类上,加入了@SpringBootApplication注解,如果需要扫描启动类当前包和子包以外的其他包,可用如下注解属性配置实现:
@SpringBootApplication(scanBasePackages = {"com.dkd","com.xxx.commmon"}) // SpringBoot项目指定要扫描的包 //@ComponentScan(basePackages = {"com.dkd","com.dkd.commmon"}) // 非SpringBoot项目指定要扫描的包,@ComponentScan优先级高于@SpringBootApplication中的scanBasePackages public class DkdApplication { public static void main(String[] args) { SpringApplication.run(DkdApplication.class, args); } }
2、推荐解决方案
观察一下案例中不同模块的包结构:
由于SpringBoot启动类的默认包扫描规则,会扫描com.dkd包及其子包,虽然它们属于不同模块,但是启动类所在的模块引入了其他模块的依赖。在编译成jar包时,会进行同包合并。也就是说dkd-common模块下的包结构也保持com.dkd,这样就不用专门指定scanBasePackages包扫描路径。SpringBoot会自动扫描其他模块下同结构的包。
因此我们的项目包结构尽量定义为:
xxx-parent(父模块)
---xxx-admin(子模块)
------com.xxx.admin
------XxxApplication(启动类)
---xxx-common(子模块)
------com.xxx.common
---xxx-manage(子模块)
------com.xxx.manage
......