5

我指的是 Effective Java 第 2 章中讨论的“服务提供者框架” ,这似乎正是处理我遇到的问题的正确方法,我需要在运行时实例化几个类中的一个,基于 aString来选择哪个服务和一个Configuration对象(本质上是一个 XML 片段):

但是我如何让各个服务提供者(例如一堆默认提供者+一些自定义提供者)注册自己?

 interface FooAlgorithm
 {
     /* methods particular to this class of algorithms */
 }

 interface FooAlgorithmProvider
 {
     public FooAlgorithm getAlgorithm(Configuration c);
 }

 class FooAlgorithmRegistry
 {
     private FooAlgorithmRegistry() {}
     static private final Map<String, FooAlgorithmProvider> directory =
        new HashMap<String, FooAlgorithmProvider>();
     static public FooAlgorithmProvider getProvider(String name)
     {
         return directory.get(serviceName);
     }
     static public boolean registerProvider(String name, 
         FooAlgorithmProvider provider)
     {
         if (directory.containsKey(name))
            return false;
         directory.put(name, provider);
         return true;
     }
 }

例如,如果我编写自定义类 MyFooAlgorithm 和 MyFooAlgorithmProvider 来实现 FooAlgorithm,并将它们分发到一个 jar 中,有没有办法让 registerProvider 被自动调用,或者我使用该算法的客户端程序必须显式调用 FooAlgorithmRegistry.registerProvider( ) 对于他们想要使用的每个类?

4

2 回答 2

10

我认为您需要创建一个 META-INF/services/fully.qualified.ClassName 并在其中列出内容,但我不记得规范(JAR File Specificationthis)。

Java 架构师书籍第 8 章的实用 API 设计自白是关于 SPI 的。

ServiceLoader 可能会帮助您列出可用的实现。例如使用 PersistenceProvider 接口:

ServiceLoader<PersistenceProvider> loader = 
        ServiceLoader.load(PersistenceProvider.class);
Iterator<PersistenceProvider> implementations = loader.iterator();
while(implementations.hasNext()) {
    PersistenceProvider implementation = implementations.next();
    logger.info("PersistenceProvider implementation: " + implementation);
}
于 2009-07-17T18:34:09.650 回答
1

您可以让客户端 JAR 在您知道之前会调用的某个类中的静态初始化程序块中注册提供程序FooAlgorithmRegistry.getProvider(),例如:

static {
    FooAlgorithmRegistry.registerProvider("test", new MyFooAlgorithmProvider());
}

但是,可能很难找到一种方法来保证它会在工厂的访问器方法之前运行(静态初始化程序保证在第一次加载类时只运行一次)。

于 2009-07-17T18:44:38.363 回答