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



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

我们的应用程序中有 ~4K JSP,有许多${undefined}(未指定范围)表达式,迁移到 Tomcat 8 会导致性能显著下降,因为这些表达式的评估是合法的"空"值。我们不再将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 打开了一个错误 - 使用无范围的可选属性时出现性能问题,该错误因无法修复而关闭。我以为他们可能会添加一些属性来禁用性能消耗代码,但现在他们不会,因为:

  • 这将是雄猫特定的
  • 它必须是系统属性,因为这是一个规范类
  • 它不能应用于每个应用程序 - 它会影响在该实例上运行的所有应用程序

请告知谢谢

禁用新行为的一种方法是利用 Tomcat 的类加载机制。公共类装入器包含对 Tomcat 内部类和所有 Web 应用程序可见的其他类。此类装入器搜索的位置由 $CATALINA_BASE/conf/catalina.properties 中的 common.loader 属性定义。默认设置将按列出顺序搜索以下位置:

  1. $CATALINA_BASE/lib 中解压缩的类和资源
  2. $CATALINA_BASE/lib 中的 JAR 文件
  3. 解压缩的类和资源 $CATALINA_HOME/lib
  4. $CATALINA_HOME/lib 中的 JAR 文件

我创建了一个带有一个类的新jar:javax.servlet.jsp.el.ScopedAttributeELResolver,这个类与原始类相同(来自jsp-api.jar),除了执行静态解析的getValue方法(tomcat代码在Apache 2许可证下,因此补丁是合法的)。放置在 $CATALINA_BASE/lib 文件夹下的 jar。

新方法:

    @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;
    }

将加载此类而不是原始类,并绕道性能问题。

优势:

  • 通过简单的 jar 删除轻松回滚

弊:

  • 每次雄猫升级都需要维护

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

几年后,我们在Tomcat 8.5上运行的系统出现了巨大的内存分配问题,我们实施了与上述类似的解决方法 https://stackoverflow.com/a/35679744/8068546),但是我们没有完全禁用类的解析,而是仅将其保留为以大写首字母命名的属性(如类应该是)。

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

相关内容

  • 没有找到相关文章

最新更新