当前位置: 首页 > news >正文

Java ServiceLoader、Spring SpringFactoriesLoader、SPI方式解耦第三方组件

背景

项目框架中引入了各种第三方组件,比如nacos、seata、mq、Redis、MySQL等等,这些三方组件一般都具有可替代性,如果把这些组件拿来直接使用会对原框架有一定侵入性,后期可能造成框架升级困难、运维复杂等多方面的问题。

使用SPI可以有效解耦三方组件,降低组件变更对原框架的影响,SPI需要原项目框架把可能用到的三方组件的功能抽象出接口,然后不同的组件按照SPI规范提供对应实现,完成对原项目框架的升级拓展。

实现

接口项目

SPI接口

由框架项目抽象出功能接口,例:

package com.test.spi;

public interface IHelloService {
	void sayHello(String name);
}

SPI接口工具类

通过这个工具类获取SPI接口的实现类,例:

package com.test.spi;

import java.util.List;
import java.util.ServiceLoader;

import org.springframework.core.io.support.SpringFactoriesLoader;
import org.springframework.util.CollectionUtils;

public class HelloServiceBuild {

	private static IHelloService service;

	public static IHelloService build() {
		if (null != service) {
			return service;
		}

		ServiceLoader<IHelloService> serviceLoader = ServiceLoader.load(IHelloService.class);
		if (serviceLoader.iterator().hasNext()) {
			service = serviceLoader.iterator().next();
		}

		if (null == service) {
			List<IHelloService> loadFactories = SpringFactoriesLoader.loadFactories(IHelloService.class, Thread.currentThread().getContextClassLoader());
			if (!CollectionUtils.isEmpty(loadFactories)) {
				service = loadFactories.get(0);
			}
		}

		return service;
	}
}

其中ServiceLoader是java自带获取SPI的方式,SpringFactoriesLoader是有spring提供的获取SPI的方式,可以看出这两种方式都会获取到一个SPI实例的集合,本例只获取集合中的第一个服务实例,两种方式都没有提供通过类名或者是其他方式获取某一确定实例的方式,需要自己拓展,可以参考dubbo的SPI实现过程。

服务项目

接口实现类

是SPI接口的具体实现,最终上面的工具类会实例化出这个类,通过该类完成业务调用,例:

package com.test.spi.provider;

import com.test.spi.IHelloService;

public class HelloServiceProvider implements IHelloService {
    @Override
    public void sayHello(String name) {
        System.out.println("Hello " + name);
    }
}

接口配置文件

SPI要完成自动加载实现类,需要借助配置文件,java和spring的配置方式不同,二选一留一个配置即可。

Java配置方式

需要在项目的META-INF/services目录下创建文件名为SPI接口全称的文件,例:

com.test.spi.IHelloService

文件内容为接口实现类的全名

com.test.spi.provider.HelloServiceProvider

Spring配置方式

需要在项目的META-INF目录下创建文件名为spring.factories的文件,

文件内容为SPI接口全名=SPI实现类全名

com.test.spi.IHelloService=com.test.spi.provider.HelloServiceProvider

使用SPI

SPI服务项目一般都是jar包,打包的时候需要确保META-INF文件夹及里面的内容在jar包里, 

使用时通过build获取服务提供者

IHelloService service = HelloServiceBuild.build();

if(null != service){
    service.sayHello("luck");
}

相关文章:

  • 聚焦个性化与场景化,全新升级的三星电视看点何在?
  • LeetCode每日一题JAVA、JavaSrcipt题解——2022.08.21-08.31
  • 哪种神经网络最好使用,哪种神经网络最好用
  • 02- Spring IOC与DI
  • 基于jeecgboot流程管理平台的自定义业务表单集成方法
  • 矩阵类问题处理技巧
  • MyBatis Plus (三) --------- 入门 HelloWorld
  • 云安全践行者:亚马逊云科技如何打好“安全”牌?
  • 第8章 Spring AOP
  • 操作系统 | 【一 概述】强化阶段 —— 应用题总结
  • 深度学习(PyTorch)——python中的两大法宝(dir与help)
  • 记一次vue^2.6.5-router^3.0.6的keep-alive事故
  • vi vim 快速跳到文件末尾 在最后一行下方新增一行 (光标换行,文字不换行)
  • 【我不熟悉的css】03. 使用px、em、rem
  • 1.直流无刷电机BLDC转速计算推论
  • es的写入过程
  • HTTP--网络协议分层,http历史(二)
  • HTTP中的ETag在移动客户端的应用
  • JavaScript 基础知识 - 入门篇(一)
  • java中具有继承关系的类及其对象初始化顺序
  • leetcode378. Kth Smallest Element in a Sorted Matrix
  • node-glob通配符
  • 阿里云容器服务区块链解决方案全新升级 支持Hyperledger Fabric v1.1
  • 第十八天-企业应用架构模式-基本模式
  • 湖南卫视:中国白领因网络偷菜成当代最寂寞的人?
  • 如何合理的规划jvm性能调优
  • 7行Python代码的人脸识别
  • ​软考-高级-系统架构设计师教程(清华第2版)【第12章 信息系统架构设计理论与实践(P420~465)-思维导图】​
  • #【QT 5 调试软件后,发布相关:软件生成exe文件 + 文件打包】
  • #Linux(make工具和makefile文件以及makefile语法)
  • (附源码)springboot建达集团公司平台 毕业设计 141538
  • (更新)A股上市公司华证ESG评级得分稳健性校验ESG得分年均值中位数(2009-2023年.12)
  • **Java有哪些悲观锁的实现_乐观锁、悲观锁、Redis分布式锁和Zookeeper分布式锁的实现以及流程原理...
  • ./indexer: error while loading shared libraries: libmysqlclient.so.18: cannot open shared object fil
  • .bat批处理(六):替换字符串中匹配的子串
  • .NET 设计模式—简单工厂(Simple Factory Pattern)
  • .Net 知识杂记
  • .NET/C# 使用 ConditionalWeakTable 附加字段(CLR 版本的附加属性,也可用用来当作弱引用字典 WeakDictionary)
  • @CacheInvalidate(name = “xxx“, key = “#results.![a+b]“,multi = true)是什么意思
  • @serverendpoint注解_SpringBoot 使用WebSocket打造在线聊天室(基于注解)
  • @synthesize和@dynamic分别有什么作用?
  • []指针
  • [2008][note]腔内级联拉曼发射的,二极管泵浦多频调Q laser——
  • [Android]常见的数据传递方式
  • [C#]C# winform实现imagecaption图像生成描述图文描述生成
  • [CSS]浮动
  • [DevOps云实践] 彻底删除AWS云资源
  • [docker]docker网络-直接路由模式
  • [HeadFrist-HTMLCSS学习笔记][第一章Web语言:开始了解HTML]
  • [Java] 什么是IoC?什么是DI?它们的区别是什么?
  • [LeetCode] 2.两数相加
  • [LeetCode]剑指 Offer 40. 最小的k个数
  • [MicroPython]TPYBoard v102 CAN总线通信
  • [Nginx]反向代理Node将3000端口访问转换成80端口
  • [NHibernate]一对多关系(关联查询)