我的项目中有一个接口。
最终用户可以实现此接口并可以创建他们的具体实现。
建议所有用户在创建实现时遵循单例设计模式。
用户将实现存储在属性文件中。
我使用Java Reflection来加载类,如下所示。
上述方法对性能来说非常糟糕,因此出于各种原因我决定将加载部分移至Java ServiceLoader。
但是,ServiceLoader 需要一个公共的无参数构造函数来加载类,这是一个相当大的障碍。
有没有办法使用带有私有构造函数的 Java ServiceLoader 来实现类加载,或者我可以使用公共无参数构造函数使单例实现安全吗?
我已阅读文档,并用谷歌搜索了可能的解决方案,但没有发现任何实质性内容。
现在如何加载类:
Class klass = Class.forName(klassName);
Method method = klass.getDeclaredMethod("getInstance");
Object object = method.invoke(null);
我只是想摆脱这个属性文件并转向 Java ServiceLoader,就像我转向其他非单例类一样。
您至少可以使用几种不同的方法。
最好的解决方案可能是确保您自己只加载提供程序的单个实例。这减轻了提供商实施的责任。
public final class ServiceRegistry {
private static List<Service> services;
public static synchronized List<Service> getServices() {
if (services == null) {
// The 'stream()' method and 'ServiceLoader.Provider` interface were
// added in Java 9. On older versions you can use the 'iterator()` method
// to do something similar.
services = ServiceLoader.load(Service.class).stream()
.map(ServiceLoader.Provider::get)
.toList(); // 'Stream::toList()' added in Java 16
}
return services;
}
private ServiceRegistry() {}
}
然后您可以将这些
Service
实例传递到您需要它们的任何地方。
另一种选择是通过使服务成为工厂来使用某种间接方式。
public interface ServiceFactory {
Service getSingletonInstance();
}
您将加载为:
static List<Service> getServices() {
// The 'stream()' method and 'ServiceLoader.Provider` interface were
// added in Java 9. On older versions you can use the 'iterator()` method
// to do something similar.
return ServiceLoader.load(ServiceFactory.class).stream()
.map(ServiceLoader.Provider::get)
.map(ServiceFactory::getSingletonInstance)
.toList(); // 'Stream::toList()' added in Java 16
}
可以创建任意数量的
ServiceFactory
实例。这是工厂的实现,负责每次返回相同的 Service
实例。
如果在 Java 9+ 上并且提供程序部署在非自动模块中,那么这些提供程序可以定义一个名为
provider
的静态无参数方法。
package com.example.provider;
import com.example.spi.Service;
public class Provider implements Service {
// can make creating the instance lazy if you want
private static final Provider INSTANCE = new Provider();
// return type must be assignable to Service
public static Provider provider() {
return INSTANCE;
}
// ... service methods ...
}
模块描述符:
module provider {
provides com.example.spi.Service with
com.example.provider.Provider;
}