首先Spring Boot
为我们在JavaEE
的开发提供了很大的便利,减少了我们使用Spring
的时候对需要的组件整合相关的配置,Spring Boot
帮我们做了很多的自动配置。要想用好这个Spring Boot
我们就需要对它非常熟悉,这次我们就来了解一下启动类标记的@SpringBootApplication
。
演示环境
- IntelliJ IDEA 2018.2.5 (Ultimate Edition)
- JDK 1.8
- Spring Boot 2.1.1.RELEASE
- Maven 3.5.4
初始化一个Spring Boot
项目
初始化项目的方式有很多,这里我就选用了使用IDEA
来初始化项目,这样初始完项目后方便我们看源码,初始化Spring Boot
项目的方式:
- 动手能力强的,创建
Maven
工程手动引入spring-boot-starter-parent
依赖以及其它依赖。 - 使用Spring官方提供的Spring Initializr,初始化我们的
Spring Boot
项目。 - 使用旗舰版的
IDEA
,来初始化项目。
初探Spring Boot
项目的启动
在启动Spring Boot
项目的时候,都会有一个被@SpringBootApplication
标注的启动类。例如下面:
@SpringBootApplication
public class JeromeApplication {
public static void main(String[] args) {
SpringApplication.run(JeromeApplication.class, args);
}
}
探究@SpringBootApplication
结构
使用工具进入到这个注解,我们会发现这样的结构:
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = {
@Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication {
...
}
我们不难看出其实@SpringBootApplication
是一个复合注解,它是由三个注解组成的:
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan
进入@SpringBootConfiguration
我们使用工具进入到这个注解后,发现其实这个注解就只是被@Configuration
标记了,也会作为组件在包扫描的时候注册到容器中。而@Configuration
我们在项目中会经常用到,比如写一些定义配置的Bean。
@Configuration
public class JeromeConfiguration{
@Bean
public Entity entity(){
return new Entity();
}
}
在这里任何一个标注了@Bean
的方法,其返回值将作为一个bean定义注册到Spring的IOC容器,方法名将默认成该bean定义的id。
进入@ComponentScan
其实@ComponentScan
这个注解大家也是不会陌生的,@ComponentScan
的功能其实就是自动扫描并加载符合条件的组件(比如@Component
和@Repository
等)或者bean定义,将这些bean定义加载到Spring的IOC容器中。当然我们可以通过basePackages
等属性来细粒度的指定@ComponentScan
自动扫描的范围,如果不指定,则默认Spring框架实现会从声明@ComponentScan
所在类的package进行扫描。
因为我们在使用
Spring Boot
的时候并没有指定扫描路径,所以我们的启动类需要和根目录同级
进入@EnableAutoConfiguration
把这个放到最后,也说明了这个注解的重要性。从这个注解的字面意思就不难看出,这个注解是用来激活自动配置的,我们进入看看到底做了什么。
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {
...
}
这里@EnableAutoConfiguration
又是由两个注解组成,这里使用了@Import
来完成条件装配:
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
了解@AutoConfigurationPackage
其中@AutoConfigurationPackage
的作用就是加载我们项目中自定义的 一些组件,比如(@Controller
或@Service
等),将这些组件注册到Spring的IOC容器。
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Import(AutoConfigurationPackages.Registrar.class)
public @interface AutoConfigurationPackage {
}
我们进入到AutoConfigurationPackages.Registrar.class
的源码中再124行会发现这个类:
/**
* {@link ImportBeanDefinitionRegistrar} to store the base package from the importing
* configuration.
*/
static class Registrar implements ImportBeanDefinitionRegistrar, DeterminableImports {
@Override
public void registerBeanDefinitions(AnnotationMetadata metadata,
BeanDefinitionRegistry registry) {
register(registry, new PackageImport(metadata).getPackageName());
}
...
}
当我们在上面代码的第10行打个断点,以DEBUG的方式运行项目,当项目执行到我们打的断点的地方。就会发现new PackageImport(metadata).getPackageName()
返回的是我们@SpringBootApplication
标注的这个启动类的包路径,接下来将启动类(@SpringBootApplication
标注的类)的所在包及下面所有子包里面的所有组件扫描到Spring容器中。
了解@Import(AutoConfigurationImportSelector.class)
到这里就可以看出@EnableAutoConfiguration
借助了@Import
和AutoConfigurationImportSelector.class
来完成条件装配。帮助SpringBoot
应用将所有符合条件的@Configuration
配置都加载到当前应用容器中。
进入到AutoConfigurationImportSelector.class
的源码中,我们能找到一个selectImports
方法中调用getAutoConfigurationEntry
方法:
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata,
AnnotationAttributes attributes) {
List<String> configurations = SpringFactoriesLoader.loadFactoryNames(
getSpringFactoriesLoaderFactoryClass(), getBeanClassLoader());
Assert.notEmpty(configurations,
"No auto configuration classes found in META-INF/spring.factories. If you "
+ "are using a custom packaging, make sure that file is correct.");
return configurations;
}
从这个方法中看出,使用了SpringFactoriesLoader
的支持,而这个SpringFactoriesLoader
类的主要功能就是从类路径下指定的配置文件META-INF/spring.factories
加载配置。配置的key就是@EnableAutoConfiguration
这个注解的全路径。在spring-boot-autoconfigure-2.1.1.RELEASE.jar
的META-INF/spring.factories
文件中,我们能看到Spring Boot
帮我们做好了很多的自动配置:
# Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration,\
org.springframework.boot.autoconfigure.aop.AopAutoConfiguration,\
org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration,\
.......
然后我们在使用Spring Boot
开发项目的时候,只需要引入spring-boot-starter-xxx
,使用Spring Boot
的默认配置就能完成我们的基本开发需求。
总结
通过我们上面的对Spring Boot
应用启动的初探,发现Spring Boot
默认的为我们做了好多的配置。通过EnableAutoConfiguration
进行自动装配,降低了我们上手Spring
框架的难度,简化了我们的开发,让我们更专注于业务的开发。