天天看點

java 運作時路徑_如何在運作時檢查目前Java類路徑(重複)

下面的代碼實作了Java 9 +(JigSAW)中的子產品路徑掃描。它查找調用堆棧上的所有類,然後對每個類引用調用

classRef.getModule().getLayer().getConfiguration().modules()

,它傳回A

List

,而不僅僅是

List

. (

ResolvedModule

允許您通路子產品資源,而

Module

沒有。)給定

解析子產品

參考每個子產品,您可以調用

.reference()

方法擷取

ModuleReference

對于一個子產品。

ModuleReference#open()

給你一個

ModuleReader

,它允許您使用

ModuleReader#list()

,或使用

Optional ModuleReader#open(resourcePath)

Optional ModuleReader#read(resourcePath)

. 然後關閉

模數轉換器

當你完成了子產品。我所看到的任何地方都沒有記錄。很難搞清楚這一切。但這裡是代碼,希望其他人能從中受益。

注意,即使在jdk9+中,您仍然可以使用傳統的類路徑元素和子產品路徑元素,是以對于完整的子產品路徑+類路徑掃描,您可能應該使用适當的類路徑掃描解決方案,例如

ClassGraph

,它支援使用以下機制進行子產品掃描(免責聲明,我是作者)。

package main;

import java.lang.StackWalker.Option;

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 {

private static final class CallerResolver extends SecurityManager {

@Override

protected Class>[] getClassContext() {

return super.getClassContext();

}

}

private static void findLayerOrder(ModuleLayer layer,

Set visited, Deque layersOut) {

if (visited.add(layer)) {

List parents = layer.parents();

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

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

}

layersOut.push(layer);

}

}

private static List> findModuleRefs(

Class>[] callStack) {

Deque layerOrder = new ArrayDeque<>();

Set visited = new HashSet<>();

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

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

findLayerOrder(layer, visited, layerOrder);

}

Set addedModules = new HashSet<>();

List> moduleRefs = new ArrayList<>();

for (ModuleLayer layer : layerOrder) {

Set modulesInLayerSet = layer.configuration()

.modules();

final List> 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 m : modulesInLayer) {

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

moduleRefs.add(m);

}

}

}

return moduleRefs;

}

private static Class>[] getCallStack() {

// Try StackWalker (JDK 9+)

PrivilegedAction[]> stackWalkerAction = new PrivilegedAction[]>() {

@Override

public Class>[] run() {

List> stackFrameClasses = new ArrayList<>();

StackWalker.getInstance(Option.RETAIN_CLASS_REFERENCE)

.forEach(sf -> stackFrameClasses

.add(sf.getDeclaringClass()));

return stackFrameClasses.toArray(new Class>[0]);

}

};

try {

// Try with doPrivileged()

return AccessController

.doPrivileged(stackWalkerAction);

} catch (Exception e) {

}

try {

// Try without doPrivileged()

return stackWalkerAction.run();

} catch (Exception e) {

}

// Try SecurityManager

PrivilegedAction[]> callerResolverAction = new PrivilegedAction[]>() {

@Override

public Class>[] run() {

return new CallerResolver().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> 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 in the call stack

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

}

}

}

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> systemModuleRefs = new ArrayList<>();

List> nonSystemModuleRefs = new ArrayList<>();

Class>[] callStack = getCallStack();

List> moduleRefs = findModuleRefs(

callStack);

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

for (Entry m : moduleRefs) {

(isSystemModule(m.getKey()) ? systemModuleRefs

: nonSystemModuleRefs).add(m);

}

// List system modules

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

for (Entry 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 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 location = ref.location();

if (location.isPresent()) {

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

}

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

Stream stream = moduleReader.list();

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

}

}

}

}