关于现场的一个类加载问题
先看一个服务器的类加载视图(使用Arthas查看很方便,阿里巴巴开源的 Java 诊断工具)

当然,Bootstrapclassloader是ExtClassloadered的父级关系,自己也可以自定义classloader在web类加载器下面,说到这里就不得不提jvm的双亲委派机制
双亲委派机制
双亲委派机制是指当一个类加载器收到一个类加载请求时,该类加载器首先会把请求委派给父类加载器。每个类加载器都是如此,只有在父类加载器在自己的搜索范围内找不到指定类时,子类加载器才会尝试自己去加载。
双亲委派模型工作工程:
1.当Application ClassLoader 收到一个类加载请求时,他首先不会自己去尝试加载这个类,而是将这个请求委派给父类加载器Extension ClassLoader去完成。
2.当Extension ClassLoader收到一个类加载请求时,他首先也不会自己去尝试加载这个类,而是将请求委派给父类加载器Bootstrap ClassLoader去完成。
3.如果Bootstrap ClassLoader加载失败(在<JAVA_HOME>\lib中未找到所需类),就会让Extension ClassLoader尝试加载。
4.如果Extension ClassLoader也加载失败,就会使用Application ClassLoader加载。
5.如果Application ClassLoader也加载失败,就会使用自定义加载器去尝试加载。
6.如果均加载失败,就会抛出ClassNotFoundException异常。
现场遇到当项目部署在服务器上,发现el表达式解析错误,以下为错误堆栈:
Caused by: java.lang.NullPointerException
at java.util.Objects.requireNonNull(Objects.java:203)
at javax.el.CompositeELResolver.add(CompositeELResolver.java:43)
at com.bes.enterprise.web.jasper.el.ELContextImpl.<clinit>(ELContextImpl.java:83)
... 117 more
15:14:08.519|SEVERE|web|_ThreadID=237;_ThreadName=httpWorkerThread-8080-20|Servlet.service() for servlet [jsp] threw exception
java.lang.NoClassDefFoundError: Could not initialize class com.bes.enterprise.web.jasper.el.ELContextImpl
at com.bes.enterprise.web.jasper.compiler.Validator$ValidateVisitor.getJspAttribute(Validator.java:1439)
at com.bes.enterprise.web.jasper.compiler.Validator$ValidateVisitor.checkXmlAttributes(Validator.java:1257)
at com.bes.enterprise.web.jasper.compiler.Validator$ValidateVisitor.visit(Validator.java:890)
at com.bes.enterprise.web.jasper.compiler.Node$CustomTag.accept(Node.java:1543)
at com.bes.enterprise.web.jasper.compiler.Node$Nodes.visit(Node.java:2388)
at com.bes.enterprise.web.jasper.compiler.Node$Visitor.visitBody(Node.java:2440)
发现实例化不了服务器下的
java.lang.NoClassDefFoundError: Could not initialize class com.bes.enterprise.web.jasper.el.ELContextImpl
仔细查看堆栈
javax.el.CompositeELResolver.add(CompositeELResolver.java:47)
这个类路径,应用的juel-api.jar和服务器下的el-api.jar都有,发现两者都调用这个方法,且包名相同,所以会冲突,发现这个jar包是activiti的el实现和tomcat的el实现冲突导致
juel-api-2.2.7.jar ——包含javax.el 包下的一些类
juel-impl-2.2.7.jar ——包含de.odysseus.el 实现类
juel-spi-2.2.7.jar ——包含META-INF/service/javax.el.ExpressionFactory 服务提供资源的定义(如果你的classpath里有多个EL的实现,而你又希望使用JUEL的实现,那么需要调用ExpressionFactory.newInstance() )
再查看调用关系,发现对ExpressionFactory抽象类的调用不同,tomcat的EL调用的是tomcat的org.apache.el.ExpressionFactoryImpl,而juel调用的是 juel-api.jar中的de.odysseus.el.ExpressionFactoryImpl,原来如此,也就是说tomcat的EL和juel都只是满足自己解析表达式的需要,且因为使用了相同的包名(javax.el),不能同时使用,要么只能解析JSP中的EL表达式,要么只能解析Activiti中的EL表达式。
自己有测试将juel-api.jar向上委托父加载器,发现不能强转

所以解决方案有是三种 1 去掉juel-spi.jar
2 降低activiti的版本到5.x
3 将服务器下的el-api.jar包名给改掉
题外话:看到一篇很不错的
Tomcat ClassLoader详解 原文链接:https://blog.csdn.net/qq_35076190/article/details/115529271
浙公网安备 33010602011771号