SpringBoot扫描不到组件?给你提供几种方案

前言最近接手一套基于SpringBoot项目 , 对项目进行重构调整 , 将公共部分抽离成子项目 。 在实践的过程中 , 发现抽离之后的模板中组件并没有被初始化 。 于是将排查解决过程中搜集到的方案及知识汇总分享给大家 。
问题原因问题的原因很简单 , 因多套系统的package命名不一致 。 比如业务系统的包命名为com.abc.xx , 而公共(common)部分的包命名为com.efg.xx , 引入公共jar包时默认是无法初始化的 。
SpringBoot扫描不到组件?给你提供几种方案文章插图
对于SpringBoot项目 , 我们知道扫描的路径从启动类所在包开始 , 扫描当前包及其子级包下的所有文件 。 上图如果启动类在com.abc包下 , 肯定是无法扫描到com.def包内的组件的 。
场景延伸SpringBoot的这个机制还延伸出另外两个场景 。
第一个场景是如果SpringBoot的启动类放的包路径靠下 , 那么在它上级目录中的组件是无法被扫描并初始化的 。 新手往往会因放错位置导致启动时异常 。
第二个场景是故意将一些不需要纳入SpringBoot容器的类放在其他包中 , 避免被SpringBoot容器加载 。 当然此时也可以使用ComponentScan来指定排除对应的包 。
├── src│├── main││├── java│││└── com│││└── secbro│││├── SpringBootMainApplication.java│││├── controller││││└── DruidController.java│││├── model││││└── Order.java│││└── service│││├── OrderService.java│││└── impl│││└── OrderServiceImpl.java上述项目结构中 , 如果将类直接放在com目录或com目录的其他子目录下 , 默认是不会被初始化的 。
通过@ComponentScan扫描回到正题 , 遇到类似不被初始化的情况 , 我们可以使用的最简单的方案就是手动指定扫描包路径 。
在启动类上的@SpringBootApplication注解内部集成了@ComponentScan注解 。 此时我们可以显示的指定扫描的包 。
@SpringBootApplication@ComponentScan({"com.abc.xx","com.def.xx"})public class SpringBootMainApplication {public static void main(String[] args) {SpringApplication.run(SpringBootMainApplication.class, args);}}此种用法一定要先包含本项目要扫描的路径“com.abc.xx” , 然后再在后面添加上common项目要扫描的路径“com.def.xx” 。
如果其他项目不需要初始化common中的内容 , 则可不进行指定 。
自定义@Enable * *注解上述方法虽然能够解决问题 , 但如果直接写包名 , 难免没有个统一的规范 。 此时可考虑使用@Enable类型的注解 。
【SpringBoot扫描不到组件?给你提供几种方案】了解SpringBoot机制的朋友都知道 , 最重要的一个注解便是@EnableAutoConfiguration 。 类似的 , 我们定义一个可以通过注解之后便可使用的Enable注解 。
SpringBoot扫描不到组件?给你提供几种方案文章插图
定义配置类 , 在配置类中指定要扫描的包路径:
@Component@ComponentScan("com.def.xx")public class CommonConfig {}定义Enable注解类 , 并通过@Import导入配置类:
@Target({ElementType.TYPE})@Retention(RetentionPolicy.RUNTIME)@Documented@Import(CommonConfig.class)public @interface EnableCommon {}然后 , 在启动类中便可使用@EnableCommon此注解来指定实例化对应的package 。
@EnableCommon@SpringBootApplicationpublic class SpringBootMainApplication {// ...}在此过程中需要注意的是CommonConfig是位于common项目当中的 。 如果CommonConfig直接可被SpringBoot扫描到 , 那也就不需要EnableCommon注解了 。


推荐阅读