java的SPI机制
参考https://blog.csdn.net/qq_52423918/article/details/130968307
1 概念
Java SPI(Service Provider Interface)是Java官方提供的一种服务发现机制,它允许在运行时动态地加载实现特定接口的类,而不需要在代码中显式地指定该类,从而实现解耦和灵活性。
2 实现原理
Java SPI 的实现原理基于 Java 类加载机制和反射机制。
这里会用到java.util.ServiceLoader类加载器。当使用 ServiceLoader.load(Class<T> service) 方法加载服务时,会检查 META-INF/services 目录下是否存在以接口全限定名命名的文件。如果存在,则读取文件内容,获取实现该接口的类的全限定名,并通过 Class.forName() 方法加载对应的类。
在加载类之后,ServiceLoader 会通过反射机制创建对应类的实例,并将其缓存起来。
这里涉及到一个懒加载迭代器的思想:当我们调用 ServiceLoader.load(Class<T> service) 方法时,并不会立即将所有实现了该接口的类都加载进来,而是返回一个懒加载迭代器。
只有在使用迭代器遍历时,才会按需加载对应的类并创建其实例。
3 例子
服务接口ProgrammingLanguageService
public interface ProgrammingLanguageService { void study(); }
两个实现类
public class JavaServiceImpl implements ProgrammingLanguageService { @Override public void study() { System.out.println("开始学习java"); } }
和
public class PythonServiceImpl implements ProgrammingLanguageService { @Override public void study() { System.out.println("开始学习python"); } }
创建META-INF/services路径和com.demo.szj.ProgrammingLanguageService文件,内容
com.demo.szj.JavaServiceImpl
com.demo.szj.PythonServiceImpl
启动类
public class ServiceLoaderTest { public static void main(String[] args) { ServiceLoader<ProgrammingLanguageService> serviceLoader = ServiceLoader.load(ProgrammingLanguageService.class); Iterator<ProgrammingLanguageService> iterator = serviceLoader.iterator(); while(iterator.hasNext()) { ProgrammingLanguageService service = iterator.next(); service.study(); } } }
执行结果
我们看到,虽然我们没有创建这两个服务类,但是通过SPI机制,可以成功创建其实例。