2017-02-15 131 views
1

我正在創建自定義CDI範圍,並使用BeanManager來註冊我的NavigationHandler自定義類。但它返回的bean很奇怪。BeanManager始終返回相同的參考

所以我用的是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 [email protected] (hash=1261587818) 
Found [email protected] (hash=1261587818) 

我不明白爲什麼在了toString()使用的哈希值是不同的,但()中使用的hashCode哈希是相同的。

回答

1

我想我找出了這兩個鏈接問題的原因,那是一個棘手的問題!

m_beanManager.getReference(..)不返回NavigationHandler實例,而是一個代理,它應該在範圍的上下文中選擇並充當正確的NavigationHandler。

鏈接瞭解代理/語境/ BeanManager的概念:https://developer.jboss.org/blogs/stuartdouglas/2010/10/12/weld-cdi-and-proxies

所以我getNavigationHandler()方法是不適合的工作:我的游泳池調用該方法將持有NavigationHandler代理,而不是NavigationHandlers。由於我的池不是CDI字段,因此代理不會被CDI自動更新,因此返回的引用始終是來自代理正在使用的最後一個上下文的引用。

對於這種輸出相同的原因:

Found [email protected] (hash=1261587818) 
Found [email protected] (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(..)andbeanManager.getContext(..).get(..)Canonical way to obtain CDI managed bean instance: BeanManager#getReference() vs Context#get()