在src/main/resource文件下,可以新建META-INF文件,并新建spring.factories文件,可以实现让spring扫描包扫描不到的bean对象实例化。

准备工作

新建了一个父级项目test_factories,下面新建了两个module,分别是use_factory,provider_factory,在use_factory的pom.xml中引入provider_factory的依赖。

在provider_factory中写一个监听器:

@Slf4j
public class SelfDefinedListener implements ApplicationListener<ApplicationEnvironmentPreparedEvent> {public SelfDefinedListener() {log.info("自定义的监听器实例化");}@Overridepublic void onApplicationEvent(ApplicationEnvironmentPreparedEvent event) {Environment env = event.getEnvironment();log.info("env= {}",env);}
}

use_factory中直接调用SelfDefinedListener

然后在use_factory中随便写一个访问方法:

@RestController
@RequestMapping("/test")
public class TestWeb {private SelfDefinedListener self;@GetMapping("/test1")public String test(){self.test();return "调用结束";}
}

可以明显是为self对象是null的。因为没有任何地方给这个对象有实例化的过程。

SelfDefinedListener使用@Component注解

如果直接在use_factory中直接使用@Autowired注解是没用的,因为SelfDefinedListener不在bean管理器中,会找不到类型报错。需要在provider_factory使用@Component注解,并启动use_factory(只会启动这个项目,不会启动provider_factory)

可以看到在控制台中有打印信息,说明调用了构造函数开始了实例化,再次调用user_factory中的访问方法。

页面显示正常。

使用spring.factories

把@Compoent和@Autowired注解去掉,在use_factory中新建META-INF/spring.factories文件,如下图:

然后启动use_factory:

可以看到不仅打印了构造函数的日志,而且还打印了onApplicationEvent方法的内容。如果构造函数的日志打印了两边,可能是因为用了spring-boot-devtools热部署,直接在pom.xml中注释掉就行。

使用@Component和spring.factories的区别

明显可以看到的主要区别就是加载顺序问题,@Component打印的构造函数的日志是在启动use_factory之后打印的;但是使用spring.factories则是在打印use_factory启动日志之前就出来了。

SpringFactoriesLoader读取spring.factories

SpringFactoriesLoader类就是专门去读取META-INF/spring.factories文件的, 截取一段源码:

 private static Map<String, List<String>> loadSpringFactories(ClassLoader classLoader) {Map<String, List<String>> result = cache.get(classLoader);if (result != null) {return result;}result = new HashMap<>();try {Enumeration<URL> urls = classLoader.getResources('META-INF/spring.factories');while (urls.hasMoreElements()) {URL url = urls.nextElement();UrlResource resource = new UrlResource(url);Properties properties = PropertiesLoaderUtils.loadProperties(resource);for (Map.Entry<?, ?> entry : properties.entrySet()) {String factoryTypeName = ((String) entry.getKey()).trim();String[] factoryImplementationNames =StringUtils.commaDelimitedListToStringArray((String) entry.getValue());for (String factoryImplementationName : factoryImplementationNames) {result.computeIfAbsent(factoryTypeName, key -> new ArrayList<>()).add(factoryImplementationName.trim());}}}// Replace all lists with unmodifiable lists containing unique elementsresult.replaceAll((factoryType, implementations) -> implementations.stream().distinct().collect(Collectors.collectingAndThen(Collectors.toList(), Collections::unmodifiableList)));cache.put(classLoader, result);}catch (IOException ex) {throw new IllegalArgumentException("Unable to load factories from location [" +FACTORIES_RESOURCE_LOCATION + "]", ex);}return result;}

仿照这段代码自己试了下,确实读取到了:

test.factories中的内容是:

org.springframework.boot.autoconfigure.EnableAutoConfiguration=/com.example.TestProject.test2022.day0723.TestConfigurationBean

SpringFactoriesLoader类的loadSpringFactories方法中的ClassLoader参数

ClassLoader就是类加载器,作用就是将java类加载到jvm虚拟机中。

引用地址:ClassLoader——JAVA成长之路

Java 中的类加载器大致可以分成两类,一类是系统提供的,另外一类则是由 Java 应用开发人员编写的。系统提供的类加载器主要有下面三个:

引导类加载器(bootstrap class loader):它用来加载 Java 的核心库,是用原生代码来实现的,并不继承自
java.lang.ClassLoader。

扩展类加载器(extensions class loader):它用来加载 Java 的扩展库。Java
虚拟机的实现会提供一个扩展库目录。该类加载器在此目录里面查找并加载 Java 类。

系统类加载器(system class loader):它根据 Java 应用的类路径(CLASSPATH)来加载 Java
类。一般来说,Java 应用的类都是由它来完成加载的。可以通过
ClassLoader.getSystemClassLoader()来获取它。

除了系统提供的类加载器以外,开发人员可以通过继承 java.lang.ClassLoader类的方式实现自己的类加载器,以满足一些特殊的需求。

随笔记录-spring.factories相关推荐

  1. spring.factories 的妙用

    现象 在阅读 Spring-Boot 相关源码时,常常见到 spring.factories 文件,里面写了自动配置(AutoConfiguration)相关的类名,因此产生了一个疑问:"明 ...

  2. spring.factories 的基本使用

    spring.factories 的基本作用 在若依-微服务版的源码学习中,发现项目中多次用到了 spring.factories .因此记录一下自己的学习总结: 参考博客: spring.facto ...

  3. SpringBoot扩展机制——spring factories

    介绍 Spring Boot中有一种非常解耦的扩展机制:Spring Factories.这种扩展机制实际上是仿照 Java 中的 SPI 扩展机制来实现的.它在META-INF/spring.fac ...

  4. 【SpringBoot】SPI 与 spring.factories

    目录 什么是 SPI SPI 原理 Spring.factories 实现原理 应用 什么是 SPI 即 Service Provider Interface.是 JDK 内置的一种服务提供发现机制, ...

  5. @Import和spring.factories实现原理

    本篇文章主要记录@Import和spring.factories实现原理,具体怎么用,可自行百度 demo地址(代码结构很简单,不做任何说明) @Import 基本用法参考 spring.factor ...

  6. spring.factories文件

    本文涉及spring-boot版本为2.1.6.RELEASE 在阅读spring-boot相关源码时,常常见到spring.factories文件,里面写了自动配置(AutoConfiguratio ...

  7. META-INF/spring.factories文件的作用是什么

    META-INF/spring.factories文件的作用是什么 这片文章中会找到你想要的答案. *看一个SpringBoot入口类 package com.example.multithread; ...

  8. SpringBoot解耦的扩展机制 Spring Factories介绍及使用

    一.什么是 SPI机制 Spring Boot中有一种非常解耦的扩展机制:Spring Factories.这种扩展机制实际上是仿照Java中的SPI扩展机制来实现的.SPI的全名为Service P ...

  9. Spring Boot 之spring.factories

    首先抛出一个问题:如果想要被Spring容器管理的Bean的路径不再Spring Boot 的包扫描路径下,怎么办呢?也就是如何去加载第三方的Bean 呢? 有两种方式可以解决: 这里我们使用Swag ...

最新文章

  1. 将MPM雪模拟移植到Maya
  2. Web测试实践-任务进度-Day02
  3. python谷歌浏览器驱动安装失败_阿里云centos7.2下安装chrome浏览器+webdriver+selenium及常见设置-傻瓜教程...
  4. angular-ui-router路由备忘
  5. Vs2010删除空白行
  6. 均值滤波、中值滤波、混合中值滤波C++源码实例
  7. 【2022】JVM常见面试真题详解
  8. Python Pytest中fixture之yield唤醒teardown和终结函数addfinalizer
  9. 【英语学习】【Daily English】U12 E-World L04 I bought it on a Swiss website
  10. java compiler.run_eclipse build path与java Compiler
  11. centos7.3二进制安装mariadb10.2.8
  12. 2月25日 局域不变特征的目标跟踪,SURF算子,KLT算子
  13. 简述STL中容器适配器的概念
  14. 百科园c语言题库13164,C语言题库-编程
  15. python遥感数据有偿处理_地质男转行学遥感Python——DMSP数据预处理二
  16. 子类化和超子类化http://www.cppblog.com/wangjia184/archive/2008/03/27/45520.html
  17. 井下三专两闭锁的内容_三专两闭锁
  18. 一篇文带你零基础玩转mysql触发器 | 超级干货,建议收藏
  19. 【UE4全反射松耦合框架笔记】第一章 UE4框架基础(下)
  20. 【华为od机试】统计射击比赛成绩-Python3

热门文章

  1. 将车辆数据集kitti转换为VOC格式(车辆检测)
  2. PASCAL VOC
  3. 讲“格调”的大疆,能否重回高增长?
  4. 计算机检测维修的英语缩写,(完整版)必须懂的53个电脑英文缩写(2页)-原创力文档...
  5. CentOS 7下安装达梦8开发版
  6. Python三大排序算法实现
  7. C# Color 颜色对照表
  8. 【机器学习】TensorFlow 在 iOS 端的用例
  9. cad老是出现计算机内存不足怎么办,CAD出图显示内存不足怎么办?
  10. 计算机病毒存在的目的不是影响计算机,计算机病毒论文.doc