2017-02-15 1 views
1

Je crée une étendue personnalisée CDI et j'utilise le BeanManager pour obtenir une injection de ma classe personnalisée NavigationHandler. Mais les fèves retournées sont assez étranges.BeanManager renvoie toujours la même référence

J'utiliser le BeanManager cette façon:

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; 
    } 
    ... 
} 

je pense, quand j'utiliser mon projet avec deux navigateurs différents, pour obtenir deux différents NavigationHandler, qui sont définies ainsi:

@Named 
@WindowScoped 
public class NavigationHandler 
    implements Serializable, INavigationHandlerController 

Mais mon débogueur renvoie true lorsque je teste reference1==reference2. Je reçois aussi des codes de hachage étranges:

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

Je ne comprends pas pourquoi les hash utilisés dans le toString() sont différentes, mais le hachage utilisé dans hashCode() sont les mêmes.

Répondre

1

Je pense avoir trouvé la raison de ces deux problèmes liés, c'était délicat!

m_beanManager.getReference(..) ne retourne pas l'instance de NavigationHandler, mais un proxy qui est supposé sélectionner et jouer le rôle de NavigationHandler correct parmi les instances existantes dans le contexte de l'étendue.

Lien à comprendre le concept de Proxy/Contexte/BeanManager:https://developer.jboss.org/blogs/stuartdouglas/2010/10/12/weld-cdi-and-proxies

donc ma méthode getNavigationHandler() ne convient pas pour le travail: ma piscine qui appelle cette méthode tiendra proxies NavigationHandler au lieu de NavigationHandlers. Comme mon pool n'est pas un champ @Inject ed, le proxy ne sera pas automatiquement mis à jour par CDI, donc la référence renvoyée est toujours celle du dernier contexte utilisé activement par un proxy.

Pour la même raison dans cette sortie:

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

Dans un cas, je reçois le hachage de l'instance NavigationHandler, et dans l'autre cas, je reçois le hachage de procuration de la NavigationHandler. Pourtant je ne sais pas lequel est qui. Je suis prêt à croire que le proxy toString() est utilisé, car beanManager.getReference(..) est censé servir un nouveau proxy à chaque fois, et le hashCode est supposé être pratiquement unique pour chaque instance.

lien qui dit tous les cas de la hashcode est hashcode unique et ne peut pas changer au fil du temps:http://docs.oracle.com/javase/7/docs/api/java/lang/Object.html#hashCode%28%29

Ainsi, la bonne façon de mettre en œuvre getNavigationHandler() est:

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; 
} 

lien qui explique la différence entrebeanManager.getReference(..)etbeanManager.getContext(..).get(..): Canonical way to obtain CDI managed bean instance: BeanManager#getReference() vs Context#get()