面对Jigsaw的相关更改,我似乎找不到任何信息,以了解是否仍然可以在运行时扫描所有可用的类(用于接口,批注等),就像Spring,Reflections和当前其他许多框架和库那样。类的加载方式。
编辑 :此问题是关于 扫描 实际的物理文件路径以查找类。另一个问题是关于动态 加载 类和资源。它是相关的,但 绝不是重复的 。
更新 :Jetty项目已经为此制定了标准化API的 JEP提案。如果您有办法帮助实现这一目标,请这样做。否则,请耐心等待。
更新2 :找到了这个相关的声音。引用后代代码段:
如果您真的只是想了解启动层中的模块(启动时已解析的模块)的内容,则可以执行以下操作:
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完成模块后。我没有看到任何地方对此进行记录。很难弄清所有这些。但是这里是代码,希望其他人可以从中受益。
classRef.getModule().getLayer().getConfiguration().modules()
List<ResolvedModule>
List<Module>
ResolvedModule
Module
.reference()
ModuleReference
ModuleReference#open()
ModuleReader
ModuleReader#list()
Optional<InputStream> ModuleReader#open(resourcePath)
Optional<ByteBuffer> ModuleReader#read(resourcePath)
请注意,即使在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)); } } } }