2017-02-15 23 views
1

Я создаю пользовательскую область CDI и использую BeanManager, чтобы получить инъекцию моего NavigationHandler пользовательского класса. Но бобы, которые он возвращает, довольно странные.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 

Но мой отладчик возвращает true, когда я тестирую reference1==reference2. Я также получаю странные хэш-коды:

Found [email protected] (hash=1261587818) 
Found [email protected] (hash=1261587818) 

Я не понимаю, почему хэшей, используемые в ToString() различны, но хэш используется в хэш-код() одинаковы.

ответ

1

Я думаю, что я выяснил причину этих двух связанных проблем, это было сложно!

m_beanManager.getReference(..) не возвращает экземпляр NavigationHandler, а прокси-сервер, который должен выбирать и действовать как правильный NavigationHandler среди существующих в контексте области видимости.

Ссылка понять концепцию прокси/Context/BeanManager:https://developer.jboss.org/blogs/stuartdouglas/2010/10/12/weld-cdi-and-proxies

Так что мой getNavigationHandler() метод не подходит для работы: мой бассейн, который вызывает этот метод будет держать NavigationHandler прокси вместо NavigationHandlers. Поскольку мой пул не является полем @Inject, прокси не будет автоматически обновляться CDI, поэтому возвращаемая ссылка всегда будет последней из последнего контекста, активно используемого прокси.

По той же причине в этом выводе:

Found [email protected] (hash=1261587818) 
Found [email protected] (hash=1261587818) 

В одном случае я получаю хэш экземпляра NavigationHandler, и в другом случае я получаю хэш-прокси NavigationHandler «s. Но я не знаю, кто из них. Я готов поверить, что используется toString() для прокси-сервера, поскольку beanManager.getReference(..) должен каждый раз обслуживать новый прокси, а хэш-код должен быть практически уникальным для объекта в каждом экземпляре.

Link, что говорит хэш-код каждого экземпляра является уникальным хэш-код и не может изменяться в течение долгого времени: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; 
} 

Link, что объясняет разницу междуbeanManager.getReference(..)иbeanManager.getContext(..).get(..): Canonical way to obtain CDI managed bean instance: BeanManager#getReference() vs Context#get()