Ich versuche, eine Instanz einer Klasse aus JAR-Datei in einem Byte-Array geladen zu erstellen.
Ich erhalte zwei argumente:
1. byte [], die mit der erforderlichen Klasse JAR-Datei repräsentiert
2. qualifizierten Klassennamen
Wenn ich es lokal zu testen bin es funktioniert wie erwartet, aber wenn ich hochladen genau die gleiche JAR-Datei mit dem gleichen qualifizierten Klassennamen remote (mithilfe der mit Spring MVC für Back und AngularJS für das Front-End im Tomcat-Server implementierten Webanwendung). Es kann die erforderliche Klasse nicht gefunden werden:
java.lang.ClassNotFoundException
Als ich debugging, drehte es sich t, dieser Klassenlader wird korrekt aufgerufen, aber keine Klasse wird von jar geladen.
Ich wäre dankbar, wenn jemand sagen kann, was der Grund für diesen Unterschied sein kann oder wie kann ich diese Funktionalität auf andere Weise implementieren.
Eine Methode, die Klasse lädt und gibt eine Instanz davon:
Problem mit der Ladeklasse aus JAR-Datei als Byte-Array dargestellt
public static <T> T getInstanceOfLoadedClass(byte[] jarFileBytes, String qualifiedClassName) throws ClassFromJarInstantiationException {
LOGGER.info("Getting instance of class from loaded jar file. Class name: " + qualifiedClassName);
try {
return (T) Class.forName(qualifiedClassName, true, new ByteClassLoader(jarFileBytes)).newInstance();
} catch (InstantiationException | IllegalAccessException | IOException | ClassNotFoundException | NoSuchFieldException e) {
LOGGER.error("Exception was thrown while reading jar file for " + qualifiedClassName + "class.", e);
throw new ClassFromJarInstantiationException(e);
}
}
Individuelle ByteClassLoader:
public class ByteClassLoader extends ClassLoader {
private static final Logger LOGGER = Logger.getLogger(ByteClassLoader.class);
private final byte[] jarBytes;
private final Set<String> names;
public ByteClassLoader(byte[] jarBytes) throws IOException {
this.jarBytes = jarBytes;
this.names = loadNames(jarBytes);
}
private Set<String> loadNames(byte[] jarBytes) throws IOException {
Set<String> set = new HashSet<>();
try (ZipInputStream jis = new ZipInputStream(new ByteArrayInputStream(jarBytes))) {
ZipEntry entry;
while ((entry = jis.getNextEntry()) != null) {
set.add(entry.getName());
}
}
return Collections.unmodifiableSet(set);
}
@Override
public InputStream getResourceAsStream(String resourceName) {
if (!names.contains(resourceName)) {
return null;
}
boolean found = false;
ZipInputStream zipInputStream = null;
try {
zipInputStream = new ZipInputStream(new ByteArrayInputStream(jarBytes));
ZipEntry entry;
while ((entry = zipInputStream.getNextEntry()) != null) {
if (entry.getName().equals(resourceName)) {
found = true;
return zipInputStream;
}
}
} catch (IOException e) {
LOGGER.error("ByteClassLoader threw exception while reading jar byte stream for resource: "+resourceName, e);
e.printStackTrace();
} finally {
if (zipInputStream != null && !found) {
try {
zipInputStream.close();
} catch (IOException e) {
LOGGER.error("ByteClassLoader threw exception while closing jar byte stream for resource: "+resourceName, e);
e.printStackTrace();
}
}
}
return null;
} }