Spring Boot源码解读

从 SpringBootApplication 注解入手

为了揭开 springboot 的奥秘,我们直接从 Annotation 入 手,看看@SpringBootApplication 里面,做了什么? 打开 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 {
}

@SpringBootConfiguration

@EnableAutoConfiguration

@ComponentScan

我们可以直接用这三个注解也可以启动 springboot 应用, 只是每次配置三个注解比较繁琐,所以直接用一个复合注 解更方便些。
然后仔细观察者三个注解,除了 EnableAutoConfiguration 可能稍微陌生一点,其他两个注解使用得都很多

简单分析@Configuration

Configuration 这个注解大家应该有用过,它是 JavaConfig形式的基于 Spring IOC 容器的配置类使用的一种注解。因 为 SpringBoot 本质上就是一个 spring 应用,所以通过这 个注解来加载 IOC 容器的配置是很正常的。所以在启动类 里面标注了@Configuration,意味着它其实也是一个 IoC 容器的配置类。

传统意义上的 spring 应用都是基于 xml 形式来配置 bean 的依赖关系。然后通过 spring 容器在启动的时候,把 bean 进行初始化并且,如果 bean 之间存在依赖关系,则分析这 些已经在 IoC 容器中的 bean 根据依赖关系进行组装。 直到 Java5 中,引入了 Annotations 这个特性,Spring 框 架也紧随大流并且推出了基于 Java 代码和 Annotation 元 信息的依赖关系绑定描述的方式。也就是 JavaConfig。

从 spring3 开始,spring 就支持了两种 bean 的配置方式, 一种是基于 xml 文件方式、另一种就是 JavaConfig 任何一个标注了@Configuration 的 Java 类定义都是一个 JavaConfig 配置类。而在这个配置类中,任何标注了 @Bean 的方法,它的返回值都会作为 Bean 定义注册到 Spring 的 IOC 容器,方法名默认成为这个 bean 的 id

简单分析 ComponentScan

ComponentScan 这个注解是大家接触得最多的了,相当 于 xml 配置文件中的、<context:component-scan >。 它的主要作用就是扫描指定路径下的标识了需要装配的类,自 动装配到 spring 的 Ioc 容器中。 标识需要装配的类的形式主要是:@Component、 @Repository、@Service、@Controller 这类的注解标识的 类。

ComponentScan 默认会扫描当前 package 下的的所有加 了相关注解标识的类到 IoC 容器中;

简单分析 EnableAutoConfiguration

我们把 EnableAutoConfiguration 放在最后讲的目的并不 是说它是一个新的东西,只是他对于 springboot 来说意义 重大。

找到 EnableAutoConfiguration,我们可以看到每一个涉及 到 Enable 开头的注解,都会带有一个@Import 的注解。

@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {
}

@import

import 注解是什么意思呢? 联想到 xml 形式下有一个 <import resource/> 形式的注解,就明白它的作用了。 import 就是把多个分来的容器配置合并在一个配置中。在 JavaConfig 中所表达的意义是一样的。

深入分析 EnableAutoConfiguration

EnableAutoConfiguration 的 主 要 作 用 其 实 就 是 帮 助 springboot 应用把所有符合条件的@Configuration 配置 都加载到当前 SpringBoot 创建并使用的 IoC 容器中。 再回到 EnableAutoConfiguration 这个注解中,我们发现 它的 import 是这样
@Import(AutoConfigurationImportSelector.class)

AutoConfigurationImportSelector 是什么?

Enable 注解不仅仅可以像前面演示的案例一样很简单的实 现多个 Configuration 的整合,还可以实现一些复杂的场 景,比如可以根据上下文来激活不同类型的 bean, @Import 注解可以配置三种不同的 class

  1. 第一种就是前面演示过的,基于普通 bean 或者带有 @Configuration 的 bean 进行诸如
  2. 实现 ImportSelector 接口进行动态注入
  3. 实现 ImportBeanDefinitionRegistrar 接口进行动态注入

@EnableAutoConfiguration 注解的实现原理

了解了 ImportSelector 和 ImportBeanDefinitionRegistrar 后,对于 EnableAutoConfiguration 的理解就容易一些了 它会通过 import 导入第三方提供的 bean 的配置类:

从名字来看,可以猜到它是基于 ImportSelector 来实现 基于动态 bean 的加载功能。之前我们讲过 Springboot @Enable*注解的工作原理 ImportSelector 接口 selectImports 返回的数组(类的全类名)都会被纳入到 spring 容器中。 那么可以猜想到这里的实现原理也一定是一样的,定位到 AutoConfigurationImportSelector 这个类中的 selectImports 方法
本质上来说,其实 EnableAutoConfiguration 会帮助 springboot 应用把所有符合@Configuration 配置都加载 到当前 SpringBoot 创建的 IoC 容器,而这里面借助了 Spring 框架提供的一个工具类 SpringFactoriesLoader 的 支持。以及用到了 Spring 提供的条件注解 @Conditional,选择性的针对需要加载的 bean 进行条件 过滤。

SpringFactoriesLoader

SpringFactoriesLoader 这个工具类的使用。它其实和 java 中的 SPI 机制的原理是一样的,不过它比 SPI 更好的 点在于不会一次性加载所有的类,而是根据 key 进行加 载。

首 先 , SpringFactoriesLoader 的 作 用 是 从 classpath/META-INF/spring.factories 文件中,根据 key 来 加载对应的类到 spring IoC 容器中。

在分析 AutoConfigurationImportSelector 的源码时,会 先扫描 spring-autoconfiguration-metadata.properties 文件,最后在扫描 spring.factories 对应的类时,会结合 前面的元数据进行过滤,为什么要过滤呢? 原因是很多 的@Configuration 其实是依托于其他的框架来加载的, 如果当前的 classpath 环境下没有相关联的依赖,则意味着这些类没必要进行加载,所以,通过这种条件过滤可以 有效的减少@configuration 类的数量从而降低 SpringBoot 的启动时间。

Conditional 中的其他注解

Conditions 描述
@ConditionalOnBean 在存在某个 bean 的时候
@ConditionalOnMissingBean 不存在某个 bean 的时候
@ConditionalOnClass 当前 classpath 可以找到某个类型的类时
@ConditionalOnMissingClass 当前 classpath 不可以找到某个类型的类 时
@ConditionalOnResource 当前 classpath 是否存在某个资源文件
@ConditionalOnProperty 当前 jvm 是否包含某个系统属性为某个值
@ConditionalOnWebApplication 当前 spring context 是否是 web 应用程序

文章作者: 凌云
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 凌云 !
  目录