SPI + 工厂设计模式
1. 什么是 SPI ?有什么用? SPI(Service Provider Interface)是Java提供的一种用于实现可扩展性和插件机制的接口规范。它允许开发者定义或使用服务提供者(Service Providers),并且可以在运行时动态地加载这些服务,而不需要在编译时将服务的实现绑定到应用程序中。这种机制特别适合那些需要根据配置或条件加载不同服务实现的场景,例如数据库驱动、加密算法等。 1.1. SPI 的核心概念: 服务接口(Service Interface):定义服务提供者需要实现的接口。例如,java.sql.Driver就是一个常见的服务接口,所有的数据库驱动都必须实现这个接口。 服务提供者(Service Provider):服务接口的具体实现。例如,不同数据库厂商的驱动程序就是服务提供者。 服务加载器(Service Loader):用于发现和加载服务提供者的机制。Java 提供了 java.util.ServiceLoader 来查找服务提供者。 配置文件:SPI 使用一个特殊的配置文件来声明服务提供者的实现类。配置文件放置在 META-INF/services/ 目录下,文件名为服务接口的全限定名,文件内容为实现类的全限定名。例如,META-INF/services/java.sql.Driver 这个文件可能包含多个 JDBC 驱动实现类。 1.2. SPI的工作原理: 应用程序通过 ServiceLoader 查找指定服务接口的实现。 JVM在 META-INF/services/ 目录下查找对应的服务配置文件。 服务加载器解析配置文件并实例化指定的服务提供者类。 2. 实现 具体实现方法如下: 指定 SPI 的配置目录,并且将配置再分为系统内置 SPI 和用户自定义 SPI,便于区分优先级和维护。 编写 SpiLoader 加载器,实现读取配置、加载实现类的方法。 用 Map 来存储已加载的配置信息 键名 => 实现类。 通过 Hutool 工具库提供的 ResourceUtil.getResources 扫描指定路径,读取每个配置文件,获取到 键名 => 实现类 信息并存储在 Map 中。 定义获取实例方法,根据用户传入的接口和键名,从 Map 中找到对应的实现类,然后通过反射获取到实现类对象。可以维护一个对象实例缓存,创建过一次的对象从缓存中读取即可。 重构序列化器工厂,改为从 SPI 加载指定的序列化器对象。 使用静态代码块调用 SPI 的加载方法,在工厂首次加载时,就会调用 SpiLoader 的 load 方法加载序列化器接口的所有实现类,之后就可以通过调用 getInstance 方法获取指定的实现类对象了。 ...