Struts2+jreloader 出现 NoClassDefFoundError: VelocityEngine

用 jreloader 动态重新加载改变的类而不用重启 JVM 来避免因 classes 目录中的文件改动而不停重启 Tomcat。但是却会出现如下的问题:

Feb 15, 2011 3:51:06 PM org.apache.catalina.core.StandardContext filterStart
SEVERE: Exception starting filter struts2
java.lang.NoClassDefFoundError: Lorg/apache/velocity/app/VelocityEngine;
 at java.lang.Class.getDeclaredFields0(Native Method)
 at java.lang.Class.privateGetDeclaredFields(
 at java.lang.Class.getDeclaredFields(
 at com.opensymphony.xwork2.inject.ContainerImpl.addInjectors(
 at com.opensymphony.xwork2.inject.ContainerImpl$1.create(
 at com.opensymphony.xwork2.inject.ContainerImpl$1.create(
 at com.opensymphony.xwork2.inject.util.ReferenceCache$
 at java.util.concurrent.FutureTask$Sync.innerRun(
 at com.opensymphony.xwork2.inject.util.ReferenceCache.internalCreate(
 at com.opensymphony.xwork2.inject.util.ReferenceCache.get(
 at com.opensymphony.xwork2.inject.ContainerImpl$ConstructorInjector.<init>(
 at com.opensymphony.xwork2.inject.ContainerImpl$5.create(
 at com.opensymphony.xwork2.inject.ContainerImpl$5.create(
 at com.opensymphony.xwork2.inject.util.ReferenceCache$
 at java.util.concurrent.FutureTask$Sync.innerRun(
 at com.opensymphony.xwork2.inject.util.ReferenceCache.internalCreate(

原因是在虚拟机参数中加了  -noverify,这将促使 Struts2 去加载代码中引用了而不会在运行时使用的 Velocity 相关的类。


It turns out that this is not directly a jrebel issue. This problem appears when -noverify jvm flag is used, the application will fail even without jrebel when this flag is present.
Struts contains org.apache.struts2.views.velocity.VelocityManager which contains fields that reference velocity classes. In com.opensymphony.xwork2.config.providers.XmlConfigurationProvider#register getDeclaredConstructors() is called on the VelocityManager, without noverify flag this call will fail and this class will be ignored, but with noverify this call will succeed and processing will fail later on when getDeclaredFields() is called on the same class.
Similar issue has been also reported with jrockit vm, see As weblogic runns with bytecode verifier disabled by default it is likely to be the same problem.
To resolve it you have at least the following choices:
1) Add the missing velocity jar to your application (this is probably the easiest solution).
2) Remove -noverify form jvm arguments
3) Improve XmlConfigurationProvider#register
4) Investigate why getDeclaredConstructors fails or succeeds depending on -noverify. If one of these behaviours turns out to be violating jvm spec then file a bug for jvm.
Currently it doesn't look like we should be attempting to somehow fix it in jrebel, though if we find a good way to fix it then we'll do it.

其实我们看到这样的错误,第一个反应是找不到类,缺包,那么是谁在引用该类,要不就直接引入相应的 jar 文件。pom.xml 里加上:

可恶的是 velocity-tools 会加入它所依赖的:

+- commons-digester:commons-digester:jar:1.8:compile
+- commons-chain:commons-chain:jar:1.1:compile
+- commons-validator:commons-validator:jar:1.3.1:compile
+- oro:oro:jar:2.0.8:compile
+- sslext:sslext:jar:1.2-0:compile
+- org.apache.struts:struts-core:jar:1.3.8:compile
+- org.apache.struts:struts-taglib:jar:1.3.8:compile
\- org.apache.struts:struts-tiles:jar:1.3.8:compile

那就用 <excludes> 排除掉不用的吧。

再就是去掉虚拟机参数 -noverify,不用 jreloader 或是 jrebel,或是修正 Struts2 使之迁就于 jreloader 或 jrebel。

好像也并不怎么会影响到 jreloader 的使用。


本文链接, 来自 隔叶黄莺 Yanbin Blog

[版权声明] Creative Commons License 本文采用 署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0) 进行许可。

Notify of

1 Comment
Inline Feedbacks
View all comments
9 years ago


Struts2+jreloader 出现 NoClassDefFoundError: VelocityEngine | 隔叶黄莺 Unmi Blog - 软件编程实践