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 配置类
org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.zqh.test.springfactories.TestBean

  • TestBean.class 测试Bean
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 依赖
<?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 启动时已经进行实例化。

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包)
    Spring Boot spring.factories的原理-LMLPHP
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 容器中,业务直接引用即可。

Spring Boot spring.factories的原理-LMLPHP

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 人正在系统学习中
11-05 20:40