spring.factories是什么?有什么用处?

您所在的位置:网站首页 SPI的作用 spring.factories是什么?有什么用处?

spring.factories是什么?有什么用处?

2022-12-17 22:28| 来源: 网络整理| 查看: 265

文章目录 作用总结问题引出去SpringBoot中探究

作用总结

在看一些开源项目时,我们常常会看到spring.factories 文件,或者读一些Spring-Boot 相关源码时也会遇到,从网上查了查,这个的作用是记录所有需要自动装配进 Spring 容器 bean类,如果你想要实现自己的自动配置,就将你的类通过键值对的方式写在你的spring.factories即可。

问题引出

这里我就产生了一个疑问:

我在自动配置的类已经打上了 @Configuration 的注解不就行了,为什么还要写 spring.factories 文件?

没办法,看来是有必要详细学一下了:

去SpringBoot中探究

在SpringBoot中使用@ComponentScan注解来扫描 @SpringBootApplication 所在的 Application 类所在的包(basepackage)下所有的 @component 注解(或拓展了 @component 的注解)标记的 bean,并注册到 spring 容器中

用过 Spring Boot 的都知道

@ComponentScan 注解的作用是扫描 @SpringBootApplication 所在的 Application 类所在的包(basepackage)下所有的 @component 注解(或拓展了 @component 的注解)标记的 bean,并注册到 spring 容器中。

那么问题来了

在 Spring Boot 项目中,如果你想要被 Spring 容器管理的 bean 不在 Spring Boot 包扫描路径下,怎么办?

解决 Spring Boot 中不能被默认路径扫描的配置类的方式,有 2 种:

(1)在 Spring Boot 主类上使用 @Import 注解 (2)使用 spring.factories 文件

在 Spring 中也有一种类似与 Java SPI 的加载机制。它在 resources/META-INF/spring.factories 文件中配置接口的实现类名称,然后在程序中读取这些配置文件并实例化。

这种自定义的SPI机制是 Spring Boot Starter 实现的基础。 在这里插入图片描述

Spring Factories 实现原理是什么?

spring-core 包里定义了 SpringFactoriesLoader 类,这个类实现了检索 META-INF/spring.factories 文件,并获取指定接口的配置的功能。在这个类中定义了两个对外的方法:

在这里插入图片描述 loadFactories 根据接口类获取其实现类的实例,这个方法返回的是对象列表。

/** * 加载并实例化给定类型的工厂实现 * {@value #FACTORIES_RESOURCE_LOCATION},使用给定的类加载器。 * 返回的工厂通过 {@link AnnotationAwareOrderComparator} 排序。 * 如果需要自定义实例化策略,请使用 {@link #loadFactoryNames} * 获取所有注册的工厂名称。 * * @param factoryType 代表工厂的接口或抽象类 * @param classLoader 用于加载的类加载器(可以是 {@code null} 使用默认值) * @throws IllegalArgumentException 如果任何工厂实现类不能 * 被加载或在实例化任何工厂时发生错误 * @see #loadFactoryNames */ public static List loadFactories(Class factoryType, @Nullable ClassLoader classLoader) { Assert.notNull(factoryType, "'factoryType' must not be null"); ClassLoader classLoaderToUse = classLoader; if (classLoaderToUse == null) { classLoaderToUse = SpringFactoriesLoader.class.getClassLoader(); } List factoryImplementationNames = loadFactoryNames(factoryType, classLoaderToUse); if (logger.isTraceEnabled()) { logger.trace("Loaded [" + factoryType.getName() + "] names: " + factoryImplementationNames); } List result = new ArrayList(factoryImplementationNames.size()); for (String factoryImplementationName : factoryImplementationNames) { result.add(instantiateFactory(factoryImplementationName, factoryType, classLoaderToUse)); } AnnotationAwareOrderComparator.sort(result); return result; }

loadFactoryNames 根据接口获取其接口类的名称,这个方法返回的是类名的列表。

public static List loadFactoryNames(Class factoryType, @Nullable ClassLoader classLoader) { String factoryTypeName = factoryType.getName(); return loadSpringFactories(classLoader).getOrDefault(factoryTypeName, Collections.emptyList()); }

上面的两个方法的关键都是从指定的 ClassLoader 中获取 spring.factories 文件,并解析得到类名列表,Springboot具体装配代码如下 在这里插入图片描述 从代码中我们可以知道,在这个方法中会遍历整个 spring-boot 项目的 classpath 下 ClassLoader 中所有 jar 包下的 spring.factories文件。也就是说我们可以在自己的 jar 中配置 spring.factories 文件,不会影响到其它地方的配置,也不会被别人的配置覆盖。

Spring Factories 在 Spring Boot 中的应用

在 Spring Boot 的很多包中都能够找到 spring.factories 文件,接下来我们以 spring-boot-autoconfigure 包为例进行介绍 在这里插入图片描述

结合前面的内容,可以看出 spring.factories 文件可以将 spring-boot 项目包以外的 bean(即在 pom 文件中添加依赖中的 bean)注册到 spring-boot 项目的 spring 容器。

由于@ComponentScan 注解只能扫描 spring-boot 项目包内的 bean 并注册到 spring 容器中,因此需要 @EnableAutoConfiguration 注解来注册项目包外的bean。而 spring.factories 文件,则是用来记录项目包外需要注册的bean类名



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3