如何从spring jar加载Class spring注释类

问题描述 投票:0回答:1

我在春季项目中获得了以下课程

interface IStep {
    IStep doStep();
    String getName();
}

@Component
public class Step1 implements IStep {
    public final static String NAME = "STEP1";

    ...
}

@Component
public class Step1 implements IStep {
    ...
}

从该项目构建了一个 jar。

使用一个简单的java项目,我尝试加载jar来分析类之间的依赖关系并创建一些图表。我的第一个用例是找到所有实现 IStep 的类并获取它们的名称。

我正在尝试使用反射来加载 jar,获取类并加载它们。然而,我总是在

noclassdeffounderror
上得到
Step1
。当我删除
@Component
注释时,它工作得很好。如何在不删除注释的情况下加载类?

JarFile jarFile = new JarFile(pathToJar);
Enumeration<JarEntry> e = jarFile.entries();

URL[] urls = { new URL("jar:file:" + pathToJar+"!/") };
URLClassLoader cl = URLClassLoader.newInstance(urls);

while (e.hasMoreElements()) {
    JarEntry je = e.nextElement();
    if(je.isDirectory() || !je.getName().endsWith(".class") || !je.getName().contains("mypackagename")){
        continue;
    }
    // -6 because of .class
    String className = je.getName().substring(0,je.getName().length()-6);
    className = className.replace('/', '.');
    Class c = cl.loadClass(className); //noclassdeffounderror
}
java spring reflection
1个回答
0
投票

添加类似 System.out.println(je.getName()); 的内容在 if 表达式之后并显示输出吗?

@AndrewL 我得到这样的东西:

BOOT-INF.classes.com.example.demo.Step1

所以问题出在 jar 文件内的路径上。

试试这个:

String 类名 = je.getName() .replace("BOOT-INF.classes.", "") .substring(0, je.getName().length() - 6);

我尝试过,但这给了我一个 ClassNotFoundException。

啊,现在我明白了!我事先没看清楚。

是的,如果在 jar 文件(或文件系统)中找不到该类,您将得到

ClassNotFoundException
。但如果存在依赖性问题,您将得到类似名称的
NoClassDefFoundError

您遇到的问题是,您的 Jar 文件似乎是由 Spring Boot 在其特殊的“可执行 Jar 文件结构”中创建的。这会在 jar 文件中以分层方式定位依赖项。 一个简单的标准 URLClassLoader 不知道如何查找

embedded

jar 文件中的依赖项,这就是为什么你会得到 NoClassDefFoundError

要么不使用 Spring Boot 的分层索引打包项目,请考虑以下替代方案:

    Maven Shade 插件
  • JarClassLoader
  • OneJar
  • Gradle 影子插件
  • 如果这不是一个选项,您将需要深入研究 Spring Boot 提供的工具来读取其 Jar 文件结构(请参阅
可执行 Jar 文件结构

的第 2.1 节)

© www.soinside.com 2019 - 2024. All rights reserved.