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

我指的是有效Java第2章中讨论的“服务提供者框架”,这似乎是处理我遇到的问题的正确方法,我需要在运行时基于要选择的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 directory = new HashMap(); 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( )他们想要使用的每个class级?

我认为你需要创建一个META-INF / services / fully.qualified.ClassName并在那里列出东西,但我不记得规范( JAR文件规范或者这个 )。

Java架构师第8章的实用API设计附件是关于SPI的。

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

 ServiceLoader loader = ServiceLoader.load(PersistenceProvider.class); Iterator implementations = loader.iterator(); while(implementations.hasNext()) { PersistenceProvider implementation = implementations.next(); logger.info("PersistenceProvider implementation: " + implementation); } 

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

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

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