【问题标题】:BeanManager always returns same referenceBeanManager 总是返回相同的引用
【发布时间】:2017-07-04 13:12:00
【问题描述】:

我正在创建一个自定义 CDI 范围并使用 BeanManager 来注入我的 NavigationHandler 自定义类。但是它返回的 bean 很奇怪。

所以我就是这样使用 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

但是当我测试reference1==reference2 时,我的调试器返回true。我也得到奇怪的哈希码:

Found NavigationHandler@593e785f (hash=1261587818)
Found NavigationHandler@b6d51bd (hash=1261587818)

我不明白为什么 toString() 中使用的哈希值不同,但是 hashCode() 中使用的哈希值是一样的。

【问题讨论】:

    标签: hash scope cdi custom-scope


    【解决方案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。因为我的池不是@Injected 字段,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()

    之间区别的链接

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-04-29
      • 1970-01-01
      • 2019-10-04
      • 1970-01-01
      • 2014-05-01
      • 2019-10-22
      • 2019-10-31
      • 1970-01-01
      相关资源
      最近更新 更多