Чистый код, сеанс без состояния beans и личное состояние

Согласно чистому коде Роберту Мартину, методы должны иметь небольшую подпись. Лучшим случаем был бы метод без каких-либо параметров. Вместо этого рекомендуется использовать переменные состояния. Это действительно полезно. Но как насчет сессии без состояния beans?

Название немного путано, потому что SLSB может иметь состояние. Вам просто нужно сделать свое хозяйство, чтобы вы не использовали состояние из предыдущего вызова EJB.

Возвращаясь к чистому коду: я бы тоже хотел использовать переменные экземпляра в SLSB. Это прекрасно работает, и если вы достаточно осторожны, у вас нет проблем с несогласованностью состояния, поскольку состояние перезаписывается при каждом вызове публичного метода.

Пока все хорошо. Но что произойдет, если используемый bean вернется в пул? Он берет свое государство с этим. В зависимости от размера состояния это может быть реальной утечкой памяти. JBoss очень щедрый с beans и генерирует довольно много из них, что вызывает некоторое серьезное потребление памяти - ни для чего.

Таким образом, одним из способов было бы очистить состояние до того, как будет существовать метод bean, и bean будет возвращен в пул. Но это кажется мне ненужным кодом, которого следует избегать.

Есть ли способ справиться с этой проблемой? Какая наилучшая практика в этой ситуации?

Ответ 1

Держите жизнь простой, просто передайте параметры. Даже если вы можете сделать иначе, это очевидно из-за намерения EJB без гражданства, вы не должны.

FWIW, стремящийся к цели нулевых параметров, кажется мне глупым. Направляйте немного, да, но стремление к нулю для себя - просто глупо.

Ответ 2

в соответствии с чистым кодом Робертом К. Мартином методы должны иметь маленькая подпись.

Обычно я предпочитаю передавать (передавать объекты) в качестве аргументов, таким образом я могу изменить то, что я передаю, не влияя на подпись метода.

Кроме того, я бы предпочел передать интерфейс, а не фактический базовый класс.

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

Где IMyTransferObject - это интерфейс

interface IMyTransferObject {
   ...
}

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

Лучшим случаем был бы метод без каких-либо параметров. Вместо этого рекомендуется использовать переменные состояния. Это действительно полезно. Но как насчет сессии без состояния beans?

Этого нельзя придерживаться религиозно, и на самом деле нет причин для этого.

Ответ 3

Из http://docs.oracle.com/javaee/6/tutorial/doc/gipjg.html:

Безстоящий сеанс Beans

Сеанс без состояния bean не поддерживает диалоговое состояние с клиентом. Когда клиент вызывает методы безстоящих bean, переменные экземпляра bean s могут содержать состояние, специфичное для этого клиента, но только на время призывание. Когда метод завершен, состояние, специфичное для клиента не следует сохранять. Однако клиенты могут изменять состояние переменные экземпляра в объединенном состоянии без состояния beans, и это состояние сохраняется до следующего вызова объединенного апатрида 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", где у вас все чисто и без параметров.

Ответ 4

Совершенно возможно сохранить переменные экземпляра в SLSB, так как вы не используете прокси-сервер для совершения вызовов между методами. Например:

@Stateless 
public class MyEJB {
    private String var;

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

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

Дело в том, что когда вы вводите этот SLSB в другой, любой вызов метода будет проходить через прокси-сервер для достижения фактического EJB. Итак, учитывая, что реальный экземпляр извлекается из пула при вызове метода на экземпляр прокси-сервера, нет гарантии, что прокси-сервер будет использовать один и тот же объединенный экземпляр между двумя или более вызовами. Таким образом, невозможно гарантировать значение любого объявленного атрибута класса.

Когда SLSB возвращается в пул, он берет с собой каждое настроенное значение (я думаю, он может измениться в зависимости от поставщика, я не уверен). Но вполне возможно (и приемлемо), чтобы объединенный экземпляр SLSB уже имел ранее настроенное значение атрибута.

Я не понял ваш смысл здесь:

Пока все хорошо. Но что произойдет, если используемый bean вернется в пул? Он берет свое государство с этим. В зависимости от размера состояния это может стать настоящей утечкой памяти. JBoss очень щедрый с beans и генерирует довольно много из них, вызывая некоторую серьезную память потребление - ни за что.

Есть ли у вас пример "большого состояния", который вы могли бы иметь в SLSB?

И наконец:

Я думаю, что лучший способ обработки значений - это всегда переменные состояния дескриптора, которые вы будете использовать. Установка перед и очистка после использования. И лучшая практика - избегать такой запутанной ситуации.

Надеюсь, что это поможет.