Канонический способ получения экземпляра управляемого Бина CDI: BeanManager#getReference () vs Context#get()
Я решил, что есть два основных способа получить автоматически созданный экземпляр управляемого Бина CDI через BeanManager
при наличии только Bean<T>
Для начала (который создается на основе Class<T>
):
-
By
BeanManager#getReference()
, что чаще всего проявляется в фрагменты:Bean<TestBean> bean = (Bean<TestBean>) beanManager.resolve(beanManager.getBeans(TestBean.class)); TestBean testBean1 = (TestBean) beanManager.getReference(bean, bean.getBeanClass(), beanManager.createCreationalContext(bean));
-
By
Context#get()
, что реже всего показано в фрагментах:Bean<TestBean> bean = (Bean<TestBean>) beanManager.resolve(beanManager.getBeans(TestBean.class)); TestBean testBean2 = beanManager.getContext(bean.getScope()).get(bean, beanManager.createCreationalContext(bean));
В эффектах они делают в конечном счете точно то же самое: возвращают проксированный ссылка на текущий управляемый экземпляр компонента CDI и автоматическое создание экземпляра компонента, если он еще не существует в области.
Но они делают это немного иначе:BeanManager#getReference()
всегда создает совершенно новый экземпляр прокси, в то время как Context#get()
повторно использует существующий экземпляр прокси, если он уже был создан ранее. Это очевидно, когда приведенный выше код выполняется в методе действия существующего экземпляра TestBean
:
System.out.println(testBean1 == testBean2); // false
System.out.println(testBean1 == this); // false
System.out.println(testBean2 == this); // true
Javadoc из Context#get()
очень явно выражен в этом:
Возвращает существующий экземпляр определенного контекстного типа или создает новый экземпляр, вызывая Contextual.создайте (CreationalContext) и верните новый экземпляр.
В то время как javadoc из BeanManager#getReference()
не является достаточно явным по этому поводу:
Это привело меня в замешательство. Когда вы используете то или другое? Для обоих способов вам нужен aПолучает контекстуальную ссылку для определенного Боба и определенного типа Боба.
Bean<T>
экземпляр в любом случае, из которого класс bean и область bean легко доступны, что требуется в качестве дополнительного аргумента. Я не могу себе представить, почему они должны быть поставлены извне в этом конкретном случае.
Я могу себе представить, что Context#get()
более эффективен в памяти, поскольку он не создает без необходимости другой экземпляр прокси, ссылающийся на тот же самый базовый экземпляр bean, а просто находит и повторно использует существующий экземпляр прокси.
BeanManager#getReference()
более полезным, чем Context#get()
? Он чаще показывается во фрагментах и чаще рекомендуется в качестве решения, но он только без необходимости создает новый прокси-сервер, даже если он уже существует.3 ответа:
BeanManager#getReference предоставляет вам новый экземпляр клиентского прокси, но клиентский прокси будет перенаправлять вызовы метода текущему контекстному экземпляру конкретного контекста. Как только вы получите прокси и сохраните его, вызов метода будет вызван на текущем экземпляре (например, текущий запрос). Это также полезно, если контекстный экземпляр не сериализуем - прокси клиента будет и будет повторно подключаться после десериализации.
BeanManager#getContext получает целевой экземпляр без прокси-сервера клиента. Вы все еще можете видеть прокси сварного шва в имени класса, но это улучшенный подкласс, который обеспечивает перехват и оформление. Если Боб не перехватывается и не украшается, это будет простой экземпляр данного Боба.
Обычно (1) является более подходящим, если у вас нет специального случая использования, когда вам нужно получить доступ к целевому экземпляру напрямую (например, для доступа к его полям).
Или другими словами
1) BeanManager#getReference вернет "контекстную ссылку"с обычным прокси-сервером области для Боба. Если Боб имеет с
@SessionScoped
Как@SessionScoped User user;
Тогда пользователь контекстной ссылки будет "указывать" на соответствующий экземпляр пользователя ("контекстный экземпляр") текущего сеанса для каждого вызова. Два разных вызова
user.getName()
из двух разных веб-браузеров дадут вам разные ответы.2) Context#get () вернет внутренний "Контекстный экземпляр" без обычного прокси-сервера области видимости.Обычно это не то, что пользователь должен называть сам. Если вы получите
User user
для " Bob " таким образом и сохраните его в бобе@ApplicationScoped
или в статической переменной, тогда он всегда будет оставаться пользователем "Боб" - даже для веб-запросов от других браузеров! Вы получите прямой, не проксированный экземпляр.
У меня есть Синглет, на который я использовал метод getReference() для получения ссылки. Несмотря на то, что синглет уже был инициализирован, прокси, созданный с помощью getReference (), вызывал @PostConstruct каждый раз, когда использовался getReference ().
@Startup @ApplicationScoped @Singleton @PostConstruct private void initialize() {}
Путем переключения на getContext ().метод get (), ненужные вызовы прокси @PostConstruct больше не выполняются.
Это было очень полезно при интеграции CDI с javafx, дело было в том, что мне нужна была ссылка на причину объекта правой области, а не прокси зависимой области...
Я использовал метод производителя, чтобы получить узел javaFX, который вводится в контроллер следующим образом:
@Inject @ApplicationScoped @FXMLFile("javafx/wares.fxml") @FXMLController(WaresController.class) Parent wares;
Но при использовании BeanManager#getReference() прокси, который я получаю обратно, "съедает" все значения, установленные FXMLLoader, getContext.получить() способ решить ее.
Thnx для этого