SpringBoot启动过程 - @SpringBootApplication

SpringBoot 的启动过程如下:

1
2
3
4
5
6
7
@SpringBootApplication
public class SpringbootlLearningApplication {

public static void main(String[] args) {
SpringApplication.run(SpringbootlLearningApplication.class, args);
}
}

SpringBoot 简化了大量的配置的信息,几行代码就将 Spring Boot 服务启动,具体观察一下,有两部分指的注意:

  1. @SpringBootApplication 注解去指定启动类
  2. SpringApplication.run(SpringbootLearingApplication.class, args) 启动 Spring 容器


@SpringBootApplication

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
@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 是一个组合注解,它包含了以下三个重要的注解:

  1. @SpringBootConfiguration
  2. @EnableAutoConfiguration
  3. @ComponentScan


@SpringBootConfiguration

1
2
3
4
5
6
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Configuration
public @interface SpringBootConfiguration {
}

可以看出,@SpringBootConfiguration 实际上就是一个配置注解,与 @Configuration 不同的是,一个应用程序中只能使用一个 @SpringBootConfiguration,而在我们启动 SpringBootApplication 的时候就已经开启配置,而 @Configuration 可以根据需要进行 JavaConfig 的方式进行多个实例配置


@EnableAutoConfiguration

1
2
3
4
5
6
7
8
9
10
11
12
13
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import({AutoConfigurationImportSelector.class})
public @interface EnableAutoConfiguration {
String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";

Class<?>[] exclude() default {};

String[] excludeName() default {};
}

@EnableAutoConfiguration这个复合annotation 的主要作用是开启容器的自动配置功能,而具体由 @AutoConfigurationPackage 和 @Import({AutoConfigurationImportSelector.class}) 实现。


@AutoConfigurationPackage

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Import({Registrar.class})
public @interface AutoConfigurationPackage {
}

static class Registrar implements ImportBeanDefinitionRegistrar, DeterminableImports {
Registrar() {
}

public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
AutoConfigurationPackages.register(registry, (new AutoConfigurationPackages.PackageImport(metadata)).getPackageName()); // 注册组件bean信息
}

public Set<Object> determineImports(AnnotationMetadata metadata) {
return Collections.singleton(new AutoConfigurationPackages.PackageImport(metadata));
}
}


AutoConfigurationPackages.Register 会向 Spring 容器中注册所有包下的的组件Bean 信息,例如:我们自定义一个 Bean

1
2
3
4
5
6
7
@Component
public class HelloService {

void sayHello(){
System.out.println("hello");
}
}

Debug 的时候就会发现,我们自定义的 component HelloService 被加入到 BeanDefinitionMap中,准备进行注入容器中

@Import({AutoConfigurationImportSelector.class})

@Import({AutoConfigurationImportSelector.class}) 这个注解主要是借助 @Import 的帮助,将符合自动配置 auto configure 的bean加载到容器中。

1
2
3
4
5
6
7
8
AutoConfigurationImportSelector.class

protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
// 这里获取了 auto configurate的所有类文件名
List<String> configurations = SpringFactoriesLoader.loadFactoryNames(this.getSpringFactoriesLoaderFactoryClass(), this.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;
}



加载这些 auto configurate 的类文件主要是借助于 SpringFactoriesLoader 进行实现的,SpringFactoriesLoader 会根据 配置的key即(@EnableAutoConfiguration 的路径,为 org.springframework.boot.autoconfigure)下,找到指定的配置文件如 META-INF/spring.factories 加载对应的 auto configure class,并加入到容器中。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 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,\
org.springframework.boot.autoconfigure.batch.BatchAutoConfiguration,\
org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration,\
org.springframework.boot.autoconfigure.cassandra.CassandraAutoConfiguration,\
org.springframework.boot.autoconfigure.cloud.CloudServiceConnectorsAutoConfiguration,\
org.springframework.boot.autoconfigure.context.ConfigurationPropertiesAutoConfiguration,\
org.springframework.boot.autoconfigure.context.MessageSourceAutoConfiguration,\
org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration,\
org.springframework.boot.autoconfigure.couchbase.CouchbaseAutoConfiguration,\
...


@ComponentScan

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
@Documented
@Repeatable(ComponentScans.class)
public @interface ComponentScan {
@AliasFor("basePackages")
String[] value() default {};

@AliasFor("value")
String[] basePackages() default {};

Class<?>[] basePackageClasses() default {};

Class<? extends BeanNameGenerator> nameGenerator() default BeanNameGenerator.class;

Class<? extends ScopeMetadataResolver> scopeResolver() default AnnotationScopeMetadataResolver.class;

ScopedProxyMode scopedProxy() default ScopedProxyMode.DEFAULT;

String resourcePattern() default "**/*.class";

boolean useDefaultFilters() default true;

ComponentScan.Filter[] includeFilters() default {};

ComponentScan.Filter[] excludeFilters() default {};

boolean lazyInit() default false;

@Retention(RetentionPolicy.RUNTIME)
@Target({})
public @interface Filter {
FilterType type() default FilterType.ANNOTATION;

@AliasFor("classes")
Class<?>[] value() default {};

@AliasFor("value")
Class<?>[] classes() default {};

String[] pattern() default {};
}
}

@ComponentScan 这个注解的主要功能就是自动扫描并加载符合条件的组件,如 @Component 和 @Repository,并将组件加入到容器中,根据属性配置 basePackage可以指定扫描的范围