undertow开发模式下类加载器问题

自己写了一个redis工具,在Jfinal启动的时候发现有不同的类加载器都要加载Jedis这个类,导致启动失败。后面发现将undertow的开发模式关闭(热加载关闭),就能正常启动。

# 设置为false可正常启动
undertow.devMode=false

undertow的开发模式下,我在代码里打印了下类加载器:

Class<?> jedisClass = null;
try {
    jedisClass = Class.forName("redis.clients.jedis.Jedis");
    ClassLoader loader = jedisClass.getClassLoader();
    System.out.println("Jedis loaded by: " + loader);
    System.out.println("Parent loader: " + loader.getParent());
} catch (ClassNotFoundException e) {
    throw new RuntimeException(e);
}

结果是:

Jedis loaded by: com.jfinal.server.undertow.hotswap.HotSwapClassLoader@1b75c2e3
Parent loader: sun.misc.Launcher$AppClassLoader@18b4aac2

Exception in thread "main" java.lang.LinkageError: loader constraint violation: loader (instance of sun/misc/Launcher$AppClassLoader) previously initiated loading for a different type with name "redis/clients/jedis/Jedis"
	at java.lang.ClassLoader.defineClass1(Native Method)
	at java.lang.ClassLoader.defineClass(ClassLoader.java:763)
	at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:142)
	at java.net.URLClassLoader.defineClass(URLClassLoader.java:467)
	at java.net.URLClassLoader.access$100(URLClassLoader.java:73)
	at java.net.URLClassLoader$1.run(URLClassLoader.java:368)
	at java.net.URLClassLoader$1.run(URLClassLoader.java:362)
	at java.security.AccessController.doPrivileged(Native Method)
	at java.net.URLClassLoader.findClass(URLClassLoader.java:361)
	at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
	at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:349)
	at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
	at redis.clients.jedis.JedisFactory.makeObject(JedisFactory.java:170)
	at org.apache.commons.pool2.impl.GenericObjectPool.create(GenericObjectPool.java:566)
	at org.apache.commons.pool2.impl.GenericObjectPool.borrowObject(GenericObjectPool.java:306)
	at org.apache.commons.pool2.impl.GenericObjectPool.borrowObject(GenericObjectPool.java:233)
	at redis.clients.jedis.util.Pool.getResource(Pool.java:38)
	at redis.clients.jedis.JedisPool.getResource(JedisPool.java:378)

只要将开发模式关闭,打印的就都是sun.misc.Launcher,则能正常启动。

------收个尾------

按照评论区热心人士小杜同学的方法解决了,虽然现在仍不明白这个类为什么会被热加载器补捕获。方法如下:

UnsertowServer.create(...).addSystemClassPrefix("redis.clients.jedis.").start();

通过addSystemClassPrefix方法将其强行推给系统级classLoader来加载。

------还得收个尾------PixPin_2025-03-20_23-47-33-1.png

这就是redis.clients会被热加载爱上的原因了。

评论区

杜福忠

2025-03-20 11:10

https://jfinal.com/doc/1-5

文档的 第4 小结 配置

happyboy

2025-03-20 11:28

@杜福忠 问题依旧。其实这个类压根就不在classes下,HotSwapClassLoader为什么要捕获他呢。而且我现在也并不是类型转换问题。我是希望在开发模式下,能单独排除对他的热加载。

杜福忠

2025-03-20 12:54

@happyboy 看错了是 addSystemClassPrefix 方法。主要也是没看见你redis工具是咋写的,估计是反序列化那里没用 JF 内置的ISerializer

happyboy

2025-03-20 20:27

@杜福忠 可行,同时我也发现了这篇帖子:https://jfinal.com/feedback/8460

杜福忠

2025-03-20 20:59

@happyboy HotSwapResolver 的 hotSwapClassPrefix 内置名单就有redis.clients.

happyboy

2025-03-20 23:37

@杜福忠 源代码我看到了,原来如此。ღ( ´・ᴗ・` )比心

热门反馈

扫码入社