1、关于项目中使用struts2 报java.lang.NoSuchFieldException: resourceEntries 的问题。
当我们使用tomcat 7.0.64 及以下的版本时是不会出问题的。当我们在使用tomcat 7.0.65时会报这个问题,网上看到很多解答都是说什么tomcat 8之类的。
实际出现问题在tomcat 7.0.65 就开始了 。出现这个问题的根源是因为。在64到65 的时候,org\apache\catalina\loader\WebappClassLoader.java 这个类进行了抽象,抽象出了org\apache\catalina\loader\WebappClassLoaderBase.java.
2、在我们用的struts2 的xwork 包内 \com\opensymphony\xwork2\util\LocalizedTextUtil.java内的清除tomcat 缓存的地方有问题。问题就初夏这个clearMap。java自带的getDeclaredField 是取不到父类的属性的。所以这里会一直报错。
最新版的这两个方法:
private static void clearTomcatCache() {
ClassLoader loader = getCurrentThreadContextClassLoader();
// no need for compilation here.
Class cl = loader.getClass();
try {
if ("org.apache.catalina.loader.WebappClassLoader".equals(cl.getName())) {
clearMap(cl, loader, TOMCAT_RESOURCE_ENTRIES_FIELD);
} else {
if (LOG.isDebugEnabled()) {
LOG.debug("class loader " + cl.getName() + " is not tomcat loader.");
}
}
} catch (NoSuchFieldException nsfe) {
if ("org.apache.catalina.loader.WebappClassLoaderBase".equals(cl.getSuperclass().getName())) {
if (LOG.isDebugEnabled()) {
LOG.debug("Base class #0 doesn't contain '#1' field, trying with parent!", nsfe, cl.getName(), TOMCAT_RESOURCE_ENTRIES_FIELD);
}
try {
clearMap(cl.getSuperclass(), loader, TOMCAT_RESOURCE_ENTRIES_FIELD);
} catch (Exception e) {
if (LOG.isWarnEnabled()) {
LOG.warn("Couldn't clear tomcat cache using #0", e, cl.getSuperclass().getName());
}
}
}
} catch (Exception e) {
if (LOG.isWarnEnabled()) {
LOG.warn("Couldn't clear tomcat cache", e, cl.getName());
}
}
}
private static void clearMap(Class cl, Object obj, String name)
throws NoSuchFieldException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {
Field field = cl.getDeclaredField(name);
field.setAccessible(true);
Object cache = field.get(obj);
synchronized (cache) {
Class ccl = cache.getClass();
Method clearMethod = ccl.getMethod("clear");
clearMethod.invoke(cache);
}
}
3、遇到这个问题的时候,我们往往在处理老项目,很多项目是因为扫描除了漏洞而不得不使用新版本的tomcat。我们可以选择升级struts2的版本,可是版本的升级会带来很多意想不到的问题。摆在我们面前三条路①、用最新版本的struts2.②、拿出这个类,重新一下这两个方法。③、更改一下这两个方法,再放到jar包里面。
参考:
apache commons lang3包下的FieldUtils.getAllFields()可以获取类和父类的所有(public、protected、default、private)属性。
https://blog.csdn.net/wangjun5159/article/details/79289244