corejava11(6.4 服务装载机)

6.4 服务装载机

有时,您使用服务体系结构开发应用程序。有些平台鼓励使用这种方法,例如OSGi(http://osgi.org),它用于开发环境、应用程序服务器和其他复杂的应用程序。这样的平台远远超出了本书的范围,但是JDK还提供了一个加载服务的简单机制,我们在这里描述。Java平台模块系统很好地支持了这个机制,参见第二卷第9章。

通常,在提供服务时,程序希望给服务设计者一些自由,让他们知道如何实现服务的特性。还需要从多个实现中进行选择。ServiceLoader类使加载符合公共接口的服务变得容易。

使用每个服务实例应该提供的方法定义接口(或者,如果您愿意,定义一个超类)。例如,假设您的服务提供加密。

package serviceLoader;
public interface Cipher
{
    byte[] encrypt(byte[] source, byte[] key);
    byte[] decrypt(byte[] source, byte[] key);
    int strength();
}

例如,服务提供者提供一个或多个实现此服务的类

package serviceLoader.impl;
public class CaesarCipher implements Cipher
{
    public byte[] encrypt(byte[] source, byte[] key)
    {
        var result = new byte[source.length];
        for (int i = 0; i < source.length; i++)
            result[i] = (byte)(source[i] + key[0]);
        return result;
    }
    public byte[] decrypt(byte[] source, byte[] key)
    {
        return encrypt(source, new byte[] { (byte) - key[0] });
    }
    public int strength() { return 1; }
}

实现类可以在任何包中,不一定与服务接口在同一包中。它们中的每一个都必须有一个无参数构造函数。

现在,将类的名称添加到META-INF/services目录中的一个文件中的UTF-8编码文本文件中,该文件的名称与完全限定的类名匹配。在我们的示例中,文件META-INF/services/serviceLoader.Cipher将包含

serviceLoader.impl.CaesarCipher

在这个例子中,我们提供了一个实现类。您还可以提供多个类,稍后在其中进行选择。

完成此准备后,程序将按如下方式初始化服务加载程序:

public static ServiceLoader<Cipher> cipherLoader = ServiceLoader.load(Cipher.class);

这应该在程序中只执行一次。

服务加载程序的iterator方法通过提供的所有服务实现返回迭代器。(有关迭代器的更多信息,请参见第9章。)最容易使用增强的for循环遍历它们。在循环中,选择适当的对象来执行服务。

public static Cipher getCipher(int minStrength)
{
    for (Cipher cipher : cipherLoader) // implicitly calls cipherLoad
    {
        if (cipher.strength() >= minStrength) return cipher;
    }
    return null;
}

或者,您可以使用流(参见第二卷第1章)来定位所需的服务。流方法生成ServiceLoader.Provider实例流。该接口具有用于获取提供程序类和提供程序实例的方法typeget。如果您按类型选择一个提供者,那么您只需要调用type,而不需要实例化任何服务实例。

public static Optional<Cipher> getCipher2(int minStrength)
{
    return cipherLoader.stream()
        .filter(descr -> descr.type() == serviceLoader.impl.CaesarCipher.class)
        .findFirst()
        .map(ServiceLoader.Provider::get);
}

最后,如果您愿意使用任何服务实例,只需调用findFirst

Optional<Cipher> cipher = cipherLoader.findFirst();

Optional类将在第二卷第一章解释。

java.util.ServiceLoader<S> 1.6

  • static <S> ServiceLoader<S> load(Class<S> service)
    创建用于加载实现给定服务接口的类的服务加载程序。
  • Iterator<S> iterator()
    生成一个延迟加载服务类的迭代器。也就是说,每当迭代器前进时都会加载一个类。
  • Stream<ServiceLoader.Provider<S>> stream() 9
    返回提供程序描述符流,以便可以延迟加载所需类的提供程序。
  • Optional<S> findFirst() 9
    查找第一个可用的服务提供程序(如果有)。

java.util.ServiceLoader.Provider<S> 9

  • Class<? extends S> type()
    获取此提供程序的类型。
  • S get()
    获取此提供程序的实例。

猜你喜欢

转载自blog.csdn.net/nbda1121440/article/details/91351362
今日推荐