简单的Java“服务提供者框架”?

时间:2009-07-17 18:23:36

标签: java factory service-provider

我指的是Chapter 2 of Effective Java中讨论的“服务提供者框架”,这似乎是处理我遇到的问题的正确方法,我需要在运行时实例化几个类中的一个,基于String选择哪个服务和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;
     }
 }

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

2 个答案:

答案 0 :(得分: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);
}

答案 1 :(得分:1)

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

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

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