Внедрить @Names @ViewScoped в @SessionScoped

У меня есть два компонента, использующих @Named, один с @SessionScoped, а другой с @ViewScoped. Я могу внедрить bean-компонент @ViewScoped в @SessionScoped, и я пытаюсь сделать наоборот, и у меня почти работает, но у меня нет таких же экземпляров.

Я вижу это, когда печатаю this.hashcode() внутри метода @PostContruct компонента viewScoped и сравниваю его с введенным внутри компонента sessionScoped.

Итак, я нашел решение, но я не знаю, является ли это хорошей практикой: внутри метода @PostContruct bean-компонента ViewScoped после внедрения bean-компонента SessionScoped я отправляю ViewScoped в SessionScoped через à setter.

если я хорошо понял, что эти объекты привязаны к пользователю, так что это не создает никаких проблем, я прав?

@Named
@ViewScoped
public class ViewScopedBean {

    @Inject
    protected SessionScopedBean sessionScopedBean;

    @PostContruct
    public void init(){

        sessionScopedBean.setViewScopedBean(this);
    }
}

@Named
@SessionScoped
public class SessionScopedBean {

    protected ViewScopedBean viewScopedBean ;

    public void setViewScopedBean(ViewScopedBean viewScopedBean){

        this.viewScopedBean = viewScopedBean;
    }
}

person Kaizokun    schedule 25.02.2018    source источник
comment
Здесь следует отметить две вещи. Во-первых, действительно ли эти два вида bean-компонентов, которые вы получаете, разные? Помните, что они (скорее всего) являются прокси, поэтому проверьте это, используя их внутреннее состояние, а не hashCode (которое может быть вызвано на уровне прокси). Во-вторых, вы уверены, что достаточно хорошо понимаете ViewScoped жизненный цикл? Например. может быть логично, что вы получаете два разных экземпляра, потому что они привязаны к представлению JSF. См. также этот ответ   -  person Siliarus    schedule 26.02.2018
comment
Спасибо за ответ, вы правы! Я проверил, и это тот же объект, встроенный в прокси. Если я вызываю хэш-код для Injected ViewScopedBean, я вижу прокси-сервер, но если я вызываю метод встроенного компонента (который печатает хэш-код), я вижу, что это то же самое. О жизненном цикле я думаю да, но я не знаю всех деталей (я должен ^^), я использую Bean-компонент ViewScoped для сохранения состояния компонента дерева простых лиц, узлы могут быть расширены с помощью ленивой загрузки.   -  person Kaizokun    schedule 26.02.2018
comment
Со старой системой ManagedBean я не мог внедрить viewScopedBean в sessionScopedBean с аннотацией @ManagedProperty. Но вот мне интересно узнать, как это работает. Я предполагаю, что каждый раз, когда изменяется ViewScopedBean, он повторно вводится в SessionScopedBean, верно?   -  person Kaizokun    schedule 26.02.2018
comment
Я не знаком с деталями реализации представления с областью действия, но с точки зрения CDI (представление с областью действия исходит из JSF) вы всегда должны внедрять текущий активный (если есть) компонент с областью видимости в заданном контексте и потоке. Создание/замена этого базового компонента с областью видимости предписывается JSF impl и должно происходить при создании/закрытии представления.   -  person Siliarus    schedule 26.02.2018
comment
Я извлек комментарий в ответ, чтобы можно было решить этот ТАК вопрос.   -  person Siliarus    schedule 26.02.2018


Ответы (2)


Извлечение того, что я написал в комментариях, в ответ:

Загвоздка здесь в том, что CDI/Weld не @Inject создает контекстуальный экземпляр напрямую, а передает экземпляры прокси (для @NormalScoped bean-компонентов!), которые затем делегируются одному нижележащему экземпляру bean-компонента; в данном случае @ViewScoped bean.

В вопросе было сделано предположение, что hashCode() можно использовать для введенных объектов, чтобы убедиться, что они идентичны. Это, однако, не обязательно должно быть правдой, поскольку CDI может предоставить вам другой прокси для каждой точки внедрения, и hashCode() будет вызываться для прокси-объекта, а не для базового экземпляра компонента - отсюда и различия.

Способ проверить внутреннее состояние bean-компонента, которое оказалось равным, таким образом, показав, что обе точки внедрения внедрили один и тот же экземпляр bean-компонента @viewScoped.

person Siliarus    schedule 26.02.2018
comment
Если метод hashCode() был реализован на проксируемом объекте, прокси-объект вызовет метод hashCode() проксируемого объекта... То же самое касается equals() - person thobens; 26.02.2018
comment
hashCode (и по расширению equals), скорее всего, реализованы там (вы можете легко дампировать байт-код прокси в сварке и проверке), и поэтому такое поведение происходит. Разные прокси доставляются на два разных IP. - person Siliarus; 26.02.2018

Я вижу две проблемы:

  1. Ваша главная проблема здесь в том, что у вас есть циклические зависимости. Постарайтесь избежать этого. ViewScopedBean не может зависеть от SessionScopedBean и наоборот, потому что CDI не будет знать, какой из них создать первым. (Вот почему вы должны установить свою зависимость вручную в методе @PostConstruct.)
  2. Вы не можете сравнивать Beans, сравнивая их ссылки, поскольку они сериализуются/не сериализуются и, следовательно, не являются одними и теми же объектами. Вот почему вы должны сравнивать их, используя equals(), и реализовывать методы hashCode().
person thobens    schedule 26.02.2018
comment
CDI может обрабатывать определенное количество циклических зависимостей по умолчанию благодаря ленивой инициации (по крайней мере, в Weld) и прокси. Но насколько я понял, OP ввел эту зависимость только для проверки поведения инъекции? Но вы правы. Что касается 2. - опять же, это детали внедрения Weld, но вы можете увидеть, как они создаются для клиентских прокси здесь. Прочитайте javadoc, чтобы понять, как именно это работает, ваш ответ вводит в заблуждение и не соответствует действительности. - person Siliarus; 26.02.2018
comment
@thobens спасибо, я не уверен, но я думаю, что sessionScopedBean можно внедрить в viewScopedBean, потому что sessionScopedBean создается первым, потому что он привязан к сеансу пользователя, а viewScopedBean должен быть создан тогда, когда вызывается конкретное представление. И похоже, он довольно хорошо справляется с круговой зависимостью. - person Kaizokun; 26.02.2018
comment
в любом случае, если я хочу сделать это вручную в @PostConstruct и избежать циклических зависимостей, я должен по крайней мере внедрить одну из них: p. И спасибо за информацию о сериализации, я уже забыл! - person Kaizokun; 26.02.2018