源码分析,基于 Spring Boot 1.5.10 版本
通过前面内容【Spring Boot 工程创建】介绍,我们了解到 Spring Boot 项目需要在一个类上添加 @SpringBootApplication
注解,然后执行该类下的 main() 方法,即可启动容器。接下来就从 @SpringBootApplication 注解来分析一下它的具体执行流程。
/** * @SpringBootApplication 来标注一个主程序类,说明这是一个Spring Boot应用 */
@SpringBootApplication
public class BootApplication {
public static void main(String[] args) {
// Spring应用启动起来
SpringApplication.run(BootApplication.class,args);
}
}
@SpringBootApplication注解分析
该注解是一个组合注解。它主要由@SpringBootConfiguration
、@EnableAutoConfiguration
这两个注解组成。
@SpringBootApplication 标注在某个类上,说明这个类是 Spring Boot 的主配置类,Spring Boot 就会运行这个类的 main 方法来启动 Spring Boot 应用。
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration//标注该类是Spring Boot主配置类
@EnableAutoConfiguration//开启自动配置功能
@ComponentScan(excludeFilters = {
@Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication {
}
1.@SpringBootConfiguration
Spring Boot的配置类。标注在某个类上,表示这是一个Spring Boot的配置类。(该注解被@Configuration注解注释
)
@Target({
ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Configuration
public @interface SpringBootConfiguration {
}
@Configuration 注解,又被@Component注解注释,说明 @SpringBootApplication注解其实也是Spring 容器的一个组件而已。(被@Component 注解注释的类,都是Spring 容器的组件)
@Target({
ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Configuration {
String value() default "";
}
2.@EnableAutoConfiguration
该注解意为:开启自动配置功能。
以前我们需要配置的东西,开启该注解后,Spring Boot 便会帮我们自动配置(该注解被@ AutoConfigurationPackage注释)@AutoConfigurationPackage注解,意为:自动配置包()
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
//这是一个@Import
@Import(EnableAutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {
}
@AutoConfigurationPackage注解又被 @Import 注释,我们来继续分析 @Import 注解。
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
//这是另一个@Import
@Import(AutoConfigurationPackages.Registrar.class)
public @interface AutoConfigurationPackage {
}
@Import 是 Spring 的一个底层注解,意思是:给容器中导入一个组件
。先分析最里层 @Import 注解。该注解导入什么组件由AutoConfigurationPackages.Registrar
这个类决定,这个类就是重点!!! 如下 new PackageImport(metadata).getPackageName()。这个方法就是重点内容!!!
@Order(Ordered.HIGHEST_PRECEDENCE)
static class Registrar implements ImportBeanDefinitionRegistrar, DeterminableImports {
@Override
public void registerBeanDefinitions(AnnotationMetadata metadata,
BeanDefinitionRegistry registry) {
//此处 new PackageImport(metadata).getPackageName() 返回的是被 @SpringBootApplication 注解的类所在的包名。
register(registry, new PackageImport(metadata).getPackageName());
}
@Override
public Set<Object> determineImports(AnnotationMetadata metadata) {
return Collections.<Object>singleton(new PackageImport(metadata));
}
}
new PackageImport(metadata).getPackageName();
1.这个 @Import注解, 返回主配置类所在的包路径,然后通过 register() 方法,将该包下的所有配置信息,都加载到 Spring 容器中。 如下图所示:
再来分析外层 @Import(EnableAutoConfigurationImportSelector.class) 注解。它导入的组件由EnableAutoConfigurationImportSelector
这个类决定,该类继承自 AutoConfigurationImportSelector 类。这个类就是重点!!! 如下 selectImports()
方法,便是最终的执行方法。2.这个 @Import注解, 返回SpringBoot为我们默认配置的 AutoConfiguration。
@Override
public String[] selectImports(AnnotationMetadata annotationMetadata) {
if (!isEnabled(annotationMetadata)) {
return NO_IMPORTS;
}
try {
AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader
.loadMetadata(this.beanClassLoader);
AnnotationAttributes attributes = getAttributes(annotationMetadata);
//获取所有配置信息
//分析getCandidateConfigurations方法,层层分析到loadSpringFactories()方法,最终发现
//它会加载"META-INF/spring.factories"路径下的所有配置信息
//getCandidateConfigurations,翻译为:获取候选人配置信息
//configurations中的具体内容,如下图所示:
List<String> configurations = getCandidateConfigurations(annotationMetadata,
attributes);
configurations = removeDuplicates(configurations);
configurations = sort(configurations, autoConfigurationMetadata);
Set<String> exclusions = getExclusions(annotationMetadata, attributes);
checkExcludedClasses(configurations, exclusions);
configurations.removeAll(exclusions);
configurations = filter(configurations, autoConfigurationMetadata);
fireAutoConfigurationImportEvents(configurations, exclusions);
return configurations.toArray(new String[configurations.size()]);
}
catch (IOException ex) {
throw new IllegalStateException(ex);
}
}
META-INF/spring.factories 路径下的配置信息如下:
List<String> configurations 中加载的默认配置,具体内容如下图:
Spring Boot 项目在启动的时候,会从类路径下的META-INF/spring.factories
中获取 EnableAutoConfiguration 指定的值,将这些值作为自动配置类导入到容器中,自动配置类就生效,帮我们进行自动配置工作。这部分工作在 Spring 中我们都需要自己配置,Spring Boot 中的自动配置类都帮我们做了这些事情。J2EE的整体整合解决方案和自动配置都在 spring-boot-autoconfigure-x.x.x.RELEASE.jar
这个包下。
分析结果:
@SpringBootApplication
注解原理 主要通过两个@Import 注解,将配置的组件加载到 Spring 容器中,最终得以让 Spring 容器启动,其实底层还是通过 Spring 来实现的,你如果了解 Spring 容器底层实现,这块就会一目了然。
①会将 @SpringBootApplication 标注的主配置类,所在包及下面所有子包里面的所有组件扫描到 Spring 容器中;(这个注解:@Import(AutoConfigurationPackages.Registrar.class) )
②会将 SpringBoot 为 J2EE 企业级开发的默认配置,全部加载到 Spring 容器中。(这个注解:@Import(EnableAutoConfigurationImportSelector.class) )
博主写作不易,来个关注呗
求关注、求点赞,加个关注不迷路 ヾ(◍°∇°◍)ノ゙
博主不能保证写的所有知识点都正确,但是能保证纯手敲,错误也请指出,望轻喷 Thanks♪(・ω・)ノ