BeanManager всегда возвращает одну и ту же ссылку
Я создаю пользовательскую область CDI и использую BeanManager
чтобы получить инъекцию моего NavigationHandler
пользовательский класс. Но бобы, которые он возвращает, довольно странные.
Поэтому я использую BeanManager таким образом:
public class ScreenContext implements Context
{
private NavigationHandler getNavigationHandler()
{
final Set<Bean<?>> beans = m_beanManager.getBeans(NavigationHandler.class);
final Bean<?> bean = m_beanManager.resolve(beans);
NavigationHandler reference =
(NavigationHandler) m_beanManager.getReference(bean, NavigationHandler.class,
m_beanManager.createCreationalContext(bean));
System.out.println("Found "+reference+" (hash="+reference.hashCode()+")");
return reference;
}
...
}
Я ожидаю, когда я использую свой проект с использованием двух разных браузеров, чтобы получить два разных NavigationHandler
, которые определены таким образом:
@Named
@WindowScoped
public class NavigationHandler
implements Serializable, INavigationHandlerController
Но мой отладчик возвращается true
когда я проверяю reference1==reference2
, Я также получаю странные хэш-коды:
Found NavigationHandler@593e785f (hash=1261587818)
Found NavigationHandler@b6d51bd (hash=1261587818)
Я не понимаю, почему хеши, используемые в toString(), отличаются, но хеш, используемый в hashCode(), одинаков.
1 ответ
Я думаю, что я выяснил причину этих двух связанных проблем, это было сложно!
m_beanManager.getReference(..)
не возвращает экземпляр NavigationHandler, но прокси, который должен выбирать и действовать как правильный NavigationHandler среди существующих в контексте области.
Ссылка для понимания концепции Proxy / Context / BeanManager: https://developer.jboss.org/blogs/stuartdouglas/2010/10/12/weld-cdi-and-proxies
Так что мой getNavigationHandler()
метод не подходит для работы: мой пул, который вызывает этот метод, будет содержать прокси NavigationHandler вместо NavigationHandlers. Потому что мой бассейн не @Inject
В поле ed прокси не будет автоматически обновляться с помощью CDI, поэтому возвращаемая ссылка всегда совпадает с последней из контекста, активно используемого прокси.
По той же причине в этом выводе:
Found NavigationHandler@593e785f (hash=1261587818)
Found NavigationHandler@b6d51bd (hash=1261587818)
В одном случае я получаю хэш NavigationHandler
экземпляр, а в другом случае я получаю хэш NavigationHandler
прокси. И все же я не знаю, кто из них какой. Я готов поверить, что toString() прокси используется, так как beanManager.getReference(..)
должен каждый раз обслуживать новый прокси, а hashCode должен быть практически уникальным для каждого экземпляра объекта.
Ссылка, в которой говорится, что хэш-код каждого экземпляра является уникальным хеш-кодом и не может изменяться со временем: http://docs.oracle.com/javase/7/docs/api/java/lang/Object.html
Так что правильный способ реализации getNavigationHandler()
является:
private getNavigationHandlergetgetNavigationHandler()
{
final Set<Bean<?>> beans = m_beanManager.getBeans(getNavigationHandler.class);
final Bean<?> bean = m_beanManager.resolve(beans);
/* Works : pure reference (not proxied) */
Class<? extends Annotation> scopeType = bean.getScope();
Context context = m_beanManager.getContext(scopeType);
CreationalContext<?> creationalContext = m_beanManager.createCreationalContext(bean);
// Casts below are necessary since inheritence does not work for templates
getNavigationHandler reference =
context.get((Bean<NavigationHandler>) bean, (CreationalContext<NavigationHandler>) creationalContext);
return reference;
}
Ссылка, которая объясняет разницу между beanManager.getReference(..)
а также beanManager.getContext(..).get(..)
: Канонический способ получения экземпляра управляемого компонента CDI: BeanManager#getReference() vs Context#get()