我很确定finalize在后来的JVM上仍然是个坏消息 - 还有其他选择吗?

时间:2011-03-19 01:22:00

标签: java orm finalization

我想实现一个ORM风格的系统,当调用者无法再访问POJO时,它可以保存更新。

我认为引用类可以做到这一点,但它们似乎只在对象被清除后才将对引用入队(我希望它们能够被收集),所以一旦将.get()方法排入队列将始终返回null。

我可以使用终结器但是上次我检查那些是有问题的(不保证会立即运行或者根本不运行) - 我相信终结器和runShutdownHook()的组合可以工作但是进入相当沼泽的领域。 / p>

除了强制性的“还有其他路径,我还没有想到”只要让呼叫者调用.save(),当他完成时?“

4 个答案:

答案 0 :(得分:1)

使用Observer Pattern来构建一个ClearanceManager和一些Destroyables。 IDestroyable是一个接口,用于包含方法public void destroy()的观察者 ClearanceManager是Observerpattern的主题。也许在这里使用Singleton来确保您的应用程序中只有一个ClearanceManager对象。

在ClearanceManager中使用Set internaly(不是List,以确保只能添加​​一次对象)

支持addDestroyable(IDestroyable destoryable)方法(也许是removeDestroyable方法)。

在运行时期间,您需要进行一些析构函数仿真的类可以在ClearenceManager中自行注册。 。ClearenceManager.getInstance()addDestroyable(本);

ClearanceManager有一个doClearance()方法,只能在Main方法的末尾调用。它迭代抛出私有Set并在每个IDestroyable对象上调用destroy()。

这样做你可以模仿析构函数,而不使用它们,因为使用析构函数你会失去对myabe所需对象的存在的控制。 你不知道什么时候覆盖finalize,什么时候调用它。

也许,如果你不想在你的Main方法中调用doClearance(),你可以在这里使用,但就在这里,一个真正的析构函数finalize()。因为ClearenceManager中有对所需对象的引用,所以它们不会被首先销毁。但也许嗯,如果有交叉引用....更好不要使用finalize,使用doClearance()并享受它的乐趣:)

答案 1 :(得分:1)

我认为你在这里咆哮错误的树。

基于可达性的所有Java的终结器和引用机制都依赖于垃圾收集器来确定相应的对象是否可访问。因此,如果您使用任何参考机制进行某种最终化,那么您会遇到使finalize成为一个坏主意的相同问题。

技术上可以实现自己的可达性机制;例如通过实现自己的特定于应用程序的引用计数。但是,它很可能是昂贵的,脆弱的,并使您的代码看起来很糟糕。 (Java中的引用计数可能比C ++中更复杂,更脆弱,因为您不能重载引用赋值运算符以确保引用计数透明调整。因此每个引用赋值都需要包含在方法调用中。)所以我会说,做自己的可达性分析是一个坏主意

所以,为了实用,你需要:

  • 重新考虑您的设计,以便您不会根据可达性或
  • 执行操作
  • 忍受使用finalize的后果。

第一种选择显然是最好的,IMO。

答案 2 :(得分:1)

您是否只是想避免在您修改的每个POJO上拨打save()

这可以使用持久性会话对象可靠地完成,如下所示:

  1. 打开一个新的会话对象。
  2. 通过会话对象加载对象。会话对象维护对它加载的所有对象的引用。
  3. 对加载的对象进行任何更改。没有必要在更新的对象上调用save方法。
  4. 关闭会话对象。会话保存其所有对象。它甚至可能足以保留干净加载数据的副本,将其所有对象与干净数据进行比较,并仅保存已修改的数据。
  5. 如果您不想通过代码传递会话对象,可以使用工作单元模式更进一步,将会话对象与当前线程相关联:

    1. 开始一个工作单元。这会在幕后创建一个会话对象,并将其与当前线程相关联。
    2. 加载对象。无论何时加载对象,ORM都会根据当前线程自动将其与会话对象关联。
    3. 对加载的对象进行任何更改。没有必要在更新的对象上调用save方法。
    4. 完成工作单元。这将关闭会话对象,保存所有对象。
    5. 这解决了基于可达性的解决方案的几个问题:

      • 您不依赖于非确定性垃圾收集,这些垃圾收集可能在运行之间有很长时间,或者根本不运行。
      • 一次操作中修改的所有对象都保存在一起。如果依赖于可达性,则在同一操作中修改的不同对象可能在不同时间无法访问,这意味着您的修改可以按位进行保存到数据库中。
      • 回滚更容易 - 只需为会话对象提供rollback()方法即可。使用可达性解决方案,如果操作失败,您需要记住在每个修改过的POJO上调用rollback(),这与原始问题完全相同。

      或许可以查看http://nhibernate.info/doc/patternsandpractices/nhibernate-and-the-unit-of-work-pattern.html或研究工作单元模式并模仿其中的一些想法。

答案 3 :(得分:0)

也许您可以将PhantomReference子类化,并将必要的数据存储在其中以进行最终操作。