Компонент JSF в области запросов продолжает воссоздавать новые сеансовые компоненты с сохранением состояния при каждом запросе? - PullRequest
32 голосов
/ 17 января 2012

Я создаю свое первое приложение Java EE с использованием JSF, PrimeFaces, Glassfish и Netbeans.Поскольку я новичок, возможно, я неправильно подхожу к основной проблеме.

Основная проблема: я хочу защищать информацию пользователя.Кажется, существуют противоречивые идеи о том, следует ли поддерживать его в сессионном компоненте JSF или в EJB с сохранением состояния.Я пытаюсь использовать сессионный EJB с сохранением состояния, потому что таким образом он более безопасен.

Проблема в том, что мое приложение, похоже, создает несколько экземпляров этого компонента, когда я ожидаю, что оно создаст его и повторно используетЭто.Если я обновляю страницу, она запускается @PostConstruct и @PostActivate 3 раза, все они с разными экземплярами.Затем они все разрушаются, когда я повторно развернуть приложение.

Я неправильно понял, как это должно работать, или что-то неправильно настроено?

Я попытаюсь показать урезанный пример кода:

basic.xhtml:

<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:h="http://java.sun.com/jsf/html"
      xmlns:c="http://java.sun.com/jsp/jstl/core">
    <h:head>
        <title>Facelet Title</title>
    </h:head>
    <h:body>
        Hello from Facelets
        <c:if test="#{loginController.authenticated}">
            Authenticated
        </c:if>
        <c:if test="#{loginController.authenticated}">
            Authenticated
        </c:if>
        <c:if test="#{loginController.authenticated}">
            Authenticated
        </c:if>
    </h:body>
</html>

LoginController:

@Named(value = "loginController")
@RequestScoped
public class LoginController implements Serializable {

    @EJB
    private UserBeanLocal userBean;

    public boolean isAuthenticated() {
        return userBean.isAuthenticated();
    }

}

UserBean (исключая UserBeanLocal интерфейс)

@Stateful
public class UserBean implements UserBeanLocal, Serializable {

    boolean authenticated = false;

    @PostConstruct
    @PostActivate
    public void setup(){
        System.out.println("##### Create user Bean: "+this.toString());
    }

    @Override
    public boolean isAuthenticated() {
        System.out.println("########## Authentication test is automatically passing.");
        authenticated = true;//hard coded for simplicity.
        return authenticated;
    }     

    @PrePassivate
    @PreDestroy
    public void cleanup(){
        System.out.println("##### Destroy user Bean");
    }

}

Наконец, вот вывод Glassfish после трехкратного обновления:

INFO: ##### Create user Bean: boundary._UserBean_Serializable@2e644784
INFO: ########## Authentication test is automatically passing.
INFO: ########## Authentication test is automatically passing.
INFO: ########## Authentication test is automatically passing.
INFO: ##### Create user Bean: boundary._UserBean_Serializable@691ae9e7
INFO: ########## Authentication test is automatically passing.
INFO: ########## Authentication test is automatically passing.
INFO: ########## Authentication test is automatically passing.
INFO: ##### Create user Bean: boundary._UserBean_Serializable@391115ac
INFO: ########## Authentication test is automatically passing.
INFO: ########## Authentication test is automatically passing.
INFO: ########## Authentication test is automatically passing.

Ответы [ 2 ]

58 голосов
/ 17 января 2012

Сессионные компоненты с состоянием (SFSB) не совсем то, что вы думаете.Вы, кажется, думаете, что они ведут себя как-то как бины JSF, управляемые сессионной областью.Это неправда.Термин «сессия» в EJB-компонентах имеет совершенно другое значение, чем HTTP-сессия, которую вы имели в виду.

«Сеанс» в EJB-компонентах должен интерпретироваться в транзакционном контексте.Транзакция (в основном, сеанс БД) живет в случае SFSB до тех пор, пока живет клиент.Клиент SFSB в вашем конкретном примере не веб-браузер, но сам экземпляр управляемого JSF-компонента, именно тот, в который был введен SFSB.Поскольку вы поместили управляемый компонент JSF в область запроса, SFSB будет воссоздан при каждом HTTP-запросе вместе с управляемым компонентом JSF.

В качестве примера попробуйте поместить управляемый компонент JSF в область представления.,Например, область просмотра полезна для многошаговой формы на той же странице.Каждый раз, когда представление выполняет обратную передачу к себе, один и тот же экземпляр управляемого JSF-компонента будет использоваться повторно, и этот экземпляр дает вам доступ к тому же тому же -м экземпляру SFSB, как и при создании компонента, то есть не поделился в другом месте.Транзакция SFSB живет до тех пор, пока живет клиент (управляемый компонент JSF в области представления).

Сессионный компонент без сохранения состояния (SLSB) может совместно использоваться в другом месте, но это не должно иметь значения, так как предполагается, что его обрабатывают как без гражданства в любом случае.Эта «функция» экономит время и память контейнера для их создания и хранения.Контейнер может просто иметь их пул.Более того, экземпляр SLSB, который был внедрен в управляемый компонент JSF вида, сеанса или области приложения, не обязательно должен ссылаться на один и тот же экземпляр в каждом HTTP-запросе, как это было при создании управляемого компонента JSF.Это может быть даже совершенно другой экземпляр, в зависимости от доступных экземпляров в пуле контейнера.Транзакция живет (по умолчанию) столько, сколько один вызов метода на SLSB.

Тем не менее, SFSB не подходит для вашего конкретного случая «запоминания вошедшего в систему пользователя».То, что это «более безопасно», не имеет никакого смысла.Просто поместите управляемый компонент JSF в область действия сеанса и дайте ему самостоятельно запомнить зарегистрированного пользователя и используйте SLSB для выполнения любых бизнес-действий (например, взаимодействия с БД) и используйте SFSB только тогда, когда вы хотите real сессионный компонент с сохранением состояния (я предполагаю, что вы сейчас понимаете, что именно они :)).

См. также:

2 голосов
/ 16 июля 2013

Насколько я понимаю из моего исследования и использования, EJB SFSB бесполезен для веб-приложений, так как JSF, Spring предоставляет скрытую аннотацию для сохранения сеанса для пользователя.Но в случае, когда приложение, требующее вызова метода webservice и вызова RPC-метода, работает, EJB SFSB необходим для сохранения сеанса (перехода) для каждого пользователя.

...