SPI + JDK 9 + module-info.java
Я экспериментирую с SPI на JDK 9. Весь пример работает на JDK 9 без "module-info.java". После добавления "module-info.java" ServiceLocator не находит реализующий класс. Я запутался и не могу найти работающий пример SPI в модульном проекте JDK 9.
Итак, мой пример проекта выглядит так:
/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:
module eu.com.example.applicationB {
requires eu.com.example.apiModule;
requires transitive eu.com.example.applicationCommon;
uses eu.com.example.text.spi.TextAPI;
}
Содержимое /implementationB/src/main/java/module-info.java:
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
Я пытался изменить имена пакетов, как предлоги ошибок компиляции, но затем я ввел проблемы "разделенного пакета".
Что я должен сделать, чтобы использовать ServiceLocator в полностью модульном JDK 9? Является ли это возможным? Кто-нибудь видел рабочий пример? Код также можно увидеть здесь: https://github.com/RadoslawOsinski/spidemo
2 ответа
Вы можете перейти на использование:-
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;
Службы в документе предоставляют образец вокруг реализации.
Модуль может указывать, что он предоставляет услугу с определенным типом поставщиков услуг. Заявлено использование и
with
ключевое слово.
синтаксис: предоставляет serviceType с implementationTypes;
(Можно указать несколько типов реализаций в виде списка, разделенного запятыми)
Поэтому в ваш модуль следует добавить следующую инструкцию.
provides eu.com.example.implb.text.TextB with eu.com.example.text.spi.TextAPI;
ПРИМЕЧАНИЕ :
provides
не равно
exports
. Итак, любые другие модули, требующие
eu.com.example.implb.text
не будет иметь доступа
eu.com.example.implb.text.TextB
если не экспортирует.