SpiUtil
SpiUtil是Hutool中用于处理SPI(Service Provider Interface)的核心工具类,提供了丰富的服务加载和管理功能,简化了Java SPI的使用。
# 主要功能
- 服务加载:加载指定接口的实现类
- 服务缓存:缓存加载的服务,提高性能
- 服务排序:支持服务的优先级排序
- 服务分组:支持服务的分组管理
- 服务实例化:实例化加载的服务
- 服务获取:获取指定的服务
# 服务加载
# loadList(serviceClass)
加载指定接口的所有实现类到列表中。
// 加载HelloService的所有实现类
List<HelloService> services = SpiUtil.loadList(HelloService.class);
for (HelloService service : services) {
Console.log(service.sayHello("Hutool"));
}
// 输出:
// Hello, Hutool from ServiceImpl1
// Hello, Hutool from ServiceImpl2
# loadList(serviceClass, comparator)
加载指定接口的所有实现类,并按照指定的比较器排序。
// 按优先级加载HelloService的所有实现类(优先级高的先加载)
List<HelloService> servicesByPriority = SpiUtil.loadList(HelloService.class,
(o1, o2) -> Integer.compare(o2.getPriority(), o1.getPriority()));
for (HelloService service : servicesByPriority) {
Console.log(service.sayHello("Hutool"));
}
// 输出:
// Hello, Hutool from ServiceImpl2
// Hello, Hutool from ServiceImpl1
# loadMap(serviceClass)
加载指定接口的所有实现类到Map中,键为实现类的类名,值为实现类的实例。
// 加载HelloService的所有实现类到Map中
Map<String, HelloService> serviceMap = SpiUtil.loadMap(HelloService.class);
for (Map.Entry<String, HelloService> entry : serviceMap.entrySet()) {
Console.log(entry.getKey() + ": " + entry.getValue().sayHello("Hutool"));
}
// 输出:
// cn.hutool.demo.service.HelloServiceImpl1: Hello, Hutool from ServiceImpl1
// cn.hutool.demo.service.HelloServiceImpl2: Hello, Hutool from ServiceImpl2
# loadMap(serviceClass, keyFunc)
加载指定接口的所有实现类到Map中,键由指定的函数生成,值为实现类的实例。
// 加载HelloService的所有实现类到Map中,键为实现类的优先级
Map<String, HelloService> serviceMap = SpiUtil.loadMap(HelloService.class, service -> String.valueOf(service.getPriority()));
for (Map.Entry<String, HelloService> entry : serviceMap.entrySet()) {
Console.log(entry.getKey() + ": " + entry.getValue().sayHello("Hutool"));
}
// 输出:
// 1: Hello, Hutool from ServiceImpl1
// 2: Hello, Hutool from ServiceImpl2
# 服务实例化
# newInstance(serviceClass)
实例化指定接口的默认实现类。
// 实例化HelloService的默认实现类
HelloService service = SpiUtil.newInstance(HelloService.class);
Console.log(service.sayHello("Hutool"));
// 输出: Hello, Hutool from ServiceImpl1
# newInstance(serviceClass, serviceName)
实例化指定接口的指定实现类。
// 实例化HelloService的HelloServiceImpl2实现类
HelloService service = SpiUtil.newInstance(HelloService.class, "cn.hutool.demo.service.HelloServiceImpl2");
Console.log(service.sayHello("Hutool"));
// 输出: Hello, Hutool from ServiceImpl2
# 服务获取
# getService(serviceClass)
获取指定接口的默认实现类。
// 获取HelloService的默认实现类
HelloService service = SpiUtil.getService(HelloService.class);
Console.log(service.sayHello("Hutool"));
// 输出: Hello, Hutool from ServiceImpl1
# getService(serviceClass, serviceName)
获取指定接口的指定实现类。
// 获取HelloService的HelloServiceImpl2实现类
HelloService service = SpiUtil.getService(HelloService.class, "cn.hutool.demo.service.HelloServiceImpl2");
Console.log(service.sayHello("Hutool"));
// 输出: Hello, Hutool from ServiceImpl2
# 服务缓存
SpiUtil内置了服务缓存机制,会缓存加载的服务,提高性能。缓存会在首次调用时自动创建,后续调用会直接从缓存中获取,避免重复的服务加载。
// 第一次调用,会加载服务并缓存
List<HelloService> services1 = SpiUtil.loadList(HelloService.class);
// 第二次调用,会直接从缓存中获取
List<HelloService> services2 = SpiUtil.loadList(HelloService.class);
# clearCache()
清除所有服务缓存。
// 清除所有服务缓存
SpiUtil.clearCache();
# clearCache(serviceClass)
清除指定接口的服务缓存。
// 清除HelloService的服务缓存
SpiUtil.clearCache(HelloService.class);
# 服务加载器获取
# getServiceLoader(serviceClass)
获取指定接口的服务加载器。
// 获取HelloService的服务加载器
ServiceLoader<HelloService> serviceLoader = SpiUtil.getServiceLoader(HelloService.class);
# getListServiceLoader(serviceClass)
获取指定接口的列表服务加载器。
// 获取HelloService的列表服务加载器
ListServiceLoader<HelloService> listServiceLoader = SpiUtil.getListServiceLoader(HelloService.class);
List<HelloService> services = listServiceLoader.load();
# getMapServiceLoader(serviceClass)
获取指定接口的Map服务加载器。
// 获取HelloService的Map服务加载器
MapServiceLoader<HelloService> mapServiceLoader = SpiUtil.getMapServiceLoader(HelloService.class);
Map<String, HelloService> serviceMap = mapServiceLoader.load();
# 注意事项
- 服务注册:需要在META-INF/services目录下创建配置文件,文件名为接口的全限定名,文件内容为实现类的全限定名
- 服务实例化:服务实现类需要有公共的无参构造器,否则无法实例化
- 服务缓存:服务缓存会在首次调用时自动创建,后续调用会直接从缓存中获取
- 服务排序:可以通过比较器对加载的服务进行排序
- 服务分组:可以通过函数将加载的服务分组到Map中
- 异常处理:SpiUtil将checked异常转换为runtime异常,避免繁琐的try-catch
# 总结
SpiUtil提供了丰富的SPI操作功能,涵盖了服务加载、实例化、获取、缓存等多个方面。通过使用SpiUtil,可以大大简化Java中的SPI操作,提高开发效率。
无论是插件化开发、框架扩展还是服务发现,SpiUtil都能提供简洁高效的解决方案。其内置的服务缓存机制也提高了SPI操作的性能,适合在高并发场景下使用。