Spring Boot学习笔记(三):@SpringBootApplication注解分析

        通过前面内容【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
@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方法,最终它会加载"META-INF/spring.factories"路径下的所有配置信息
		//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)


SpringBoot 容器启动原理:@SpringBootApplication注解,介绍到此为止。

如果本文对你有所帮助,那就给我点个赞呗 O(∩_∩)O

End

发布了301 篇原创文章 · 获赞 66 · 访问量 7万+

猜你喜欢

转载自blog.csdn.net/lzb348110175/article/details/105128752