是否可以在 Tomcat 8 中禁用对 JSP 2.3 引用静态字段和方法的支持

Is it possible to disable support for referencing static fields and methods for JSP 2.3 in Tomcat 8

是否可以关闭作为统一表达式语言 3.0 的一部分添加的 Tomcat8 中对引用静态字段和方法的支持。

我们的应用程序中有 ~4K JSP,有许多 ${undefined}(未指定范围)表达式,迁移到 Tomcat 8 导致性能显着下降,因为这些表达式的评估是合法的 'null' 值。我们不再对较新的页面使用 JSP 技术,但遗留技术不会很快消失。

有问题的代码在 javax.servlet.el.ScopedAttributeELResolver class 中,它试图解析来自 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 打开了一个错误,该错误已关闭,因为不会修复。我认为他们可能会添加一些 属性 来禁用性能消耗代码,但现在他们不会,因为:

请指教谢谢

禁用新行为的一种方法是利用 Tomcat 的 class 加载机制。通用 class 加载程序包含额外的 classes,它们对 Tomcat 内部 classes 和所有 Web 应用程序都是可见的。此 class 加载程序搜索的位置由 $CATALINA_BASE/conf/catalina.properties 中的 common.loader 属性 定义。默认设置将按照列出的顺序搜索以下位置:

  1. 在 $CATALINA_BASE/lib
  2. 中解压 classes 和资源
  3. $CATALINA_BASE/lib
  4. 中的 JAR 文件
  5. 在 $CATALINA_HOME/lib
  6. 中解压 classes 和资源
  7. $CATALINA_HOME/lib
  8. 中的 JAR 文件

我用一个 class 创建了一个新的 jar:javax.servlet.jsp.el.ScopedAttributeELResolver,这个 class 与原来的相同(来自 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;
    }

此 class 将加载而不是原来的加载并绕过性能问题。

优点:

  • 通过简单的 jar 删除很容易回滚

缺点:

  • 每次Tomcat升级都需要维护

似乎 Tomcat 8.0.33 解决了这个问题,性能提高了 10 倍 https://bz.apache.org/bugzilla/show_bug.cgi?id=57583

几年后,我们的系统 运行 在 Tomcat 8.5 上出现了巨大的内存分配问题,我们实施了与上面提到的类似的解决方法 ),但不是完全禁用 类 的解析,我们只为首字母大写的属性保留它(类 应该是)。

真正的中期解决方案当然是按照 Tomcat 迁移指南中的说明调整我们的页面属性范围...