【问题标题】:Modifying Java classes at runtime to make instance fields transient -- will it work?在运行时修改 Java 类以使实例字段瞬态——它会起作用吗?
【发布时间】:2010-01-15 23:13:33
【问题描述】:

每当我们使 HTTPSession 具有不可序列化的对象(我们不关心但会污染我们的日志)时使 HTTPSession 无效时,我们都会收到一条来自 Weblogic 的烦人的日志消息。调整我们的 log4j 配置以不记录此消息似乎不是一个选项(消息来自通用 Weblogic 类,我们不想抑制来自此类的所有消息,除了编写我们自己的适配器来查看消息被写入日志并抑制反序列化错误消息我不知道我们将如何通过 log4j 配置来做到这一点)。

为了临时解决这个问题以清理我们的日志,我想拦截将对象添加到 HTTP 会话的调用,以便正在添加的对象的类(以及其对象图中的任何对象)更改其实例变量声明到瞬态。想我会通过添加 HTTPSesssionEventListener 来拦截调用,然后使用反射库修改类的实例变量。

有人知道这是否可行吗?

【问题讨论】:

  • 您需要在线查看您的日志吗?
  • 似乎是一个可怕的黑客来抑制有效警告。
  • 对于我们的目的而言,它不是一个有效的错误(weblogic 选择在 ERROR 日志级别记录它——当您不复制会话或不关心您的对象不可序列化时,ERROR 级别是不合适的。如果它是可配置的,或者它们会根据您是否正在执行诸如复制会话之类的事情(然后让您的对象可序列化很重要)来改变日志级别,那就太好了。
  • 一个有效的错误,你的应用程序应该被设计成可分发的。解决真正的问题。
  • IIRC,规范要求存储在会话中的对象是可序列化的。

标签: java session weblogic


【解决方案1】:

有没有人有更好的建议和/或知道这是否会/不会像我想要的那样工作?

是的。 按照规范构建!

符合 Java Servlet 规范:

分布式 servlet 容器必须抛出一个IllegalArgumentException 对于容器不能支持必要机制的对象 迁移存储它们的会话。

因此,如果您想避免此消息(并编写良好的可移植和可分发代码),只需使您放入 HttpSession 的对象实现 Serializable 接口即可。

说真的,我不敢相信您正在考虑解决实际问题而不是解决问题的解决方案。

【讨论】:

  • 我没有写这个代码,我继承了它。这是一个临时修复,并不打算成为真正的修复。计划是尽可能快地逐步修复应用程序,但我们现在需要清理日志,以便我们可以更好地调试其他生产错误。
  • 此外,用一个像样的 IDE 添加“Serializable”有多难?可能需要多长时间 - 也许一天的努力?破解将比修复花费更长的时间。来自我的 +1。
  • +1 - 临时 hack 修复是个坏主意。只需正确修复即可。
【解决方案2】:

如果是一个选项

tail -f yourlog | grep -v "annoying line here" > cleanLogFile

这样的干扰要小得多。但是会创建第二个文件。

我这样做是为了一个项目,我需要跟踪一个特定的问题以及中间出现的所有那些愚蠢的消息。

【讨论】:

  • @stamp31sd:我很高兴。那么,我的答案会被标记为已接受吗? (你知道那边的绿色很厚:P)
【解决方案3】:

为什么要这么麻烦?将它们全部标记为可序列化听起来很容易,只要所有有问题的对象都是您的。

如果这不可能,.a另一种方法是在您的 webApp 中注册一个实现 HttpSessionAttributeListener 的类。在 attributeAdded 方法中打印 sessionID,然后序列化 session 数据:

public void attributeAdded(HttpSessionBindingEvent hsbe)
{
    // Handle the details yourself here.
    ObjectOutputStream.writeObject(hsbe.getValue())
}

【讨论】:

  • 试图绕过类(有数百个类将它们标记为可序列化,并将其对象图中的任何其他对象标记为可序列化
【解决方案4】:

尝试修改ObjectOutputStream,而不是序列化对象。

如果你扩展ObjectOutputStream,你可以重写replaceObject方法并清除不可序列化的字段或重新创建没有不可序列化属性的对象。

另一种选择是使用反射来取消会话对象的不可序列化字段,但这是非常危险的,因为会话对象可能被加载回来并看起来可以工作,但随后会在几小时甚至几个月后抛出 NullPointerException (当最终引用您无效的字段时。)

修改类可能不起作用。

可以扩展 ClassLoader 并调整实例字段上的标志,但是:

  • 如果是您的类包含不可序列化的字段,那么您自己更改代码以使其成为瞬态会更简单
  • 如果它不是您的类,那么它将由与您的应用程序类不同的ClassLoader 加载,因此当您看到该对象时为时已晚(因为该类已经加载。)

您不能在单个对象上设置transient 标志,只能在一个类上。

【讨论】:

  • 是应用服务器在做序列化。
猜你喜欢
  • 1970-01-01
  • 2017-09-03
  • 2011-01-16
  • 2012-04-18
  • 2011-06-01
  • 2019-02-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多