JDK中的SPI和Spring中的SPI
我理解的SPI的作用就是根据自己的需要加载外部组件。
JDK中的实现直接参考:Java SPI详解
Spring中的SPI是怎么实现的呢?一开始接触是在springboot的自动装配,加载文件中的自动装配类。其实在springboot启动流程中大量的用到了这个。
核心类:org.springframework.core.io.support.SpringFactoriesLoader
四个方法:
// 加载指定类型的类,并且已经实例化了
public static <T> List<T> loadFactories(Class<T> factoryType, @Nullable ClassLoader classLoader)// 加载指定的类,返回的是类的全限定类名
public static List<String> loadFactoryNames(Class<?> factoryType, @Nullable ClassLoader classLoader)// 加载所有的类,返回的是类的全限定类名
private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader)// 实例化类
private static <T> T instantiateFactory(String factoryImplementationName, Class<T> factoryType, ClassLoader classLoader)
先看SpringFactoriesLoader#loadSpringFactories方法
private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) {// 根据类加载器的不同,分别做了缓存。MultiValueMap<String, String> result = cache.get(classLoader);if (result != null) {return result;}try {// 传入路径,加载所有jar包下该文件// String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories";Enumeration<URL> urls = (classLoader != null ?classLoader.getResources(FACTORIES_RESOURCE_LOCATION) :ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION));// 缓存 result = new LinkedMultiValueMap<>();while (urls.hasMoreElements()) {// 得到一个文件资源URL url = urls.nextElement();UrlResource resource = new UrlResource(url);// 加载文件,变成Properties 类型Properties properties = PropertiesLoaderUtils.loadProperties(resource);// 遍历properties for (Map.Entry<?, ?> entry : properties.entrySet()) {// key是:指定的类型,value:可以是多个匹配的类型String factoryTypeName = ((String) entry.getKey()).trim();for (String factoryImplementationName : StringUtils.commaDelimitedListToStringArray((String) entry.getValue())) {// 放入map中。result.add(factoryTypeName, factoryImplementationName.trim());}}}// 放入缓存。cache.put(classLoader, result);return result;}catch (IOException ex) {throw new IllegalArgumentException("Unable to load factories from location [" +FACTORIES_RESOURCE_LOCATION + "]", ex);}}
小结:使用类加载器加载所有jar包中的META-INF/spring.factories文件,从文件中解析出key,value放入map中。
如果是多个匹配的类型,使用逗号隔开
SpringFactoriesLoader#loadFactoryNames
public static List<String> loadFactoryNames(Class<?> factoryType, @Nullable ClassLoader classLoader) {String factoryTypeName = factoryType.getName();return loadSpringFactories(classLoader).getOrDefault(factoryTypeName, Collections.emptyList());}
加载指定类型,之前分析了加载所有类型的,只要从所有类型中找出指定的就可以。
SpringFactoriesLoader#loadFactories
public static <T> List<T> loadFactories(Class<T> factoryType, @Nullable ClassLoader classLoader) {Assert.notNull(factoryType, "'factoryType' must not be null");ClassLoader classLoaderToUse = classLoader;if (classLoaderToUse == null) {classLoaderToUse = SpringFactoriesLoader.class.getClassLoader();}List<String> factoryImplementationNames = loadFactoryNames(factoryType, classLoaderToUse);if (logger.isTraceEnabled()) {logger.trace("Loaded [" + factoryType.getName() + "] names: " + factoryImplementationNames);}List<T> result = new ArrayList<>(factoryImplementationNames.size());for (String factoryImplementationName : factoryImplementationNames) {result.add(instantiateFactory(factoryImplementationName, factoryType, classLoaderToUse));}AnnotationAwareOrderComparator.sort(result);return result;}
加载完指定的类型之后,得到类的全限定类名,实例化类
@SuppressWarnings("unchecked")private static <T> T instantiateFactory(String factoryImplementationName, Class<T> factoryType, ClassLoader classLoader) {try {// 得到类的元信息Class<?> factoryImplementationClass = ClassUtils.forName(factoryImplementationName, classLoader);// 如果不是指定的类型,抛异常if (!factoryType.isAssignableFrom(factoryImplementationClass)) {throw new IllegalArgumentException("Class [" + factoryImplementationName + "] is not assignable to factory type [" + factoryType.getName() + "]");}// 反射实例化。return (T) ReflectionUtils.accessibleConstructor(factoryImplementationClass).newInstance();}catch (Throwable ex) {throw new IllegalArgumentException("Unable to instantiate factory class [" + factoryImplementationName + "] for factory type [" + factoryType.getName() + "]",ex);}}
JDK中的SPI和Spring中的SPI相关推荐
- 剖析 SPI 在 Spring 中的应用
vivo 互联网服务器团队 - Ma Jian 一.概述 SPI(Service Provider Interface),是Java内置的一种服务提供发现机制,可以用来提高框架的扩展性,主要用于框架的 ...
- web.xml中的contextConfigLocation在spring中的作用
在web.xml中通过contextConfigLocation配置spring,contextConfigLocation 参数定义了要装入的 Spring 配置文件. 如果想装入多个配置文件,可以 ...
- java中factory_Java后台面试--Spring中FactoryBean与BeanFactory的使用及区别
以前刚转Java的时候去面试被问到过Spring中FactoryBean与BeanFactory的使用及区别,由于之前没有重视这两个的区别,只是在配置文件里面加bean结点并通过注解的形式调用,所以被 ...
- java 调用 spring,java中使用redis和spring中调用redis
1.需要的jar包,配置的pom.xml文件 redis.clients jedis 2.7.2 2.java调用 /** * @文件名称: JedisTest.java * @描述: TODO * ...
- (转)Spring中Singleton模式的线程安全
不知道哪里的文章,总结性还是比较好的.但是代码凌乱,有的还没有图.如果找到原文了可以进行替换! spring中的单例 spring中管理的bean实例默认情况下是单例的[sigleton类型],就还有 ...
- java观察者模式在spring中的应用_Spring源码之spring中的观察者模式和监听器的使用...
声明:本文根据鲁班学院子路老师spring中观察者模式课程整理得来 观察者模式特点: 被观察者持有监听的观察者的引用. 被观察者支持增加和删除的观察者. 被观察者状态改变通知观察者. JDK中观察者i ...
- Spring中Singleton模式的线程安全
不知道哪里的文章,总结性还是比较好的.但是代码凌乱,有的还没有图.如果找到原文了可以进行替换! spring中的单例 spring中管理的bean实例默认情况下是单例的[sigleton类型],就还有 ...
- 面试必杀技,讲一讲Spring中的循环依赖
本系列文章: 听说你还没学Spring就被源码编译劝退了?30+张图带你玩转Spring编译 读源码,我们可以从第一行读起 你知道Spring是怎么解析配置类的吗? 配置类为什么要添加@Configu ...
- Spring 中的各种注解,光会用可不够哦!
来源:https://digdeep.cnblogs.com/digdeep/p/4525567.html 1. Java中的注解 2. 使用 元注解 来自定义注解 和 处理自定义注解 3. spri ...
- Spring(四)——AOP、Spring实现AOP、Spring整合Mybatis、Spring中的事务管理
文章目录 1. 什么是AOP 2. 使用Spring实现AOP 2.1 使用Spring的API 接口实现 2.2 自定义实现 2.3 使用注解实现 3. 整合MyBatis 3.1 MyBatis- ...
最新文章
- bash脚本编程之for循环
- 为什么磁场强度大了呢?
- 【Python】纯代码通过神经网络实现线性回归的拟合
- 【翻译】关于vertical-align所有你需要知道的
- java抽象继承-模板方法
- ncbi查找目的基因序列_NCBI大搜索之目的基因寻踪
- run as date怎么用_熟词僻义 | date是一种什么水果?
- 无线网络受限制或无连接处理方法
- php类中引函数变量,一个非线性差分方程的隐函数解
- html和body高度不一致,即使html和body都是容器流体的高度不是100%
- 雷电游戏java源代码,java雷电游戏源码项目
- 破解软件下载网站100个
- 【DCANet2022】DCANet: Differential Convolution Attention Network for RGB-D Semantic Segmentation
- 怎样学手机拼音打字html t=45,在手机上怎么学拼音打字
- 青龙面板搭建及记录踩过的坑
- 计算机无法登陆账户 让注销,电脑开机出现登陆账户,点了以后就马上注销,怎么处理?...
- HDU oj 自动交题爬虫
- 图像预处理——matlab
- 以MacOS 13为例,VMware 16安装MacOS
- 基于python实现网页版微信API,包含终端版微信及微信机器人
热门文章
- linux apache 403 forbidden,apache服务器显示403 Forbidden的原因和解决方法
- steam服务器维护6月28,绝地求生6月28日维护更新公告 绝地求生6月28日更新内容汇总...
- 判断iOS机器是否支持TouchId, FaceId
- python tkinter listbox控件 简书_python tkinter模块的控件操作(1)
- 459.重复的子字符串
- matplotlib绘制横向柱状图
- 凸优化第七章统计估计 7.1参数分布估计
- 代码整洁读书笔记---序,前言,代码猴子
- 刚才读《基于Lucene的中文自然语言搜索引擎》后感
- MongoDB 在windows shell环境下的基本操作和命令的使用示例(三)