@SpringBootApplication这个annotation是由3个annotation组合而成:
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan
假如你愿意,也可以分别用这3个annotation来代替@SpringBootApplication这一个annotation。
在讲下面之前,严重吐槽一下 springboot 的官方文档,它对所涉及的内容都提到那么一点点,但是每一点都是语焉不详,非常的晦涩。
@ComponentScan中的basePackages 和 @SpringBootApplication中的scanBasePackages有什么关系?
我们稍微复杂点的应用程序,一般都有core这样的jar包引入,core.jar包的包名和springboot应用的包名前面部分基本上一样。这个架构如下图所示:
core的包为:
com.champbay.core
application的结构如下:
com.champbay.app
-->com.champbay.app.util
-->com.champbay.app.service
-->com.champbay.app.web
-->com.champbay.app.Application.java
官方文档中有一段描述如下:
We generally recommend that you locate your main application class in a root package above other classes.
The @SpringBootApplication annotation is often placed on your main class,
and it implicitly defines a base “search package” for certain items.
上面这段话的描述反映了下面几点:
1,springboot工程有一个main函数的类。
2,这个main函数的类应该位于 com.champbay.app 下面。
3,这个main函数的类上有@SpringBootApplication的注解。
4,这个@SpringBootApplication注解,隐式地表示了凡是在com.champbay.app以及com.champbay.app下面的子包(com.champbay.app.util,com.champbay.app.service,com.champbay.app.web等)中的诸如:@Component,@Repository,@Controller等都将自动扫描。
那么,Application.java启动的时候,会自动扫描com.champbay.app下面的所有子包,但是对于com.champbay.core下面的就不会自动加载。为了解决这个问题,需要在@ComponentScan设置basePackages为com.champbay即可,这样com.champbay.core就会被自动扫描注册那些bean。
我们为了能够自动扫描那些包,需要设置@ComponentScan的属性basePackages,但是总不能因为这样的需求而不用@SpringBootApplication,而用3个annotation来写太麻烦了,所以,在@SpringBootApplication中,定义了一个scanBasePackages,效果和@ComponentScan的basePackages完全一样。我们来看看Spring文档关于这一段的描述,看完后又想XXX了,简直太惜字如金了:
@SpringBootApplication also provides aliases to customize the attributes of @EnableAutoConfiguration and @ComponentScan.
然后呢?然后就没有了
好吧,让我们来看看@SpringBootApplication的源代码吧:
/**
* Base packages to scan for annotated components. Use {@link #scanBasePackageClasses}
* for a type-safe alternative to String-based package names.
* @return base packages to scan
* @since 1.3.0
*/
@AliasFor(annotation = ComponentScan.class, attribute = "basePackages")
String[] scanBasePackages() default {};
如此就完全明白了。scanBasePackages就是basePackages的别名!
我们从上面看到,当在 com.champbay.app 不同包下面,有@Component、@Repository、@Controller的时候,需要指定scanBasePackages。
但是我们从另外一篇文章:Auto-configuration的规范中可以看到,springboot不建议用这种方式来自动加载,而是采用如下的方式:
Spring Boot checks for the presence of a META-INF/spring.factories file within your published jar.
The file should list your configuration classes under the EnableAutoConfiguration key, as shown in the following example:
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.mycorp.libx.autoconfigure.LibXAutoConfiguration,\
com.mycorp.libx.autoconfigure.LibXWebAutoConfiguration
Auto-configurations must be loaded that way only.
Make sure that they are defined in a specific package space and that they are never the target of component scanning.
Furthermore, auto-configuration classes should not enable component scanning to find additional components.
Specific @Imports should be used instead.
也就是说,不要用scanBasePackages这样的方式,而是采用 META-INF/spring.factories 的方式。