доступ к существующему экземпляру с состоянием внутри без сохранения состояния, Java 6 - PullRequest
4 голосов
/ 22 февраля 2012

Возможно ли получить доступ к сессионному компоненту с сохранением состояния внутри компонента без сохранения состояния?

Моя проблема в том, что у меня есть сессионный компонент, называемый Пользователь, и я хочу получить доступ к пользовательской информации внутри компонента без состояния ...

Я пытаюсь так:

Ejb Side:

@Stateless
public class OfferManagerBean implements OfferManagerLocal, OfferManager
{
    @Resource 
    private SessionContext context;
    @EJB
    private ro.project.ejb.interfaces.User user;
    public String getUsername()
    {
        user = (ro.project.ejb.interfaces.User) context.lookup("java:global/project/projectEJB/User!ro.project.ejb.interfaces.User");
        return user.getUsername();
}

Клиентская сторона

 User user = (User) ctx.lookup("java:global/project/projectEJB/User!ro.project.ejb.interfaces.User");
 user.setUsername("Alex");

 OfferManager offerManager = (OfferManager) ctx.lookup("java:global/project/projectEJB/OfferManagerBean!ro.project.ejb.interfaces.OfferManager");
 assertEquals(offerManager.getUsername(), "Alex");

Результат этого теста: java.lang.AssertionError: expected:<null> but was:<Alex>

это не удается .. Кажется, что то, как я запрашиваю компонент с состоянием, возвращает мне новый экземпляр ...

  1. Я знаю, почему это не работает. Потому что мой тест не пройден: P. Я получаю новый экземпляр ..
  2. Я хочу проверить определенные разрешения вошедшего в систему пользователя в EJB, потому что я не хочу рассчитывать на стороне клиента, потому что я могу ошибиться или я скажу другим разработчикам сделать графический интерфейс для моего проекта.
  3. Я не хочу использовать Java EE Security, потому что я не знаю, как выполнить вход в приложение RCP
  4. Мой главный вопрос: как я могу получить доступ к сессионному компоненту (тот же, что у клиента) внутри EJB ... возможно ли это? И как?

Я спрашиваю почти то же самое, что спрашивает этот парень: Концепция многоразового сеанса входа в систему в вызовах rmi ejb

Я хочу сделать это, но не с JAAS ...

Заранее спасибо

Ответы [ 4 ]

10 голосов
/ 22 февраля 2012

Вы должны никогда вводить компонент @Stateful (SFSB) в компонент @Stateless (SLSB).SFSB живет до тех пор, пока живет его клиент (клиент является экземпляром, в который был введен SFSB, который в данном случае является самим SLSB).SLSB, однако, предназначены для без сохранения состояния , и большинство контейнеров имеют их в пуле.Таким образом, всякий раз, когда SLSB возвращается в пул после использования, он будет повторно использоваться полностью в другом месте, но он содержит тот же экземпляр SFSB, как и при создании SLSB в первый раз!Это может привести к нежелательным результатам.

Кроме того, каждый раз, когда вы получаете SFSB от JNDI, вы получаете совершенно новый экземпляр, который отличается от SLSB , а не , доступный для других пользователей.,Клиент SFSB - это текущий экземпляр класса клиента, в котором вы получили SFSB от JNDI.Вы должны сами удерживать этот экземпляр и повторно использовать тот же самый экземпляр до тех пор, пока не завершите выполнение транзакции с ним.Один из способов - сохранить его в сеансе HTTP самостоятельно или в управляемом компоненте области сеанса используемой вами инфраструктуры MVC.

Функциональные требования мне не совсем понятны, поэтому трудно датьподходящий ответ, как решить вашу конкретную проблему, но у меня сложилось впечатление, что вам на самом деле необходимо хранить пользователя в сеансе HTTP, а не в SFSB.Наиболее распространенная ошибка новичка в отношении сессионных компонентов заключается в том, что они неправильно интерпретируют «сессию» в контексте EJB как сессию HTTP.

См. Также этот связанный ответ на вопрос того же рода для получения дополнительной информации.подробное объяснение: bean-объект области действия запроса JSF продолжает воссоздавать новые сессионные bean-компоненты Stateful при каждом запросе? Согласно истории ваших вопросов вы знакомы с JSF, поэтому этот ответ должен быть легко понятным.

3 голосов
/ 22 февраля 2012

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

Но то, что вы пытаетесь, не может работать.Причина в том, что оба, иждивенец-инжекция (@EJB) и поиск (ctx.lookup ...) гарантированно вызывают newInstance, и, как следствие, у вас будет новый экземпляр.

Это объясняется в спецификации следующими словами:

Жизнь экземпляра сессионного компонента начинается, когда клиент получает ссылку на экземпляр сессионного компонента с сохранением состояния посредством внедрения зависимостей или поиска JNDI, или когда клиент вызывает метод create на домашнем интерфейсе сессионного компонента.Это заставляет контейнер вызывать newInstance для класса сессионного компонента для создания нового экземпляра сессионного компонента.

2 голосов
/ 23 февраля 2012

На случай, если другие уже не достаточно ясно: вы делаете это неправильно!;)

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

Различные компоненты, которые вы получаете из этогоконтекст не разделяют какой-либо общий сеанс.В EJB бины не хранятся в сеансе EJB, но они являются ЭТОМ сеансом.

Другими словами, InitialContext (ctx в вашем коде) НЕ является эквивалентностью EJB для HttpSession.

Возможно, еще хуже то, что в вашем коде пользователь является EJB-компонентом.Это НЕПРАВИЛЬНО.

Пользователь - существительное в вашем приложении.Они представлены сущностями JPA или простыми «нормальными» Java-бинами.EJB-компоненты предназначены для реализации в вашем приложении глаголов : служб, DAO, репозиториев и т. Д.

Предполагается, что состояние в сессионных компонентах с сохранением состояния будет удерживать данные модели во время бизнес-процесса (длякэширование, блокировка, резервирование и т. д.).Ни в коем случае это состояние не должно быть данными модели.

Мой совет: оставьте свой текущий «дизайн».Не пытайтесь это исправить, не пытайтесь оправдать это.Отпусти, удали свой код, не оглядывайся назад.Прочитайте несколько хороших книг о EJB и начните все сначала.

Удачи!

1 голос
/ 10 мая 2012

Я не проверяю, правильно ли вы поступаете с SFSB и SLSB. Но ниже ответ на вашу проблему

Вариант 1: из вашего сервлета выполните поиск JNDI для SFSB. Это должно быть один раз. Сохраните возвращенную ссылку SFSB в вашей HttpSession. Когда вы вызываете метод SLSB, которому нужен экземпляр SFSB для хранения пользовательских данных, передайте вышеуказанный эталонный объект SFSB в качестве параметра методу SLSB. Затем получите доступ к нему из метода SLSB и сохраните пользовательские данные.

Проблема с вариантом 1: вы связываете свой механизм персистентности (SFSB) с кодом UI (поскольку вы сохраняете его в HttpSession и передаете его). Завтра, если вы захотите перейти на другой механизм персистентности, такой как кеш, вам нужно будет много переделать. Опять же, если вы хотите представить свой метод SLSB как WebService, вы не сможете этого сделать, поскольку не можете xml-ize ссылки на объект SFSB. Короче, плохой вариант.

Вариант 2: иметь статическую хэш-карту в некотором классе бизнес-уровня. Предположим, у вас есть несколько уникальных атрибутов транзакции для каждой транзакции, что-то вроде идентификатора. Когда вы начинаете транзакцию, со своего бизнес-уровня создайте SFSB, сохраните ее ссылку в статической хэш-карте с идентификатором в качестве ключа. Когда вы вызываете метод обслуживания SLSB, передайте этот идентификатор (я предполагаю, что каждая транзакция может иметь уникальный идентификатор). Из метода SLSB используйте идентификатор для поиска ссылки SFSB, хранящейся в статической хэш-карте. Используйте его для хранения. В этом случае ваш пользовательский интерфейс и SFSB не связаны. Завтра, если вы хотите изменить свой механизм персистентности, вы можете обойтись без влияния на клиентов, так как ваши изменения будут ограничены на уровне BC.

...