【问题标题】:Simple Java "Service Provider frameworks"?简单的Java“服务提供者框架”?
【发布时间】:2010-11-11 19:24:39
【问题描述】:

我指的是Chapter 2 of Effective Java 中讨论的“服务提供者框架”,这似乎正是处理我遇到的问题的正确方法,我需要在运行时基于@987654322 实例化几个类之一@ 选择哪个服务,以及一个Configuration 对象(本质上是一个 XML sn-p):

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

 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()对于他们想要使用的每个类?

【问题讨论】:

    标签: java factory service-provider


    【解决方案1】:

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

    Java 架构师的实用 API 设计自白一书第 8 章是关于 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);
    }
    

    【讨论】:

    • 作为脚注:这需要 Java6
    • 有趣:所以答案似乎是有一个 JAR 文件机制用于包含服务提供者配置文件,+ 用于实例化它们的各种类/方法(例如 java.util.ServiceLoader)
    • @Jason S:是的,但我以前从未使用过它。
    【解决方案2】:

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

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

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

    【讨论】:

    • 但是你需要在某个地方显式地引用你的类来初始化它。或者,您可以在运行时找到自己的 jar 文件并遍历它以查找名称中带有 *Provider 和 Class.forName 的类。丑陋。
    猜你喜欢
    • 2017-03-05
    • 2011-04-25
    • 1970-01-01
    • 2023-03-28
    • 2018-07-23
    • 2012-08-07
    • 1970-01-01
    • 2013-11-03
    • 1970-01-01
    相关资源
    最近更新 更多