使用 Java ServiceLoader 加载类的单例实例

问题描述 投票:0回答:1
  1. 我的项目中有一个接口。

  2. 最终用户可以实现此接口并可以创建他们的具体实现。

  3. 建议所有用户在创建实现时遵循单例设计模式。

  4. 用户将实现存储在属性文件中。

  5. 我使用Java Reflection来加载类,如下所示。

  6. 上述方法对性能来说非常糟糕,因此出于各种原因我决定将加载部分移至Java ServiceLoader。

  7. 但是,ServiceLoader 需要一个公共的无参数构造函数来加载类,这是一个相当大的障碍。

  8. 有没有办法使用带有私有构造函数的 Java ServiceLoader 来实现类加载,或者我可以使用公共无参数构造函数使单例实现安全吗?

我已阅读文档,并用谷歌搜索了可能的解决方案,但没有发现任何实质性内容。

现在如何加载类:

Class klass = Class.forName(klassName);
Method method = klass.getDeclaredMethod("getInstance");
Object object = method.invoke(null);

我只是想摆脱这个属性文件并转向 Java ServiceLoader,就像我转向其他非单例类一样。

java singleton classloader serviceloader
1个回答
0
投票

您至少可以使用几种不同的方法。

仅加载一个Provider实例

最好的解决方案可能是确保您自己只加载提供程序的单个实例。这减轻了提供商实施的责任。

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;
}
© www.soinside.com 2019 - 2024. All rights reserved.