背景
SpringBoot 启动类上,配置扫描包路径有三种方式,最近看到一个应用上三种注解都用上了,代码如下:
@SpringBootApplication(scanBasePackages ={"a","b"}) @ComponentScan(basePackages = {"a","b","c"}) @MapperScan({"XXX"}) public class XXApplication extends SpringBootServletInitializer }
那么,疑问来了:SpringBoot 中,这三种注解生效优先级如何、第一种和第二种有没有区别呢?本文来整理下这三个注解的注意事项。
SpringBootApplication 注解
这是 SpringBoot 的注解,本质是三个 Spring 注解的和
- @Configuration
- @EnableAutoConfiguration
- @ComponentScan
它默认扫描启动类所在包及其所有子包,但是不包括第三方的 jar 包的其他目录,通过scanBasePackages
属性可以重新设置扫描包路径。
注意:如果我们需要扫描依赖 jar 包中的注解,而依赖包的路径跟不包含在 SpringBoot 启动类路径中的话,我们就要单独使用 @ComponentScan
注解扫描第三方包。同时必须指定本工程的扫描路径,因为一旦有这个注解后,它优先,默认扫描包就失效了。
例如这个工程:
编辑
SpringBoot 启动类的工程目录为 cn.com.a.b
,引用的第三方公共包 xxx.common.jar
的目录也是 cn.com.a.b
,那么第三方 jar 包中的注解天然能直接被扫描到。其他的 jar 包中,如果有注解,就无法扫描到了。
ComponentScan注解
这个是 Spring 框架的注解,它用来指定组件扫描路径,如果用这个注解,它的值必须包含整个工程中全部需要扫描的路径。因为它会覆盖 SpringBootApplication
的默认扫描路径,导致其失效。
失效表现有两种:
第一,如果 ComponentScan
只包括一个值且就是默认启动类目录,SpringBootApplication
生效, ComponentScan
注解失效,报错:
编辑
第二,如果 ComponentScan
指定多个具体子目录,此时 SpringBootApplication
会失效,Spring 只会扫描 ComponentScan
指定目录下的注解。如果恰好有目录外的 Controller 类,很遗憾,这些控制器将无法访问。
回到开头那段代码:
@SpringBootApplication(scanBasePackages ={}) @ComponentScan(basePackages = {})
这里指定了 ComponentScan
注解后, scanBasePackages
就失效了。因此,如果 ComponentScan
的 basePackages
值不包括 cn.com.a.b
即启动类所在的包,仅指定了第三方 jar 的目录,那么这个工程下任何的注解都无法被扫描到。
MapperScan 注解
这个是 MyBatis 的注解,会将指定目录下所有 DAO 类封装成 MyBatis 的 BaseMapper
类,然后注入 Spring 容器中,不需要额外的注解,就可以完成注入。
启示录
SpringBoot 包扫描路径,两个注解的冲突行为,我反复验证了好久确定了现象,但是没有找到合理的解释。这篇文章在草稿箱酝酿了快两周了,一直搁置着。
今天搜到了一篇文章,说二者同时使用时, SpringBootApplication
会失效,至此 SpringBoot 扫描路径的疑惑终于消除了。