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

相关推荐
秋千码途4 分钟前
小架构step系列07:查找日志配置文件
spring boot·后端·架构
seventeennnnn3 小时前
谢飞机的Java高级开发面试:从Spring Boot到分布式架构的蜕变之旅
spring boot·微服务架构·java面试·分布式系统·电商支付
超级小忍4 小时前
服务端向客户端主动推送数据的几种方法(Spring Boot 环境)
java·spring boot·后端
时间会给答案scidag4 小时前
报错 400 和405解决方案
vue.js·spring boot
Wyc724095 小时前
SpringBoot
java·spring boot·spring
ladymorgana6 小时前
【Spring Boot】HikariCP 连接池 YAML 配置详解
spring boot·后端·mysql·连接池·hikaricp
GJCTYU8 小时前
spring中@Transactional注解和事务的实战理解附代码
数据库·spring boot·后端·spring·oracle·mybatis
风象南9 小时前
SpringBoot敏感配置项加密与解密实战
java·spring boot·后端
写不出来就跑路10 小时前
暑期实习感悟与经验分享:从校园到职场的成长之路
java·开发语言·经验分享·spring boot
程序员张314 小时前
Maven编译和打包插件
java·spring boot·maven