1

我正在创建一个自定义 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() 中使用的哈希值是相同的。

4

1 回答 1

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(..)获取 CDI 托管 bean 实例的规范方法:BeanManager#getReference() vs Context#get()

于 2017-02-16T14:01:15.120 回答