Java 依赖注入的模块化
Java Modularity with Dependency Injection
让我们假设一个基于 OpenJDK 11 + OpenJFX 11 的应用程序。代码库组织在单个 java 模块中(请参阅 A Guide to Java 9 Modularity 以供参考)。
到目前为止,我将所有基于 JavaFX 的项目与 Google 的依赖注入框架 Guice 结合在一起。对于模块化项目,这似乎不起作用...
SQLiteCompassApplication.java
public class SQLiteCompassApplication extends Application {
public static void main(String[] args) {
launch(args);
}
public void start(Stage stage) throws Exception {
Injector injector = Guice.createInjector(new MyModule());
FXMLLoader fxmlLoader = injector.getInstance(FXMLLoader.class);
try(InputStream fxmlStream = getClass().getResourceAsStream("/view/View.fxml")) {
Parent root = fxmlLoader.load(fxmlStream);
stage.setScene(new Scene(root));
stage.setTitle("SQLite Compass");
stage.setOnCloseRequest(event -> System.exit(0));
stage.show();
}
}
}
模块-info.java
module org.x1c1b.sqlitecompass {
requires javafx.controls;
requires javafx.fxml;
requires com.google.guice;
exports org.x1c1b.sqlitecompass;
}
为了简单起见 Guice 配置,这意味着声明的 Guice 模块(not 与 java 模块混淆),未粘贴但仍适用于非模块化项目。
执行此代码时,我收到以下异常:
Caused by: java.lang.reflect.InaccessibleObjectException: Unable to make field com.google.inject.Injector org.x1c1b.sqlitecompass.config.provider.FXMLLoaderProvider.injector accessible: module org.x1c1b.sqlitecompass does not "opens org.x1c1b.sqlitecompass.config.provider" to module com.google.guice
at java.base/java.lang.reflect.AccessibleObject.checkCanSetAccessible(AccessibleObject.java:340)
at java.base/java.lang.reflect.AccessibleObject.checkCanSetAccessible(AccessibleObject.java:280)
at java.base/java.lang.reflect.Field.checkCanSetAccessible(Field.java:176)
at java.base/java.lang.reflect.Field.setAccessible(Field.java:170)
at com.google.guice@4.2.2/com.google.inject.internal.SingleFieldInjector.<init>(SingleFieldInjector.java:38)
at com.google.guice@4.2.2/com.google.inject.internal.MembersInjectorStore.getInjectors(MembersInjectorStore.java:126)
at com.google.guice@4.2.2/com.google.inject.internal.MembersInjectorStore.createWithListeners(MembersInjectorStore.java:93)
at com.google.guice@4.2.2/com.google.inject.internal.MembersInjectorStore.access[=13=]0(MembersInjectorStore.java:36)
at com.google.guice@4.2.2/com.google.inject.internal.MembersInjectorStore.create(MembersInjectorStore.java:45)
at com.google.guice@4.2.2/com.google.inject.internal.MembersInjectorStore.create(MembersInjectorStore.java:41)
at com.google.guice@4.2.2/com.google.inject.internal.FailableCache.load(FailableCache.java:40)
at com.google.common@25.1-android/com.google.common.cache.LocalCache$LoadingValueReference.loadFuture(LocalCache.java:3444)
at com.google.common@25.1-android/com.google.common.cache.LocalCache$Segment.loadSync(LocalCache.java:2193)
at com.google.common@25.1-android/com.google.common.cache.LocalCache$Segment.lockedGetOrLoad(LocalCache.java:2152)
at com.google.common@25.1-android/com.google.common.cache.LocalCache$Segment.get(LocalCache.java:2042)
... 39 more
Exception running application org.x1c1b.sqlitecompass.SQLiteCompassApplication
我可以通过将 opens org.x1c1b.sqlitecompass.config.provider;
粘贴到 module-info.java
来解决这个问题。但这会导致进一步的异常...
一般情况下,我应该如何配置我的模块/module-info.java
以便与 Google Guice 一起使用?是否可以结合使用 Google Guice 和 Modularity?
编辑
当我更改以下行时它似乎起作用了:
- 将声明我的 Guice 模块的
exports org.x1c1b.sqlitecompass.config
添加到 module-info.java
- 使用附加的 VM 选项执行程序
--add-opens java.base/java.lang=com.google.guice
但我猜它更多的是找到的解决方法 here 而不是官方解决方案...
您必须打开所有将由 Guice 通过反射访问的包。
最简单的方法是通过将这个词放在 module-info.java
.
中的 module
前面,将整个模块声明为 open
让我们假设一个基于 OpenJDK 11 + OpenJFX 11 的应用程序。代码库组织在单个 java 模块中(请参阅 A Guide to Java 9 Modularity 以供参考)。
到目前为止,我将所有基于 JavaFX 的项目与 Google 的依赖注入框架 Guice 结合在一起。对于模块化项目,这似乎不起作用...
SQLiteCompassApplication.java
public class SQLiteCompassApplication extends Application {
public static void main(String[] args) {
launch(args);
}
public void start(Stage stage) throws Exception {
Injector injector = Guice.createInjector(new MyModule());
FXMLLoader fxmlLoader = injector.getInstance(FXMLLoader.class);
try(InputStream fxmlStream = getClass().getResourceAsStream("/view/View.fxml")) {
Parent root = fxmlLoader.load(fxmlStream);
stage.setScene(new Scene(root));
stage.setTitle("SQLite Compass");
stage.setOnCloseRequest(event -> System.exit(0));
stage.show();
}
}
}
模块-info.java
module org.x1c1b.sqlitecompass {
requires javafx.controls;
requires javafx.fxml;
requires com.google.guice;
exports org.x1c1b.sqlitecompass;
}
为了简单起见 Guice 配置,这意味着声明的 Guice 模块(not 与 java 模块混淆),未粘贴但仍适用于非模块化项目。
执行此代码时,我收到以下异常:
Caused by: java.lang.reflect.InaccessibleObjectException: Unable to make field com.google.inject.Injector org.x1c1b.sqlitecompass.config.provider.FXMLLoaderProvider.injector accessible: module org.x1c1b.sqlitecompass does not "opens org.x1c1b.sqlitecompass.config.provider" to module com.google.guice
at java.base/java.lang.reflect.AccessibleObject.checkCanSetAccessible(AccessibleObject.java:340)
at java.base/java.lang.reflect.AccessibleObject.checkCanSetAccessible(AccessibleObject.java:280)
at java.base/java.lang.reflect.Field.checkCanSetAccessible(Field.java:176)
at java.base/java.lang.reflect.Field.setAccessible(Field.java:170)
at com.google.guice@4.2.2/com.google.inject.internal.SingleFieldInjector.<init>(SingleFieldInjector.java:38)
at com.google.guice@4.2.2/com.google.inject.internal.MembersInjectorStore.getInjectors(MembersInjectorStore.java:126)
at com.google.guice@4.2.2/com.google.inject.internal.MembersInjectorStore.createWithListeners(MembersInjectorStore.java:93)
at com.google.guice@4.2.2/com.google.inject.internal.MembersInjectorStore.access[=13=]0(MembersInjectorStore.java:36)
at com.google.guice@4.2.2/com.google.inject.internal.MembersInjectorStore.create(MembersInjectorStore.java:45)
at com.google.guice@4.2.2/com.google.inject.internal.MembersInjectorStore.create(MembersInjectorStore.java:41)
at com.google.guice@4.2.2/com.google.inject.internal.FailableCache.load(FailableCache.java:40)
at com.google.common@25.1-android/com.google.common.cache.LocalCache$LoadingValueReference.loadFuture(LocalCache.java:3444)
at com.google.common@25.1-android/com.google.common.cache.LocalCache$Segment.loadSync(LocalCache.java:2193)
at com.google.common@25.1-android/com.google.common.cache.LocalCache$Segment.lockedGetOrLoad(LocalCache.java:2152)
at com.google.common@25.1-android/com.google.common.cache.LocalCache$Segment.get(LocalCache.java:2042)
... 39 more
Exception running application org.x1c1b.sqlitecompass.SQLiteCompassApplication
我可以通过将 opens org.x1c1b.sqlitecompass.config.provider;
粘贴到 module-info.java
来解决这个问题。但这会导致进一步的异常...
一般情况下,我应该如何配置我的模块/module-info.java
以便与 Google Guice 一起使用?是否可以结合使用 Google Guice 和 Modularity?
编辑
当我更改以下行时它似乎起作用了:
- 将声明我的 Guice 模块的
exports org.x1c1b.sqlitecompass.config
添加到module-info.java
- 使用附加的 VM 选项执行程序
--add-opens java.base/java.lang=com.google.guice
但我猜它更多的是找到的解决方法 here 而不是官方解决方案...
您必须打开所有将由 Guice 通过反射访问的包。
最简单的方法是通过将这个词放在 module-info.java
.
module
前面,将整个模块声明为 open