@ComponentScan注解引发外部请求无法处理的解决办法
问题起因
最近通过maven从项目中拆分出模块module-db和模块module-seckill
模块module-db主要通过mybatisplus实现数据库的操作,并封装业务接口;
模块module-seckill引入module-db依赖,使用相关操作
问题1:在module-seckill中无法访问到module-db模块中的接口
原因:原因是module-seckill没有扫描和注册到module-db中业务的bean
解决办法:在module-seckill主应用类上添加注解:
@MapperScan(value = "cn.jet.moduledb.dao")
@ComponentScan(value = "cn.jet. moduledb.service")
问题解决,但是又引来了问题2
问题2:发现对可执行模块module-seckill中所有请求都失败了(除了/actuator/info)
原因:忙活半天,突然顿悟,可能是@ComponentScan造成的。
解决办法:@ComponentScan注解中添加上控制器所在的包
@ComponentScan(basePackages = {"cn.jet.moduledb.service","cn.jet.moduleseckill.controller"})
解决了
关于@ComponentScan注解
@ComponentScan用于自动扫描并注册 Spring 应用上下文中的 Bean。指示 Spring 框架在哪些包中查找用其他注解(如 @Component、@Service、@Repository 和 @Controller 等)标记的组件。
主要用途
自动检测组件:@ComponentScan 可以自动扫描指定包及其子包中的类,并将用 @Component、@Service、@Repository 和 @Controller 等注解标记的类注册为 Spring 应用上下文中的 Bean。
配置类路径:通过 basePackages 或 basePackageClasses 属性,可以指定要扫描的包路径。如果不指定,Spring 将默认扫描配置类所在的包及其子包。
排除特定组件:可以使用 excludeFilters 属性来排除特定的组件,这通常用于排除一些自动配置的组件,或者防止某些类被意外地注册为 Bean。
包含特定组件:使用 includeFilters 属性可以包含特定的组件,这在需要精确控制哪些组件被扫描和注册时非常有用。
关键点
- @SpringBootApplication注解默认行为:它包括了@Configuration,@EnableAutoConfiguration,和@ComponentScan。默认情况下,@ComponentScan会扫描主应用类所在的包及其子包。
- @ComponentScan的覆盖行为:当在同一个配置类上显式地使用@ComponentScan时,它会覆盖@SpringBootApplication中的默认@ComponentScan设置。这意味着,如果在@ComponentScan中指定了不同的basePackages或scanBasePackageClasses,那么只有这些指定的包会被扫描。
关键点就是@ComponentScan注解设置的包路径覆盖了@SpringBootApplication注解默认的扫描包,不光影响了处理器,可执行模块中所有标记@Component、@Service、@Repository 和 @Controller注解的类都应该受到了影响。
最终解决办法
方法一
既然@SpringBootApplication注解默认会扫描主应用类所在的包及其子包。在使用@ComponentScan时把主应用所在的包也添加进去。
@SpringBootApplication
@MapperScan(value = {"cn.jet.moduledb.dao"})
@ComponentScan(basePackages = {"cn.jet.moduledb.service","cn.jet.moduleseckill.controller"})
public class ModuleSeckillApplication {
…
}
方法二
既然在同一个类上显式地使用@ComponentScan和@SpringBootApplication时,@SpringBootApplication默认的扫描的包会被覆盖,我就在添加一个单独的配置类
@SpringBootApplication
@MapperScan(value = {"cn.jet.moduledb.dao"})
public class ModuleSeckillApplication {
public static void main(String[] args) {
SpringApplication.run(ModuleSeckillApplication.class, args);
}
}
@Configuration
@ComponentScan(basePackages = "cn.jet.moduledb.service") // 额外的扫描路径
class AdditionalComponentScanConfig {
// 确保这个配置类位于主应用类能够扫描到的包中
}
感觉方法二更清晰好些,只添加额外的扫描的包路径