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 人正在系统学习中

相关推荐
悟空码字1 天前
Spring Boot 整合 MongoDB 最佳实践:CRUD、分页、事务、索引全覆盖
java·spring boot·后端
皮皮林5513 天前
拒绝写重复代码,试试这套开源的 SpringBoot 组件,效率翻倍~
java·spring boot
用户908324602735 天前
Spring AI 1.1.2 + Neo4j:用知识图谱增强 RAG 检索(上篇:图谱构建)
java·spring boot
用户8307196840826 天前
Spring Boot 集成 RabbitMQ :8 个最佳实践,杜绝消息丢失与队列阻塞
spring boot·后端·rabbitmq
Java水解6 天前
Spring Boot 视图层与模板引擎
spring boot·后端
Java水解6 天前
一文搞懂 Spring Boot 默认数据库连接池 HikariCP
spring boot·后端
洋洋技术笔记6 天前
Spring Boot Web MVC配置详解
spring boot·后端
初次攀爬者7 天前
Kafka 基础介绍
spring boot·kafka·消息队列
用户8307196840827 天前
spring ai alibaba + nacos +mcp 实现mcp服务负载均衡调用实战
spring boot·spring·mcp
Java水解7 天前
SpringBoot3全栈开发实战:从入门到精通的完整指南
spring boot·后端