从 getFactory 方法的源码可以看出 , 其核心逻辑分为 4 步:
- 首先,尝试查找全局属性org.apache.commons.logging.LogFactory,如果指定了具体类,尝试创建实例 。
- 利用 Java SPI 机制,尝试在 classpatch 的 META-INF/services 目录下寻找org.apache.commons.logging.LogFactory 的实现类 。
- 尝试从 classpath 目录下的 commons-logging.properties 文件中查找org.apache.commons.logging.LogFactory 属性,如果指定了具体类,尝试创建实例 。
- 以上情况如果都不满足 , 则实例化默认实现类 , 即org.apache.commons.logging.impl.LogFactoryImpl 。
下面是一个 Spring Boot 入口示例,可以看到,代码非常简洁 。
import org.springframework.boot.SpringApplication;import org.springframework.boot.autoconfigure.SpringBootApplication;import org.springframework.web.bind.annotation.GetMapping;import org.springframework.web.bind.annotation.RequestParam;import org.springframework.web.bind.annotation.RestController;@SpringBootApplication@RestControllerpublic class DemoApplication {public static void main(String[] args) {SpringApplication.run(DemoApplication.class, args);}@GetMapping("/hello")public String hello(@RequestParam(value = "https://www.huyubaike.com/biancheng/name", defaultValue = "https://www.huyubaike.com/biancheng/World") String name) {return String.format("Hello %s!", name);}}那么,Spring Boot 是如何做到寥寥几行代码 , 就可以运行一个 Spring Boot 应用的呢 。我们不妨带着疑问 , 从源码入手,一步步探究其原理 。
4.3.1 @SpringBootApplication 注解首先,Spring Boot 应用的启动类上都会标记一个
@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 {// 略}除了 @Target、 @Retention、@Documented、@Inherited 这几个元注解, @SpringBootApplication 注解的定义中还标记了 @SpringBootConfiguration、@EnableAutoConfiguration、@ComponentScan 三个注解 。
4.3.2 @SpringBootConfiguration 注解从@SpringBootConfiguration 注解的定义来看,@SpringBootConfiguration 注解本质上就是一个 @Configuration 注解,这意味着被@SpringBootConfiguration 注解修饰的类会被 Spring Boot 识别为一个配置类 。
@Target({ElementType.TYPE})@Retention(RetentionPolicy.RUNTIME)@Documented@Configurationpublic @interface SpringBootConfiguration {@AliasFor(annotation = Configuration.class)boolean proxyBeanMethods() default true;}4.3.3 @EnableAutoConfiguration 注解@EnableAutoConfiguration 注解定义如下:
@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 注解包含了 @AutoConfigurationPackage与 @Import({AutoConfigurationImportSelector.class}) 两个注解 。
4.3.4 @AutoConfigurationPackage 注解@AutoConfigurationPackage 会将被修饰的类作为主配置类,该类所在的 package 会被视为根路径,Spring Boot 默认会自动扫描根路径下的所有 Spring Bean(被 @Component 以及继承 @Component 的各个注解所修饰的类) 。——这就是为什么 Spring Boot 的启动类一般要置于根路径的原因 。这个功能等同于在 Spring xml 配置中通过 context:component-scan 来指定扫描路径 。@Import 注解的作用是向 Spring 容器中直接注入指定组件 。@AutoConfigurationPackage 注解中注明了@Import({Registrar.class}) 。Registrar 类用于保存 Spring Boot 的入口类、根路径等信息 。
4.3.5 SpringFactoriesLoader.loadFactoryNames 方法@Import(AutoConfigurationImportSelector.class) 表示直接注入AutoConfigurationImportSelector 。
AutoConfigurationImportSelector 有一个核心方法getCandidateConfigurations 用于获取候选配置 。该方法调用了SpringFactoriesLoader.loadFactoryNames 方法 , 这个方法即为 Spring Boot SPI 的关键 , 它负责加载所有 META-INF/spring.factories 文件,加载的过程由 SpringFactoriesLoader 负责 。
Spring Boot 的 META-INF/spring.factories 文件本质上就是一个 properties 文件,数据内容就是一个个键值对 。
推荐阅读
- Redisson源码解读-分布式锁
- 红米note9pro评测最新_红米note9pro深度测评
- EasyPoi大数据导入导出百万级实例
- Dubbo-聊聊通信模块设计
- 1分钟完成在线测试部署便捷收集班级同学文件的web管理系统
- 联想拯救者R7000 2021款官方配置_联想拯救者R7000 2021款升级情况
- 简易版 纯css爱心代码-最近超级火的打火机与公主裙中的爱心代码
- 三年级数学下册练习题300道 三年级数学计算题300道
- 【lwip】10-ICMP协议&源码分析
- 华为开发者大会2022:HMS Core 3D建模服务再升级,万物皆可驱动