我正在创建自定义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()中使用的哈希值是相同的。
答案 0 :(得分: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#hashCode%28%29
因此,实施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(..)
之间差异的链接:Canonical way to obtain CDI managed bean instance: BeanManager#getReference() vs Context#get()