【问题标题】:Clean code, stateless session beans and private state干净的代码、无状态会话 bean 和私有状态
【发布时间】:2012-04-24 14:03:35
【问题描述】:

根据 Robert C. Martin 的 clean code 方法应该有一个小的签名。最好的情况是完全没有参数的方法。相反,建议使用状态变量。这真的很有用。但是无状态会话 bean 呢?

这个名字有点令人困惑,因为 SLSB 可以有状态。你只需要做你的家务,这样你就不会使用上一个 EJB 调用中的状态。

回到干净的代码:我也喜欢在 SLSB 中使用实例变量。这很好用,如果你足够小心,你不会遇到任何状态不一致的问题,因为状态在每个公共方法调用上都会被覆盖。

到目前为止一切顺利。但是如果一个用过的 bean 回到池中会发生什么?它带着它的状态。根据状态的大小,这可能是真正的内存泄漏。 JBoss 对 bean 非常慷慨,并生成了相当多的 bean,导致严重的内存消耗 - 没有任何意义。

所以一种方法是在 bean 方法存在并将 bean 返回到池之前清理状态。但在我看来,这似乎是应该避免的无用代码。

有没有合适的方法来处理这个问题?在这种情况下,最佳做法是什么?

【问题讨论】:

  • 任何 DIY 方法维护的状态在集群面前都会失败,所以 JEE 不欢迎。并且为每个 bean 维护该状态的副本对我来说似乎也是错误的。

标签: java coding-style ejb-3.0 java-ee-6 ejb-3.1


【解决方案1】:

将实例变量保存在 SLSB 中是完美的,因为您不使用代理在方法之间进行调用。例如:

@Stateless 
public class MyEJB {
    private String myVar;

    public void receiveVar(String myVar) {
        this.myVar = myVar;
        useVar();
    }

    private void useVar() {
        // do something with var
    }
}

重点是:当你把这个 SLSB 注入另一个时,任何方法调用都会通过代理来实现实际的 EJB。因此,考虑到在代理实例上调用方法时会从池中检索真实实例,因此不能保证代理在两次或多次调用之间会使用相同的池化实例。所以不可能确保任何声明的类属性的值。

当 SLSB 回到池中时,它会带走每个设置的值(我认为它可能会根据供应商而改变,我不太确定)。但是,池化 SLSB 实例完全有可能(并且可以接受)已经具有先前配置的属性值。

我没明白你的意思:

到目前为止一切顺利。但是如果一个用过的 bean 回到池中会发生什么? 它带着它的状态。根据州的大小,这 可能是真正的内存泄漏。 JBoss 对 bean 和 产生相当多的东西,导致一些严重的记忆 消费——白费。

您有任何可以在 SLSB 中使用的“大状态”示例吗?

最后:

我认为处理值的最佳方式始终是处理您将使用的状态变量。使用前设置和使用后清洁。最好的做法是避免这种令人困惑的情况。

希望对你有帮助。

【讨论】:

    【解决方案2】:

    保持简单,只需传入参数。即使您可以采取其他方式,但从无状态 EJB 的意图来看,您不应该

    以零参数为目标的 FWIW 对我来说似乎很愚蠢。瞄准少数,是的,但为了自己的利益而努力为零是愚蠢的。

    【讨论】:

    • 实际上我注意到零参数方法非常教条。但我喜欢使用最多 2 个参数。我发现具有两个以上参数的方法更难阅读和维护。从 OO 模型来看,如果内聚度很高,则使用状态变量非常有意义。
    • 这一切都很好,但是退后一步,让我们承认您正在谈论将个人外观偏好与 添加状态 放在真正明显的 上无状态bean。您需要平衡 OO 原则,而不是盲目地偏爱它们。
    • 顺便说一句,对于一个恰好不同意你似乎想要采取行动的方向的真实意见,投反对票似乎很苛刻?
    • 很抱歉 :-)
    【解决方案3】:

    根据 Robert C. Martin 的 clean code 方法应该有一个 小签名。

    通常我更喜欢传入(传输对象)作为参数,这样我可以更改我传入的内容而不影响方法签名。

    另外,我更喜欢传入接口,而不是实际的基类。

    public void doSomething(IMyTransferObject arg){
     ...
    }
    

    IMyTransferObject 是一个接口

    interface IMyTransferObject {
       ...
    }
    
    class TransferObject implements IMyTransferObject{
      private String name;
      private String game;
      ... accessor / mutator
    }
    

    最好的情况是完全没有参数的方法。取而代之的是 建议使用状态变量。这真的很有用。但 无状态会话 bean 呢?

    这不能虔诚地遵循,真的没有理由这样做。

    【讨论】:

    • 内部私有方法的代码很多 :) 其实我说的是 SLSB 内部的私有方法。
    【解决方案4】:

    来自http://docs.oracle.com/javaee/6/tutorial/doc/gipjg.html

    无状态会话 Bean

    无状态会话 bean 不维护 与客户的对话状态。当客户端调用 无状态 bean 的方法,bean 的实例变量可能包含 特定于该客户的状态,但仅在 调用。当方法完成时,客户端特定的状态 不应保留。但是,客户可以更改 池化无状态 bean 中的实例变量,并且此状态被保存 转到池化无状态 bean 的下一次调用。除了 在方法调用期间,无状态 bean 的所有实例都是 等效,允许 EJB 容器将实例分配给任何 客户。也就是说,无状态会话 bean 的状态应该适用 跨所有客户。

    我不是 EE 方面的专家,但在我看来,技术上也允许按照您的计划使用字段。

    我假设您必须确保每次调用新方法时,实例字段都会使用新数据进行更新,我认为您应该确保您在方法结束后删除引用,以确保您不会仅仅因为它们在某些仍保留在某个池中的“旧”bean 中被引用而阻止旧对象的垃圾收集。

    我会建议这样的模式:

    public class MyBean{
    
      private SomeClass firstObject;
      private SomeOtherClass anotherObject;
      private AndAnotherClass thirdObject;
    
      public void theMethod(firstObject, anotherObject, thirdObject){
        try {
          this.firstObject = firstObject;
          this.anotherObject = anotherObject;
          this.third = thirdObject;
    
          startProcessing();
    
        }finally {
          this.firstObject = null;
          this.anotherObject = null;
          this.third = null;
        }
      }
    
      private void startProcessing() {
        doStep1();
        doStep2();
        doStep3();
      }
    
      [...]
    }
    

    仍然有很多代码 - 但如果您始终坚持这种风格,您会自动跳过“theMethod”部分并继续阅读“startProcessing”,在那里您可以清楚地获得所有内容并且没有参数。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-03-31
      • 2013-08-02
      相关资源
      最近更新 更多