【问题标题】:Custom Launcher ClassNotFound exception when using custom layout使用自定义布局时自定义 Launcher ClassNotFound 异常
【发布时间】:2017-01-24 13:48:34
【问题描述】:

Spring Boot Maven 插件。布局工厂新功能。从 1.5.0.M1 开始可用。

我在自定义布局中定义自定义启动器时遇到问题:

@Override public String getLauncherClassName() { return "com.mycompany.CustomLauncher"; }

如果我在启动应用程序源中包含我的自定义启动器,它会被重新打包到 BOOT-INF/类,当我尝试运行 JAR 时它会失败并出现 ClassNotFound 异常。

我一直在阅读 Repackager 代码,但我找不到任何允许有选择地从重新打包序列中排除给定类的钩子。如果我在布局中覆盖 getRepackagedClassesLocation 方法,则引导主类由不同的类加载器加载,并且在 SpringBoot ClassNotFound 上失败。

有什么方法可以强制启动器退出 BOOT-INF/类重新打包?

更新 1

@Override
public void writeLoadedClasses(LoaderClassesWriter writer) throws IOException
{
    String name = PropertiesLauncherInternal.class.getName().replaceAll("\\.", "\\\\") + ".class";
    InputStream inputStream = PropertiesLauncherInternal.class.getResourceAsStream(PropertiesLauncherInternal.class.getSimpleName() + ".class");
    writer.writeEntry(name, inputStream);
    writer.writeLoaderClasses();
}

为了查看代码是否可以访问,我添加了这个测试:

    JarInputStream is = new JarInputStream(new FileInputStream(new File("c:/git/dev/framework/boot/target/boot-current-SNAPSHOT.jar")), true);
    JarEntry entry = null;
    while (null != (entry = is.getNextJarEntry()))
    {
        System.out.println(entry.getName() + "-" + entry.getCrc());
    }

    URL url = new File("c:/git/dev/framework/boot/target/boot-current-SNAPSHOT.jar").toURL();
    URL[] urls = new URL[] { url };
    ClassLoader cl = new URLClassLoader(urls);
    Class cls = cl.loadClass("com.test.Boot");
    Class cls = cl.loadClass("com.launcher.PropertiesLauncherInternal");

对于第一个循环,我得到以下日志:

BOOT-INF/--1
BOOT-INF/classes/--1
BOOT-INF/classes/com/-0
BOOT-INF/classes/com/test/-0
BOOT-INF/classes/com/test/Boot.class-2405822989
...
com\launcher\PropertiesLauncherInternal.class--1

类名旁边的数字是 CRC。我不确定是否相关,但 CRC-32 是未知的。

当使用类加载器时,我能够加载 com.test.Boot,但它在 PropertiesLauncherInternal.class 的 ClassNotFoundException 上失败

【问题讨论】:

    标签: maven spring-boot spring-boot-maven-plugin


    【解决方案1】:

    您的启动器代码不应与您的应用程序代码一起使用,而应位于一个单独的模块中,该模块被声明为 Spring Boot 的 Maven 插件的依赖项。这个单独的模块应该使用 Maven 的标准 jar 打包,并且不应该使用 Spring Boot 的 Maven 插件重新打包。

    sample 显示了如何设置。

    【讨论】:

    • 嗨,安迪,我已经尝试过这样做,并且我的启动器已打包好。但是,当我尝试运行 JAR 时,我得到一个错误:无法找到或加载主类。如果我手动将相同的类(相同的内容、相同的名称)复制到 JAR 中的相同位置,那么它可以工作。知道问题可能是什么吗?
    • 不,抱歉。也许您可以分享一些重现问题的代码?
    • 我在原问题上添加了一些细节。
    • 问题是我使用了错误的斜杠转换方式。 JAR 已构建,可以找到资源,但类加载器无法加载它。
    猜你喜欢
    • 2018-11-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多