是否可以关闭在Tomcat 8中引用静态字段和方法的支持,它是作为统一表达式语言3.0的一部分添加的。
我们的应用程序中有~4K JSP,有许多${undefined}
(没有指定范围)表达式,迁移到Tomcat 8会导致性能显着下降,因为对这些表达式的评估是合法的“null”值。我们不再将JSP技术用于较新的页面,但遗留的不会很快消失。
有问题的代码位于 javax.servlet.el.ScopedAttributeELResolver 类中,该类尝试解析ImportHandler中的表达式,该表达式进行许多Class.forName查找,这很大程度上由于ClassNotFoundException而失败。
@Override
public Object getValue(ELContext context, Object base, Object property) {
if (context == null) {
throw new NullPointerException();
}
Object result = null;
if (base == null) {
context.setPropertyResolved(base, property);
if (property != null) {
String key = property.toString();
PageContext page = (PageContext) context
.getContext(JspContext.class);
result = page.findAttribute(key);
if (result == null) {
// This might be the name of an imported class
ImportHandler importHandler = context.getImportHandler();
if (importHandler != null) {
Class<?> clazz = importHandler.resolveClass(key);
if (clazz != null) {
result = new ELClass(clazz);
}
if (result == null) {
// This might be the name of an imported static field
clazz = importHandler.resolveStatic(key);
if (clazz != null) {
try {
result = clazz.getField(key).get(null);
} catch (IllegalArgumentException | IllegalAccessException |
NoSuchFieldException | SecurityException e) {
// Most (all?) of these should have been
// prevented by the checks when the import
// was defined.
}
}
}
}
}
}
}
return result;
}
更新
为Tomcat 8打开了一个错误 - performance problems when using scopeless optional attributes,该错误已关闭,因为无法修复。我认为他们可能会添加一些属性来禁用性能消耗代码,但是现在他们不会,因为:
请告知谢谢
答案 0 :(得分:4)
禁用新行为的一种方法是利用Tomcat的类加载机制。公共类加载器包含对Tomcat内部类和所有Web应用程序都可见的其他类。此类加载器搜索的位置由$ CATALINA_BASE / conf / catalina.properties中的common.loader属性定义。默认设置将按列出的顺序搜索以下位置:
我创建了一个包含一个类的新jar: javax.servlet.jsp.el.ScopedAttributeELResolver ,这个类与原始类(来自jsp-api.jar)相同,但 getValue除外执行静态解析的方法(tomcat代码在Apache 2许可下,因此补丁是合法的)。该jar放在 $ CATALINA_BASE / lib 文件夹下。
新方法:
@Override
public Object getValue(ELContext context, Object base, Object property) {
if (context == null) {
throw new NullPointerException();
}
Object result = null;
if (base == null) {
context.setPropertyResolved(base, property);
if (property != null) {
String key = property.toString();
PageContext page = (PageContext) context
.getContext(JspContext.class);
result = page.findAttribute(key);
// if (result == null) {
// // This might be the name of an imported class
// ImportHandler importHandler = context.getImportHandler();
// if (importHandler != null) {
// Class<?> clazz = importHandler.resolveClass(key);
// if (clazz != null) {
// result = new ELClass(clazz);
// }
// if (result == null) {
// // This might be the name of an imported static field
// clazz = importHandler.resolveStatic(key);
// if (clazz != null) {
// try {
// result = clazz.getField(key).get(null);
// } catch (IllegalArgumentException | IllegalAccessException |
// NoSuchFieldException | SecurityException e) {
// // Most (all?) of these should have been
// // prevented by the checks when the import
// // was defined.
// }
// }
// }
// }
// }
}
}
return result;
}
将加载此类而不是原始类,并绕过性能问题。
优势:
<强>缺点:强>
答案 1 :(得分:2)
似乎Tomcat 8.0.33解决了这个问题,性能提升速度提高了10倍 https://bz.apache.org/bugzilla/show_bug.cgi?id=57583
答案 2 :(得分:0)
几年后,由于在Tomcat 8.5上运行的系统存在巨大的内存分配问题,我们实现了与上述https://stackoverflow.com/a/35679744/8068546相似的变通方法,但我们并未完全禁用类的解析,而是保留了它仅适用于以首字母大写命名的属性(应具有类)。
真正的中期解决方案当然是按照Tomcat迁移指南中的说明来定义页面属性的范围。