【问题标题】:Changing a static field using reflection inside ear使用耳内反射改变静态场
【发布时间】:2018-05-09 07:47:00
【问题描述】:

一个 EAR 包含 2 个 WAR(WAR1、WAR2)这两个 WAR 都有一个依赖项 jar(JAR1)。

JAR1 有一个类 (CLASS1),其中有一个静态字段 private String STATIC1 = "DEFAULT_VAL";,它适用于 WAR2,但 不适用于 WAR1。所以我在 WAR1 中添加了一个服务来修改它:

@Service
public class ModService {
    @PostConstruct
    public void modMyVal() {
        Field declaredField = CLASS1.class.getDeclaredField("STATIC1");
        declaredField.setAccessible(true);
        declaredField.set(this, "NEW_VAL_FOR_WAR1");
    }
}

令我惊讶的是,在 WAR2 中一切正常。我期待 WAR2 有 NEW_VAL_FOR_WAR1。两个 WAR 都加载在同一个 ear、jvm、server 中——它们都依赖于同一个 jar。 WAR2 的静态字段如何没有更改?

其他几个指针:

  • Jar1 由第 3 方提供,因此无法控制来源。
  • Jar1 位于 WAR1/WEB-INF/lib 和 WAR2/WEB-INF/lib 中
  • 服务器是 weblogic。
  • 我很高兴它成功了:)。但很好奇它在内部是如何运作的,以及是什么让我的一天变得更好。

【问题讨论】:

    标签: java spring reflection


    【解决方案1】:

    两个 WAR 都有自己的类加载器。为每个 WAR 从 JAR 加载一次类会为您提供 2 个 Class 实例,因此您的 WAR 可以看到成员变量的“它们的版本”,而不是像您预期的那样共享状态。

    你也可以想象这种黑客行为会导致什么样的错误,所以我会避免养成这种习惯。

    【讨论】:

    • 第一行说明了一切,谢谢。至于不使用它的建议:已采纳建议,这将是暂时的,直到第 3 方提供动态加载它的钩子。
    【解决方案2】:

    Tomcat 使用不同的WebAppClassLoader 来加载不同的 webapp 上下文。也就是说,WAR1 中的类与 WAR2 中的类不同,尽管它们具有相同的包和类名。

    所以 WAR1 中的 CLASS1.class 与 WAR2 中的 CLASS1.class 不同。当然,在WAR1.CLASS1中设置字段不会影响WAR2.CLASS1。

    【讨论】:

    • 这确实不适用于问题。 EAR 档案不会部署到 Web 容器中。随之而来的是 Tomcat 必须隔离类加载器,因为没有 2 个 WAR 会成为同一个应用程序的一部分……
    • 在我的情况下它是 weblogic 但我想它在这里也适用。让我感到困惑的是.. 因为我将 war1 和 war2 组合到一个耳朵中然后部署,所以假设两场战争只有一个类加载器。
    • @AnandRockzz 对。但是,当您探索应用程序服务器时要小心……Web 模块的类加载器隔离只是默认设置。一些应用服务器允许你重新配置,以便 WAR 将首先搜索父类的类加载器(这样 ear/lib 中的类实际上可能由 2 个 Web 模块共享)
    • 如果只有一个classloader,那么webbapp1的状态变化会影响webapp2。例如,如果我们使用jpa,那么webapp1和webapp2都使用相同的entityManager,这样会很危险:)
    • 这是一个很好的观点,我会试着把罐子移到耳朵里看看会发生什么......这也是暂时的,一旦我们升级罐子就会摆脱这一切。
    猜你喜欢
    • 2010-10-20
    • 1970-01-01
    • 1970-01-01
    • 2012-08-08
    • 1970-01-01
    • 2011-03-19
    相关资源
    最近更新 更多