Version: 3.3.1.RELEASE
场景: 自定义了一个ClassLoader,并设置了线程上下文ClassLoader为自定义的ClassLoader,然后使用Beetl渲染模板,报Exception in thread "main" java.lang.NoClassDefFoundError: javax/servlet/http/HttpServletRequest。
伪代码:
Maven:
cn.hutool
hutool-all
5.5.2
com.ibeetl
beetl
3.3.1.RELEASE
Class:
public class BeetlTest {
public static void main(String[] args) {
File file = FileUtil.file(
"C:\\Users\\admin\\.m2\\repository\\org\\apache\\tomcat\\embed\\tomcat-embed-core\\9.0.41\\tomcat-embed-core-9.0.41.jar");
JarClassLoader jarClassLoader = JarClassLoader.loadJar(file);
Thread.currentThread().setContextClassLoader(jarClassLoader);
// 1. do some business must use JarClassLoader
// business code......
// 2. render beetl template
executeBeetl();
}
public static void executeBeetl(){
try {
// 这里出错的。
Configuration cfg = Configuration.defaultConfiguration();
GroupTemplate groupTemplate = new GroupTemplate(new StringTemplateResourceLoader(), cfg);
Template template = groupTemplate.getTemplate("Print name=AAAAA");
System.out.println(template.render());
} catch (IOException e) {
e.printStackTrace();
}
}
}
简单分析:
执行Configuration.defaultConfiguration();时,不能指定类加载器,默认使用线程上下文类加载器了。
而因为加载了tomcat的包,因此根据Beetl逻辑加载beetl-default.properties时,会添加下面的TAG:
TAG.incdlueJSP= org.beetl.ext.jsp.IncludeJSPTag,javax.servlet.http.HttpServletRequest
加载org.beetl.ext.jsp.IncludeJSPTag类时,就出错了。
正常情况下,不会加载TAG.incdlueJSP的,实际上这里的业务也不需要。
个人拙见:
Configuration类添加一个可以指定ClassLoader的构造函数,使用时用ClassLoader.getSystemClassLoader()即可。
系统类加载器不包含HttpServletRequest,于是这样就不会初始化这个TAG了:TAG.incdlueJSP= org.beetl.ext.jsp.IncludeJSPTag,javax.servlet.http.HttpServletRequest。问题也就不会发生了。
public Configuration(ClassLoader classloader) {
this.classloader = classloader;
initDefault();
}
使用:
Configuration cfg = new Configuration(ClassLoader.getSystemClassLoader());