Понимание экземпляра cdi‹› и .get() против @Inject

Я немного смущен тем, что использовать в следующей ситуации:

Предположим, сервлет создает приложение, которое обрабатывает пользовательский http-сеанс, и это приложение выглядит следующим образом:

public class Application extends AbstractHTTPApplication {

@Inject
private Instance<MainView> mainView;

public void setupApplication() {
   this.setView( mainView.get() );
}

Позже у меня есть @SessionScoped bean-компонент SSB, который я хочу внедрить в каждый пользовательский bean-компонент:

@SessionScoped
public class SSB {}

Теперь, когда я попробовал обычный @Inject SSB ssb; в качестве поля в MainView, я не получаю новый SSB для каждого пользователя:

public class MainView {

@Inject
private SSB usersSSB;

   public someMethod() {
       usersSSB.doSomething();
       System.identityHashCode( usersSSB );
   }
}

При тестировании с двумя пользователями я получаю один и тот же экземпляр usersSSB в сеансах обоих пользователей. Я не думал, что это возможно... Я думал, что, поскольку SSB имеет SessionScoped, каждому пользовательскому сеансу будет дан новый, и независимо от того, где он @Injected, он будет ссылаться на этого пользовательского сеанса. SSB.

Вместо этого я попробовал:

public class MainView {

@Inject
private Instance<SSB> usersSSB;

   public someMethod() {
       usersSSB.get().doSomething();
       System.identityHashCode( usersSSB.get() );
   }
}

Теперь он, наконец, сообщает разные usersSSB для каждого пользователя.

Что тут происходит? Когда я вызову usersSSB.get() позже в сеансе каждого пользователя, будет ли usersSSB.get() каждый раз возвращать один и тот же bean-компонент для одного и того же пользователя?

Я использую Glassfish 3.1.2.

Дополнительная информация

Класс приложения внедряется в сервлет в новом HttpServletRequest:

public abstract class AbstractCdiApplicationServlet extends
    AbstractApplicationServlet {
@Inject
protected Instance<ApplicationWrapper> wrapper;

@Override
protected Application getNewApplication(HttpServletRequest request)
        throws ServletException {
    return wrapper.get().getApplication();
}
...etc etc

А ApplicationWrapper — это SessionScoped bean:

@SuppressWarnings("serial")
@SessionScoped
public class ApplicationWrapper implements Serializable {
@Inject
private AbstractCdiApplication application;

public AbstractCdiApplication getApplication() {
    return application;
}
 }

Разве это не означает, что вызов @Inject SSB usersSSB в любом месте MainView (или любого объекта в сеансе этого пользователя) должен дать мне bean-компонент этого пользователя в области сеанса и всегда тот же самый сеанс- bean-компонент с ограниченной областью действия для сеанса каждого пользователя? Значение -- разные пользователиSSB для разных пользователей, потому что у каждого пользователя своя сессия.

В конце концов, Application сам по себе является bean-компонентом SessionScoped, внедренным и присоединенным к HTTP-сессии пользователя с помощью метода getNewApplication сервлета? Я имею в виду, в конце концов, это объект Application, который внедряет и прикрепляет класс MainView, верно? Итак, это означает, что MainView — это bean-компонент с областью действия сеанса, не так ли?

Думаю, я просто пытаюсь понять, как все это работает. Спасибо за помощь!


person Christopher Poile    schedule 26.03.2012    source источник
comment
Это очень странно. Есть ли у вас этот образец для тестирования?   -  person LightGuard    schedule 27.03.2012
comment
Честно говоря, у меня нет достаточно твердого представления об этом, чтобы сделать простой тестовый пример... Есть ли рабочий архетип maven, который запустит вас с помощью http-сервлета, создающего приложение для каждого нового сеанса? Я мог бы использовать это, чтобы создать тестовый проект и опубликовать его.   -  person Christopher Poile    schedule 29.03.2012


Ответы (1)


Это происходит потому, что «@Inject Instance‹>» получается динамически, в отличие от «@Inject».

Если вы делаете «@Inject» в bean-компонент ApplicationScoped, тогда инъекция получается только один раз, поэтому в bean-компоненте ApplicationScoped будет одна и та же ссылка для всех пользователей.

Если вы вызываете .get() для '@Inject Instance‹>', то ссылка на SSB получается динамически каждый раз, когда вы вызываете .get()

Подробнее об инъекции вы можете прочитать здесь: http://docs.jboss.org/weld/reference/1.1.0.Final/en-US/html/injection.html

person Krzysztof Miksa    schedule 28.03.2012
comment
Я добавил еще немного информации, вдохновленной вашим комментарием, Krzusztof. Разве @Inject в компонент SessionScoped (MainView) не должен всегда предоставлять один и тот же объект этому пользователю? И должен ли этот @Inject давать другой объект другому пользователю, поскольку он находится в другом сеансе? - person Christopher Poile; 29.03.2012
comment
На самом деле вы получаете прокси, который каждый раз будет искать правильный ресурс. - person LightGuard; 29.03.2012