SPI + JDK 9 + module-info.java

问题描述:

我正在用JDK 9上的SPI进行试验。整个示例在没有“module-info.java”的JDK 9上运行。在添加“module-info.java”之后,ServiceLocator没有找到实现类。我很困惑,在模块化的JDK 9项目中我找不到工作的SPI示例。SPI + JDK 9 + module-info.java

所以我的示例项目看起来是这样的:

/spidemo 
├── apiModule 
│   ├── pom.xml 
│   └── src 
│    └── main 
│     └── java 
│      ├── eu 
│      │   └── com 
│      │    └── example 
│      │     └── text 
│      │      └── spi 
│      │       └── TextAPI.java 
│      └── module-info.java 
├── applicationB 
│   ├── pom.xml 
│   └── src 
│    └── main 
│     ├── java 
│     │   └── eu 
│     │    └── com 
│     │     └── example 
│     │      └── spi 
│     │       └── b 
│     │        └── application 
│     │         └── DemoB.java 
│     └── module-info.java 
├── applicationCommon 
│   ├── pom.xml 
│   └── src 
│    └── main 
│     └── java 
│      ├── eu 
│      │   └── com 
│      │    └── example 
│      │     └── spi 
│      │      └── application 
│      │       └── TextAPIProvider.java 
│      └── module-info.java 
├── implementationB 
│   ├── pom.xml 
│   └── src 
│    └── main 
│     ├── java 
│     │   └── eu 
│     │    └── com 
│     │     └── example 
│     │      └── implb 
│     │       └── text 
│     │        └── TextB.java 
│     ├── module-info.java 
│     └── resources 
│      └── META-INF 
│       └── services 
│        └── eu.com.example.text.spi.TextAPI 

我已经介绍了接口:

package eu.com.example.text.spi; 
public interface TextAPI { 
    String getHelloWorldText(); 
} 

此接口实现:

package eu.com.example.implb.text; 
import eu.com.example.text.spi.TextAPI; 
public class TextB implements TextAPI { 
    public String getHelloWorldText() { 
     return "Text from B implementation"; 
    } 
} 

的实现是通过代码搜索相似地:

package eu.com.example.spi.application; 
import eu.com.example.text.spi.DefaultTextAPI; 
import eu.com.example.text.spi.TextAPI; 
import java.util.ServiceLoader; 
public class TextAPIProvider { 

    public static TextAPI getProvider(String providerName) { 
     ServiceLoader<TextAPI> serviceLoader = ServiceLoader.load(TextAPI.class); 
     for (TextAPI provider : serviceLoader) { 
      String className = provider.getClass().getName(); 
      if (providerName.equals(className)) { 
       return provider; 
      } 
     } 
     throw new RuntimeException(providerName + " provider is not found!"); 
    } 
} 

现在是有趣的部分。当我执行下面类无:

  • /implementationB/src/main/java/module-info.java
  • /applicationB/src/main/java/module-info.java

然后找到实现类并打印出文本。

package eu.com.example.spi.b.application; 
import eu.com.example.spi.application.TextAPIProvider; 
public class DemoB { 
    public static void main(String[] args) { 
     System.out.println("---> " + TextAPIProvider.getProvider("eu.com.example.implb.text.TextB").getHelloWorldText()); 
    } 
} 

介绍这个两个“module-info.java”文件实现类后不被发现的ServiceLocator。 内容/applicationB/src/main/java/module-info.java的:/implementationB/src/main/java/module-info.java的

module eu.com.example.applicationB { 
    requires eu.com.example.apiModule; 
    requires transitive eu.com.example.applicationCommon; 
    uses eu.com.example.text.spi.TextAPI; 
} 

内容:

module eu.com.example.implb.text { 
    requires eu.com.example.apiModule; 
    exports eu.com.example.implb.text; 
// provides eu.com.example.implb.text.TextB with eu.com.example.text.spi.TextAPI; 
} 

当我取消:

provides eu.com.example.implb.text.TextB with eu.com.example.text.spi.TextAPI; 

线则发生编译错误:

.../implementationB/src/main/java/module-info.java:[7,74] the service implementation type must be a subtype of the service interface type, or have a public static no-args method named "provider" returning the service implementation 
.../implementationB/src/main/java/module-info.java:[7,5] service implementation must be defined in the same module as the provides directive 

我试图将软件包名称更改为编译错误摘要,但后来我引入了“拆分软件包”问题。

我该怎么做才能在完全模块化的JDK 9中使用ServiceLocator?可能吗?有没有人看过工作的例子? 代码也可以在这里看到:https://github.com/RadoslawOsinski/spidemo

+3

我假设你打算增加'eu.com.example.text.spi.TextAPI和eu.com.example.implb.text。TextB“作为TextB是实现(而不是服务类型)。 –

+0

非常感谢!我花了几个小时在这个错字。这解决了我的问题。 –

您可以更改使用: -

provides eu.com.example.text.spi.TextAPI with eu.com.example.implb.text.TextB; 
// you provide a service through its implementation 

,而不是

provides eu.com.example.implb.text.TextB with eu.com.example.text.spi.TextAPI; 

Services文档中提供了围绕实施样本。