gpt4 book ai didi

java - 如何以编程方式加载 JDK 模块?

转载 作者:太空宇宙 更新时间:2023-11-04 10:23:53 24 4
gpt4 key购买 nike

假设我们有模块 A 动态加载模块 B(使用类 ModuleFinderModuleLayer 等)。最后一个需要标准模块java.sql,该模块未通过模块A 加载到引导层。如何使用java代码从JDK(或JRE)加载所需的java.sql

编辑

这个示例 Maven 项目演示了我的问题:

项目结构:

│   pom.xml

├───loader
│ │ pom.xml
│ │
│ └───src
│ ├───main
│ │ ├───java
│ │ │ │ module-info.java
│ │ │ │
│ │ │ └───app
│ │ │ └───module
│ │ │ └───loader
│ │ │ AppLoader.java
│ │ │ AppModule.java
│ │ │
│ │ └───resources
│ └───test
│ └───java
└───sql-module
│ pom.xml

└───src
├───main
│ ├───java
│ │ │ module-info.java
│ │ │
│ │ └───app
│ │ └───module
│ │ └───sql
│ │ SQLAppModule.java
│ │
│ └───resources
└───test
└───java

pom.xml:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<artifactId>sample-app</artifactId>
<groupId>sample-app</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<artifactId>loader</artifactId>
</project>

加载器/pom.xml:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<artifactId>sample-app</artifactId>
<groupId>sample-app</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<artifactId>loader</artifactId>
</project>

loader/src/main/java/module-info.java:

module app.module.loader {
exports app.module.loader;
uses AppModule;
}

loader/src/main/java/app/module/loader/AppLoader.java:

public class AppLoader {
public static void main(String[] args) {
var path = Paths.get("sql-module", "target", "classes");
var moduleFinder = ModuleFinder.of(path);
var boot = ModuleLayer.boot();
var config = boot.configuration().resolveAndBind(moduleFinder, ModuleFinder.of(), Collections.emptyList());
var newLayer = boot.defineModulesWithOneLoader(config, Thread.currentThread().getContextClassLoader());
var testModule = ServiceLoader.load(newLayer, AppModule.class)
.findFirst()
.orElseThrow(() -> new RuntimeException("Module not found!"));
System.out.println("Module name: " + testModule.name());
System.out.println("Module version: " + testModule.version());
}
}

loader/src/main/java/app/module/loader/AppModule.java:

public interface AppModule {
String name();
String version();
}

sql-module/pom.xml:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<artifactId>sample-app</artifactId>
<groupId>sample-app</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<artifactId>sql-module</artifactId>
<dependencies>
<dependency>
<groupId>sample-app</groupId>
<artifactId>loader</artifactId>
<version>1.0-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
</dependencies>
</project>

sql-module/src/main/java/module-info.java:

module app.module.sql {
requires app.module.loader;
requires java.sql;

provides AppModule with SQLAppModule;
}

sql-module/src/main/java/app/module/sql/SQLAppModule.java:

public class SQLAppModule implements AppModule {
public SQLAppModule() {
List<Driver> drivers = DriverManager.drivers().collect(Collectors.toList());
System.out.println("Drivers on class path: " + drivers.size());
drivers.forEach(d -> {
System.out.println("Driver: " + d.toString());
System.out.println("Version: " + d.getMajorVersion() + "." + d.getMinorVersion());
});
}

@Override
public String name() {
return "SQL Module";
}

@Override
public String version() {
return "1.0-SNAPSHOT";
}
}

当您尝试在AppLauncher中使用main启动应用程序时,您将收到错误消息(我现在使用jdk-10.0.1):

Exception in thread "main" java.lang.module.FindException: Module java.sql not found, required by app.module.sql
at java.base/java.lang.module.Resolver.findFail(Resolver.java:877)
at java.base/java.lang.module.Resolver.resolve(Resolver.java:191)
at java.base/java.lang.module.Resolver.bind(Resolver.java:297)
at java.base/java.lang.module.Configuration.resolveAndBind(Configuration.java:482)
at java.base/java.lang.module.Configuration.resolveAndBind(Configuration.java:288)
at app.module.loader/app.module.loader.AppLoader.main(AppLoader.java:14)

黑客怎么样:我认为它们必须在最后使用,所以我们现在尝试找到或多或少的“官方”方法来做到这一点。

This answer 并不能解决这个问题,因为启动时或任何其他层上的 layer.findModule(moduleName).orElse(null) 将返回 null。

最佳答案

你不能也不应该在运行时这样做。

可以获取“app.module.sql”模块所需的缺失模块:

var missingModuleNames = moduleFinder.find("app.module.sql")
.map(ModuleReference::descriptor)
.map(ModuleDescriptor::requires)
.orElse(Collections.emptySet())
.stream()
.map(ModuleDescriptor.Requires::name)
.filter(name -> boot.findModule(name).isEmpty())
.collect(Collectors.toSet());

您甚至可以为 Java 平台模块创建一个 ModuleFinder:

var platformModules = Files.list(Paths.get(URI.create("jrt:/modules")))
.collect(Collectors
.toMap(AppLoader::getModuleName, Function.identity()));

var missingModulePaths = missingModules.stream()
.filter(systemModules::containsKey)
.map(systemModules::get)
.toArray(Path[]::new);

var missingModuleFinder = ModuleFinder.of(missingModulePaths);

但即使您执行此递归操作(java.sql 需要 java.transaction.xa),一旦您尝试定义模块,您尝试加载任何平台模块都会失败,并出现 LayerInstantiationException:

var cfg = boot.configuration()
.resolveAndBind(missingModuleFinder, ModuleFinder.of(), missingModules);

// This will throw the exception, because 'a layer cannot be created if the
// configuration contains a module named "java.base", or a module contains a
// package named "java" or a package with a name starting with "java.".'
// (see Javadoc of ModuleLayer#defineModulesWithOneLoader(Configuration, List<ModuleLayer>, ClassLoader)
ModuleLayer.defineModulesWithOneLoader(cfg, List.of(boot), null);

关于java - 如何以编程方式加载 JDK 模块?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50776796/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com