Spring Boot spring.factories的原理

文章目录
        • [1. spring.factories 用法](#1. spring.factories 用法)
        • [2. spring.factories 实现原理](#2. spring.factories 实现原理)
        • [3. spring.factories 用于解决什么问题?](#3. spring.factories 用于解决什么问题?)
          • [3.1 业务场景思考及 starter 机制引入](#3.1 业务场景思考及 starter 机制引入)
          • [3.2 Spring Boot starter 机制](#3.2 Spring Boot starter 机制)
        • [4. 小结](#4. 小结)

近期看到业务代码里用到 spring.factories 的配置,觉得场景不合适,且网上少有文章提及 spring.factories 与 starter 机制的前因后果,本文借此机会理一下 spring.factories 的用法及原理。简单地说, Spring Boot 的 spring.factories 配置机制类似于 Java SPI,工程代码中在 META-INF/spring.factories 文件中配置接口的实现类名称,然后 Spring Boot 在启动时扫描该配置文件并实例化配置文件中的Bean。 详细看下面用法:

1. spring.factories 用法
  • Spring Boot 启动类 MainApplication
c 复制代码
package com.zqh.test.springfactories;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

/**
 * @author fangchen
 * @date 2022-02-19 14:18
 */
@SpringBootApplication
public class MainApplication {

    public static void main(String[] args) {
        SpringApplication.run(MainApplication.class, args);
    }
}
  • META-INF/ spring.factories 配置类
c 复制代码
org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.zqh.test.springfactories.TestBean
  • TestBean.class 测试Bean
c 复制代码
package com.zqh.test.springfactories;

/**
 * @author fangchen
 * @date 2022-02-19 14:16
 */
public class TestBean {

    private Long id;

    public TestBean() {
        System.out.println("test bean init.....");
    }

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }
}
  • pom.xm maven 依赖
c 复制代码
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.zqh.test</groupId>
    <artifactId>springBootDemo</artifactId>
    <version>1.0-SNAPSHOT</version>


    <dependencies>
        <!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
            <version>2.6.3</version>
        </dependency>

    </dependencies>

</project>

运行 MainApplication 类,结果如下,从中可以看出 TestBean 类已经在Spring Boot 启动时已经进行实例化。

c 复制代码
2022-02-19 19:49:30.274  INFO 20112 --- [           main] c.z.t.springfactories.MainApplication    : Starting MainApplication using Java 1.8.0_221 on DESKTOP-ITB0Q9I with PID 20112 (D:\code\springBootDemo\target\classes started by NINGMEI in D:\code\springBootDemo)
2022-02-19 19:49:30.276  INFO 20112 --- [           main] c.z.t.springfactories.MainApplication    : No active profile set, falling back to default profiles: default
test bean init.....
2022-02-19 19:49:30.614  INFO 20112 --- [           main] c.z.t.springfactories.MainApplication    : Started MainApplication in 0.595 seconds (JVM running for 0.864)
2. spring.factories 实现原理

Spring Boot 启动时先读取 spring.factories 的类列表,然后再一个个实例化,并放到 Spring 上下文中。代码比较简单,不再详述,直接看图。

  • 源码类:org.springframework.core.io.support.SpringFactoriesLoader(spring-core包)
3. spring.factories 用于解决什么问题?

在日常开发中,通常将 Bean 注入到 Spring 容器有多种方式,比如 @Autowire、@Import 注解等等,又为什么使用 spring.factories 配置机制呢?

个人理解:当应用依赖三方 jar 包时,spring.factories 配置方式可以使三方 jar 包中的 bean 有选择地注入到 Spring 容器中。 下面以 Spring Boot 的 starter 机制来说明怎么使用 spring.factories 配置文件的。

3.1 业务场景思考及 starter 机制引入

先思考一个场景:应用需要依赖 RedisTemplate 进行缓存操作,怎么引入配置呢? 一般有两种方式:

  • 方式一:将依赖的 RedisTemplate 等相关 Bean 手动一个一个分散注入到业务应用中(比如@Autowire、@Configuration等)
  • 方式二:将依赖的 RedisTemplate 等相关 Bean 统一引入到一个配置类中,并标记为 @Configuration

第一种方式明显不可取,即耦合了业务,而且后续包升级比较麻烦。第二种统一的做法比较推荐,非常易于管理。假如采用方法二将这个标记为 @Configuration 类命名为 RedisAutoConfiguration,则这个类就封装了引入 redis 必须要注入 Spring 的 Bean,以此类推,后续再引入 mysql 时再将 mysql 必须依赖的类统一封装为 DataSourceAutoConfiguration 就可以了。恰好这正是 Spring Boot starter 机制内部的原理 ,即 Spring Boot starter将各个组件分别统一封装一个固定配置类中,如 redis 相关依赖类统一封装到 RedisAutoConfiguration 类中,数据库依赖类统一封装到 DataSourceAutoConfiguration 类等,然后将这些统一配置类配置到 spring.factories 文件中,Spring Boot在启动的时候(前提配置EnableAutoConfiguration注解,这也是EnableAutoConfiguration注解的由来)会一一扫描依赖 jar 包中 spring.factories 文件,最后将这些类注入到spring 容器中,业务直接引用即可。

3.2 Spring Boot starter 机制

理解了上面,Spring Boot starter 机制的原理和定义就比较清晰了。再理解一下下面这段话:springboot starter 是一种插件机制,抛弃了之前繁琐的配置,将复杂依赖统一集成进 starter。starter 的出现极大的帮助开发者们从繁琐的框架配置中解放出来,从而更专注于业务代码,并且 springboot 官方提供除了企业级项目不同场景的 starter 依赖模块,可以很便捷的集成进项目,比如 springboot 项目需要依赖 redis,我们只需要加入 spring-boot-starter-data-redis 依赖,并配置一些必须的连接信息即可以使用。

4. 小结

从 Spring Boot starter 机制的原理来理解 spring.factories 配置似乎更好理解一些,至于为了实现 Spring Boot starter 机制才引入 spring.factories 配置,还是先有 spring.factories 配置才有 Spring Boot starter 机制的取巧,那就不得而知了。总之,spring.factories 配置为 Spring Boot 的自动装配提供了方便,在此基础上产生的 Spring Boot starter 机制为很多中间件开发带来了方便。

欢迎如转载,请注明出处!欢迎关注微信公众号:方辰的博客
文章知识点与官方知识档案匹配,可进一步学习相关知识
Java技能树首页概览 133624 人正在系统学习中

相关推荐
IT毕设梦工厂4 小时前
计算机毕业设计选题推荐-在线拍卖系统-Java/Python项目实战
java·spring boot·python·django·毕业设计·源码·课程设计
是梦终空5 小时前
JAVA毕业设计176—基于Java+Springboot+vue3的交通旅游订票管理系统(源代码+数据库)
java·spring boot·vue·毕业设计·课程设计·源代码·交通订票
工业互联网专业6 小时前
毕业设计选题:基于springboot+vue+uniapp的驾校报名小程序
vue.js·spring boot·小程序·uni-app·毕业设计·源码·课程设计
无名指的等待7126 小时前
SpringBoot中使用ElasticSearch
java·spring boot·后端
.生产的驴7 小时前
SpringBoot 消息队列RabbitMQ 消费者确认机制 失败重试机制
java·spring boot·分布式·后端·rabbitmq·java-rabbitmq
AskHarries7 小时前
Spring Boot利用dag加速Spring beans初始化
java·spring boot·后端
苹果酱05678 小时前
一文读懂SpringCLoud
java·开发语言·spring boot·后端·中间件
掐指一算乀缺钱8 小时前
SpringBoot 数据库表结构文档生成
java·数据库·spring boot·后端·spring
飞翔的佩奇9 小时前
xxl-job适配sqlite本地数据库及mysql数据库。可根据配置指定使用哪种数据库。
数据库·spring boot·mysql·sqlite·xxl-job·任务调度
luoluoal11 小时前
java项目之基于Spring Boot智能无人仓库管理源码(springboot+vue)
java·vue.js·spring boot