使用自定义布局时自定义启动器 ClassNotFound 异常
Custom Launcher ClassNotFound exception when using custom layout
Spring 启动 Maven 插件。 LayoutFactory 新功能。自 1.5.0.M1 起可用。
我在自定义布局中定义自定义启动器时遇到问题:
@Override public String getLauncherClassName() { return "com.mycompany.CustomLauncher"; }
如果我在引导应用程序源中包含我的自定义启动器,它会被重新打包到 BOOT-INF/classes,当我尝试 运行 JAR 时它会失败并出现 ClassNotFound 异常。
我一直在阅读 Repackager 代码,但我找不到任何允许从重新打包序列中选择性地排除给定 class 的钩子。如果我在我的布局中重写 getRepackagedClassesLocation 方法,那么引导主 class 由不同的 classloader 加载并且它在 SpringBoot ClassNotFound.
上失败
有什么方法可以强制启动器退出 BOOT-INF/classes 重新打包?
更新 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
class 名称旁边的数字是 CRC。我不确定是否相关,但 CRC-32 未知。
当使用 class 加载器时,我能够加载 com.test.Boot 但它因 PropertiesLauncherInternal.class
的 ClassNotFoundException 而失败
与其将它与您的应用程序代码放在一起,您的启动器代码应该位于一个单独的模块中,该模块被声明为 Spring Boot 的 Maven 插件的依赖项。这个单独的模块应该使用 Maven 的标准 jar 包装,不应该使用 Spring Boot 的 Maven 插件重新打包。
有一个 sample 展示了如何进行设置。
Spring 启动 Maven 插件。 LayoutFactory 新功能。自 1.5.0.M1 起可用。
我在自定义布局中定义自定义启动器时遇到问题:
@Override public String getLauncherClassName() { return "com.mycompany.CustomLauncher"; }
如果我在引导应用程序源中包含我的自定义启动器,它会被重新打包到 BOOT-INF/classes,当我尝试 运行 JAR 时它会失败并出现 ClassNotFound 异常。
我一直在阅读 Repackager 代码,但我找不到任何允许从重新打包序列中选择性地排除给定 class 的钩子。如果我在我的布局中重写 getRepackagedClassesLocation 方法,那么引导主 class 由不同的 classloader 加载并且它在 SpringBoot ClassNotFound.
上失败有什么方法可以强制启动器退出 BOOT-INF/classes 重新打包?
更新 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
class 名称旁边的数字是 CRC。我不确定是否相关,但 CRC-32 未知。
当使用 class 加载器时,我能够加载 com.test.Boot 但它因 PropertiesLauncherInternal.class
的 ClassNotFoundException 而失败与其将它与您的应用程序代码放在一起,您的启动器代码应该位于一个单独的模块中,该模块被声明为 Spring Boot 的 Maven 插件的依赖项。这个单独的模块应该使用 Maven 的标准 jar 包装,不应该使用 Spring Boot 的 Maven 插件重新打包。
有一个 sample 展示了如何进行设置。