как здесь экземпляр bean-компонента @RequestScoped предоставляется bean-компоненту @SessionScoped во время выполнения?

Я читаю этот пример в JBoss, где bean-компонент @RequestScoped, резервный JSF page, используется для передачи учетных данных пользователя, которые затем сохраняются в файле @sessionScoped bean. Вот пример из документов JBoss.

@Named @RequestScoped
public class Credentials {
    private String username;
    private String password;
    @NotNull @Length(min=3, max=25)
    public String getUsername() { return username; }
    public void setUsername(String username) { this.username = username; }
    @NotNull @Length(min=6, max=20)
    public String getPassword() { return password; }
    public void setPassword(String password) { this.password = password; }
}

JSF-форма:

<h:form>
   <h:panelGrid columns="2" rendered="#{!login.loggedIn}">
      <f:validateBean>
         <h:outputLabel for="username">Username:</h:outputLabel>
         <h:inputText id="username" value="#{credentials.username}"/>
         <h:outputLabel for="password">Password:</h:outputLabel>
         <h:inputSecret id="password" value="#{credentials.password}"/>
      </f:validateBean>
   </h:panelGrid>
   <h:commandButton value="Login" action="#{login.login}" rendered="#{!login.loggedIn}"/>
   <h:commandButton value="Logout" action="#{login.logout}" rendered="#{login.loggedIn}"/>
</h:form>

Объект пользователя:

@Entity
public class User {
   private @NotNull @Length(min=3, max=25) @Id String username;
   private @NotNull @Length(min=6, max=20) String password;
   public String getUsername() { return username; }
   public void setUsername(String username) { this.username = username; }
   public String setPassword(String password) { this.password = password; }
}

Компонент SessionScoped

@SessionScoped @Named
    public class Login implements Serializable {

   @Inject Credentials credentials;
   @Inject @UserDatabase EntityManager userDatabase;
   private User user;
   public void login() {
      List<User> results = userDatabase.createQuery(
         "select u from User u where u.username = :username and u.password = :password")
         .setParameter("username", credentials.getUsername())
         .setParameter("password", credentials.getPassword())
         .getResultList();
      if (!results.isEmpty()) {
         user = results.get(0);
      }
      else {
         // perhaps add code here to report a failed login
      }
   }

   public void logout() {
      user = null;
   }

   public boolean isLoggedIn() {
      return user != null;
   }

   @Produces @LoggedIn User getCurrentUser() {
 return user;
   }
}

Мои вопросы

1) Компонент @RequestScoped внедряется в компонент @SessionScoped. Какова гарантия того, что учетная информация, установленная в одном экземпляре RequestScoped, совпадает с введенной в @SessionScopedbean. почему не внедряется другой @RequestScoped из пула или даже новый экземпляр?

2)почему бину присваивается @SessionScoped, а не @Stateful. Думаю, @Stateful здесь подойдет.

3) как управляется жизненный цикл бина @sessionScoped? То есть когда он уничтожается? Если я перейду на другую JSF страницу, на которой, если я извлеку информацию, такую ​​​​как currentUser.userName, я получу ту же информацию, которую я установил на моей первой JSF странице, используемой для входа в систему. (шаг 1 выше)

4) Если я не укажу @RequestScoped, то bean-компонент Credentials получит область @Dependent, которая является областью действия по умолчанию. В документах упоминается, что установка любых переменных экземпляра @Dependent немедленно теряется. Но я не понимаю, почему? На самом деле, это подсказывает мне вопрос о том, как будет использоваться @Dependent прицел?

Спасибо

EDIT Спасибо, kolossus, за подробный и отличный ответ. Мне нужно немного больше разъяснений по некоторым вашим пунктам для лучшего понимания

  1. Для bean-компонента @requestScoped существует пул доступных экземпляров, которые передаются клиентам. Теперь, если у меня есть два клиента, обращающихся к JSF, который поддерживается bean-компонентом @RequestScoped, каждый клиент получает возможность работать с одним экземпляром bean-компонента @RequestScoped из пула. На самом деле оба клиента на самом деле работают не с прямым экземпляром, а с косвенной ссылкой на тот единственный экземпляр, который здесь является прокси. клиенты выполняют все вызовы методов или транзакции, используя этот прокси. так как долго прокси удерживает эту косвенную ссылку? То есть в моем примере выше переменные экземпляра @RequestScoped bean-компонента (Credentials) задаются в JSF. но истинный факт заключается в том, что эта настройка переменных экземпляра происходит с одним экземпляром bean-компонента @RequestScoped косвенно через прокси. Но когда этот экземпляр внедряется в bean-компонент SessionScoped, внедряется ли прокси-сервер? Поскольку жизненный цикл SessionScoped предназначен для сеанса, установленного между клиентом и приложением, прокси-сервер также живет в течение этого времени существования. Означает ли это, что этот single instance of @RequestScoped bean привязан к SessionScoped, а жизненный цикл экземпляра компонента @RequestScoped или его прокси определяется жизненным циклом компонента SessionScoped?

person brain storm    schedule 10.10.2014    source источник
comment
Сомневаюсь, что это вообще законно. Вы можете вводить переменные из долгоживущих областей, в данном случае Application, но записывать из краткосрочных.   -  person user207421    schedule 11.10.2014
comment
@EJP: приведенный выше код взят из документации JBoss, на которую я ссылался выше. На самом деле, у меня был аналогичный вопрос, является ли он законным или нет, только что опубликованным здесь: различные области видимости в ejbs" title="правила для внедрения одного bean-компонента в другой из различных областей в ejbs">stackoverflow.com/questions/26285416/   -  person brain storm    schedule 11.10.2014
comment
Интересный. Это незаконно в самом JSF.   -  person user207421    schedule 11.10.2014
comment
Ваше редактирование неясно и содержит слишком много метавопросов.   -  person kolossus    schedule 12.10.2014
comment
Вы объединяете механизм EJB с механизмом определения области действия CDI: @RequestScoped bean-компоненты не объединены в пул. Почему бы им быть? Они живы только на время одного запроса. Пользователю потребуется только один.   -  person kolossus    schedule 12.10.2014
comment
@kolossus: последняя мысль. что означает введение @RequestScoped в @SessionScoped? жизненный цикл этого экземпляра @RequestScoped связан с @SessionScoped?   -  person brain storm    schedule 12.10.2014
comment
Почти со всем в CDI связан контекст вызова (вот что подразумевается под контекстной ссылкой в ​​моем ответе). Думайте об этом как о разговоре: для каждого разговора/контекста будет по одному бобу каждого типа. В этом контексте компонент @SessionScoped может требовать компонент @RequestScoped и наоборот.   -  person kolossus    schedule 12.10.2014


Ответы (1)


  1. Компонент @RequestScoped внедряется в компонент @SessionScoped. Какова гарантия того, что учетная информация, установленная в одном экземпляре RequestScoped, совпадает с введенной в @SessionScopedbean. почему не внедряется другой @RequestScoped из пула или даже новый экземпляр?

    Это законно, благодаря средствам, с помощью которых CDI фактически получает ссылки на запрошенный компонент: клиентские прокси. Из спецификации CDI

    Введенная ссылка или ссылка, полученная программным поиском, обычно является контекстной ссылкой. Контекстная ссылка на bean-компонент с нормальной областью действия[...], не является прямой ссылкой на контекстный экземпляр bean[...].Вместо этого контекстная ссылка является объектом клиентского прокси Клиентский прокси реализует/расширяет некоторые или все типы bean-компонентов bean-компонента и делегирует все вызовы методов текущий экземпляр компонента...

    Для такой косвенности есть ряд причин:

    • The container must guarantee that when any valid injected reference to a bean of normal scope is invoked, the invocation is always processed by the current instance of the injected bean. In certain scenarios, for example if a request scoped bean is injected into a session scoped bean, or into a servlet, this rule requires an indirect reference

    Также из этой статьи DZone CDI:

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

    Это означает, что прокси заменяет реальную вещь в каждой точке внедрения. Прокси имитирует тип, объявленный в точке внедрения, расширяя/реализуя дерево предков типа, который он должен имитировать. В то время, когда вам действительно требуется использование объекта, прокси выполняет контекстный поиск существующего экземпляра запрошенного компонента в текущем диалоге. Поскольку это объект с областью действия запроса, у вас гарантированно будет ровно один экземпляр в текущем диалоге/контексте.

  2. #P8#
    #P9#
  3. #P10#
    #P11#
    #P12#
  4. Думайте о @Dependent как о любой локальной переменной метода: она полезна только до тех пор, пока существует ее родительская конструкция. При этом лучше всего использовать его не для поддержки представления JSF. Наиболее полезным приложением является переопределение области, указанной для bean-компонента, ad-hoc. Используя ваш текущий пример, я могу иметь следующее где-то еще в своем приложении:

    @Inject @New Login aDependentLoginBean; //implicit @Dependent scope applied
    @Inject Login aSessionScopedLoginBean;  //standard Login bean's scope applied
    

    Вместе с @New вы можете перепрофилировать любой другой боб будет @Dependent


Связано:

person kolossus    schedule 11.10.2014
comment
Я читаю это снова и снова. У меня есть еще один пост здесь. "правила внедрения одного bean-компонента в другой различных областей видимости в ejbs">stackoverflow.com/questions/26285416/ - person brain storm; 11.10.2014
comment
Мой комментарий к этому вопросу остается в силе: вы правильно понимаете ситуацию @brainstorm. Вам трудно понять этот ответ? - person kolossus; 11.10.2014
comment
Вы действительно дали очень подробный ответ. Большое спасибо за то же. У меня есть небольшая проблема с пониманием концепции прокси и того, как они работают. Пожалуйста, смотрите редактирование выше. Я добавил конкретные вопросы о моем понимании вашего ответа здесь - person brain storm; 11.10.2014
comment
Объяснение механизма проксирования CDI выходит за рамки этого вопроса @brainstorm. Вам нужно будет задать другой вопрос для объяснения шаблона прокси и того, как работает прокси. в ЦДИ - person kolossus; 12.10.2014
comment
Я согласен, что механизм проксирования - это другой вопрос. Я отредактировал часть выше, чтобы сосредоточиться на своих сомнениях. поскольку ваше объяснение было основано на прокси, я изначально расширил свое редактирование, сосредоточившись на прокси. Теперь я удалил его. Спасибо - person brain storm; 12.10.2014