在Java 9中的运行时中扫描类路径/模块路径

面对Jigsaw的相关更改,我似乎找不到任何信息,以了解是否仍然可以在运行时扫描所有可用的类(用于接口,批注等),就像Spring,Reflections和当前其他许多框架和库那样。类的加载方式。

:此问题是关于 扫描

实际的物理文件路径以查找类。另一个问题是关于动态 加载 类和资源。它是相关的,但 。

:Jetty项目已经为此制定了标准化API的 JEP提案。如果您有办法帮助实现这一目标,请这样做。否则,请耐心等待。

:找到了这个相关的声音。引用后代代码段:

如果您真的只是想了解启动层中的模块(启动时已解析的模块)的内容,则可以执行以下操作:

  ModuleLayer.boot().configuration().modules().stream()

.map(ResolvedModule::reference)

.forEach(mref -> {

System.out.println(mref.descriptor().name());

try (ModuleReader reader = mref.open()) {

reader.list().forEach(System.out::println);

} catch (IOException ioe) {

throw new UncheckedIOException(ioe);

}

});

回答:

以下代码在Java 9+(Jigsaw /JPMS)中实现了模块路径扫描。它在调用堆栈中查找所有类,然后为每个类引用调用classRef.getModule().getLayer().getConfiguration().modules(),它们返回aa

List<ResolvedModule>,而不仅仅是a

List<Module>。(ResolvedModule可以访问模块资源,而Module不能访问。)给定ResolvedModule每个模块的引用,您可以调用.reference()方法以获取ModuleReference模块的。ModuleReference#open()给你一个ModuleReader,它允许你列出的资源模块中使用ModuleReader#list(),或使用打开资源Optional<InputStream>

ModuleReader#open(resourcePath)Optional<ByteBuffer>

ModuleReader#read(resourcePath)。然后关闭ModuleReader完成模块后。我没有看到任何地方对此进行记录。很难弄清所有这些。但是这里是代码,希望其他人可以从中受益。

请注意,即使在JDK9

+中,您仍然可以将传统的classpath元素与模块路径元素一起使用,因此对于完整的模块路径+类路径扫描,您可能应该使用适当的类路径扫描解决方案,例如ClassGraph,该解决方案支持使用以下内容进行模块扫描机制(免责声明,我是作者)。您可以在此处找到以下代码的基于反射的版本。

还请注意,在JDK

9之后的几个JDK版本中,StackWalker中存在一个错误,必须解决,有关详细信息,请参见上面的基于反射的代码。

package main;

import java.lang.StackWalker;

import java.lang.StackWalker.Option;

import java.lang.StackWalker.StackFrame;

import java.lang.module.ModuleReader;

import java.lang.module.ModuleReference;

import java.lang.module.ResolvedModule;

import java.net.URI;

import java.security.AccessController;

import java.security.PrivilegedAction;

import java.util.AbstractMap.SimpleEntry;

import java.util.ArrayDeque;

import java.util.ArrayList;

import java.util.Collections;

import java.util.Deque;

import java.util.HashSet;

import java.util.List;

import java.util.Map.Entry;

import java.util.Optional;

import java.util.Set;

import java.util.stream.Stream;

public class Java9Scanner {

/** Recursively find the topological sort order of ancestral layers. */

private static void findLayerOrder(ModuleLayer layer,

Set<ModuleLayer> visited, Deque<ModuleLayer> layersOut) {

if (visited.add(layer)) {

List<ModuleLayer> parents = layer.parents();

for (int i = 0; i < parents.size(); i++) {

findLayerOrder(parents.get(i), visited, layersOut);

}

layersOut.push(layer);

}

}

/** Get ModuleReferences from a Class reference. */

private static List<Entry<ModuleReference, ModuleLayer>> findModuleRefs(

Class<?>[] callStack) {

Deque<ModuleLayer> layerOrder = new ArrayDeque<>();

Set<ModuleLayer> visited = new HashSet<>();

for (int i = 0; i < callStack.length; i++) {

ModuleLayer layer = callStack[i].getModule().getLayer();

findLayerOrder(layer, visited, layerOrder);

}

Set<ModuleReference> addedModules = new HashSet<>();

List<Entry<ModuleReference, ModuleLayer>> moduleRefs = new ArrayList<>();

for (ModuleLayer layer : layerOrder) {

Set<ResolvedModule> modulesInLayerSet = layer.configuration()

.modules();

final List<Entry<ModuleReference, ModuleLayer>> modulesInLayer =

new ArrayList<>();

for (ResolvedModule module : modulesInLayerSet) {

modulesInLayer

.add(new SimpleEntry<>(module.reference(), layer));

}

// Sort modules in layer by name for consistency

Collections.sort(modulesInLayer,

(e1, e2) -> e1.getKey().descriptor().name()

.compareTo(e2.getKey().descriptor().name()));

// To be safe, dedup ModuleReferences, in case a module occurs in multiple

// layers and reuses its ModuleReference (no idea if this can happen)

for (Entry<ModuleReference, ModuleLayer> m : modulesInLayer) {

if (addedModules.add(m.getKey())) {

moduleRefs.add(m);

}

}

}

return moduleRefs;

}

/** Get the classes in the call stack. */

private static Class<?>[] getCallStack() {

// Try StackWalker (JDK 9+)

PrivilegedAction<Class<?>[]> stackWalkerAction =

(PrivilegedAction<Class<?>[]>) () ->

StackWalker.getInstance(

Option.RETAIN_CLASS_REFERENCE)

.walk(s -> s.map(

StackFrame::getDeclaringClass)

.toArray(Class[]::new));

try {

// Try with doPrivileged()

return AccessController

.doPrivileged(stackWalkerAction);

} catch (Exception e) {

}

try {

// Try without doPrivileged()

return stackWalkerAction.run();

} catch (Exception e) {

}

// Try SecurityManager

PrivilegedAction<Class<?>[]> callerResolverAction =

(PrivilegedAction<Class<?>[]>) () ->

new SecurityManager() {

@Override

public Class<?>[] getClassContext() {

return super.getClassContext();

}

}.getClassContext();

try {

// Try with doPrivileged()

return AccessController

.doPrivileged(callerResolverAction);

} catch (Exception e) {

}

try {

// Try without doPrivileged()

return callerResolverAction.run();

} catch (Exception e) {

}

// As a fallback, use getStackTrace() to try to get the call stack

try {

throw new Exception();

} catch (final Exception e) {

final List<Class<?>> classes = new ArrayList<>();

for (final StackTraceElement elt : e.getStackTrace()) {

try {

classes.add(Class.forName(elt.getClassName()));

} catch (final Throwable e2) {

// Ignore

}

}

if (classes.size() > 0) {

return classes.toArray(new Class<?>[0]);

} else {

// Last-ditch effort -- include just this class

return new Class<?>[] { Java9Scanner.class };

}

}

}

/**

* Return true if the given module name is a system module.

* There can be system modules in layers above the boot layer.

*/

private static boolean isSystemModule(

final ModuleReference moduleReference) {

String name = moduleReference.descriptor().name();

if (name == null) {

return false;

}

return name.startsWith("java.") || name.startsWith("jdk.")

|| name.startsWith("javafx.") || name.startsWith("oracle.");

}

public static void main(String[] args) throws Exception {

// Get ModuleReferences for modules of all classes in call stack,

List<Entry<ModuleReference, ModuleLayer>> systemModuleRefs = new ArrayList<>();

List<Entry<ModuleReference, ModuleLayer>> nonSystemModuleRefs = new ArrayList<>();

Class<?>[] callStack = getCallStack();

List<Entry<ModuleReference, ModuleLayer>> moduleRefs = findModuleRefs(

callStack);

// Split module refs into system and non-system modules based on module name

for (Entry<ModuleReference, ModuleLayer> m : moduleRefs) {

(isSystemModule(m.getKey()) ? systemModuleRefs

: nonSystemModuleRefs).add(m);

}

// List system modules

System.out.println("\nSYSTEM MODULES:\n");

for (Entry<ModuleReference, ModuleLayer> e : systemModuleRefs) {

ModuleReference ref = e.getKey();

System.out.println(" " + ref.descriptor().name());

}

// Show info for non-system modules

System.out.println("\nNON-SYSTEM MODULES:");

for (Entry<ModuleReference, ModuleLayer> e : nonSystemModuleRefs) {

ModuleReference ref = e.getKey();

ModuleLayer layer = e.getValue();

System.out.println("\n " + ref.descriptor().name());

System.out.println(

" Version: " + ref.descriptor().toNameAndVersion());

System.out.println(

" Packages: " + ref.descriptor().packages());

System.out.println(" ClassLoader: "

+ layer.findLoader(ref.descriptor().name()));

Optional<URI> location = ref.location();

if (location.isPresent()) {

System.out.println(" Location: " + location.get());

}

try (ModuleReader moduleReader = ref.open()) {

Stream<String> stream = moduleReader.list();

stream.forEach(s -> System.out.println(" File: " + s));

}

}

}

}

以上是 在Java 9中的运行时中扫描类路径/模块路径 的全部内容, 来源链接: utcz.com/qa/416000.html

回到顶部