2008-09-16 4 views
2

Supposons que nous avons le code Java suivant:Carte des énumérations et l'injection de dépendance au printemps 2,5

public class Maintainer { 
    private Map<Enum, List<Listener>> map; 

    public Maintainer() { 
     this.map = new java.util.ConcurrentHashMap<Enum, List<Listener>>(); 
    } 

    public void addListener(Listener listener, Enum eventType) { 
     List<Listener> listeners; 
     if((listeners = map.get(eventType)) == null) { 
     listeners = new java.util.concurrent.CopyOnWriteArrayList<Listener>(); 
     map.put(eventType, listeners); 
     } 
     listeners.add(listener); 
    } 
} 

Cet extrait de code est rien mais un peu amélioré modèle d'écoute où chaque auditeur raconte quel type d'événement il s'intéresse à, et la méthode fournie maintient une carte simultanée de ces relations.

Au départ, je voulais que cette méthode soit appelée via mon propre cadre d'annotation, mais heurté un mur de briques de différentes limitations d'annotation (par exemple, vous ne pouvez pas avoir java.lang.Enum comme annotation param, il y a aussi un ensemble de divers problèmes de classloader) a donc décidé d'utiliser Spring.

Quelqu'un pourrait-il me dire comment je Spring_ify_ this? Ce que je veux obtenir est:
1. Définir Mainteneur classe comme un haricot de printemps.
2. Faites en sorte que toutes sortes d'écouteurs puissent s'enregistrer auprès de Maintainer via XML en utilisant la méthode addListener. Spring doc ou Google sont très généreux dans les exemples.

Existe-t-il un moyen d'y parvenir facilement?

Répondre

2

Que serait mal à faire quelque chose comme ce qui suit:

Définition d'une interface 'mainteneur' avec la méthode addListener (Listener, Enum).

Créez une classe DefaultMaintainer (comme ci-dessus) qui implémente Maintainer. Puis, dans chaque classe d'écoute, injectez l'interface Maintainer (l'injection du constructeur peut être un bon choix). L'auditeur peut alors s'enregistrer auprès du mainteneur. À part ça, je ne suis pas sûr à 100% exactement de ce qu'est votre problème avec le printemps en ce moment! :)

0

Vous avez dit "... vous ne pouvez pas avoir java.lang.Enum comme" annotation ... param »

Je pense que vous avez tort sur ce point. J'ai récemment utilisé sur un projet quelque chose comme ceci:.

public @interface MyAnnotation { 
    MyEnum value(); 
} 
+0

Eh bien, c'est exactement ce que je disais - "vous ne pouvez pas avoir java.lang.Enum comme annotation PARAM". Je demandais comment je fais ça au printemps? – mindas

1

1) Définition d'une classe de mainteneur comme un grain de printemps

syntaxe Spring standard applique:

<bean id="maintainer" class="com.example.Maintainer"/> 

2) Faites en sorte que toutes sortes d'auditeurs seraient en mesure de se faire enregistrer à mainteneur via XML en utilisant la méthode addListener. Spring doc ou Google sont très généreux dans les exemples.

Ceci est plus compliqué.Vous pouvez utiliser MethodInvokingFactoryBean pour appeler individuellement maintainer#addListener, comme ceci:

<bean id="listener" class="com.example.Listener"/> 

<bean id="maintainer.addListener" class="org.springframework.beans.factory.config.MethodInvokingFactoryBean"> 
    <property name="targetObject" ref="maintainer"/> 
    <property name="targetMethod" value="addListener"/> 
    <property name="arguments"> 
    <list> 
     <ref>listener</ref> 
     <value>com.example.MyEnum</value> 
    </list> 
</property> 
</bean> 

Cependant, cela est difficile à manier, et potentiellement sujettes à erreur. J'ai tenté quelque chose de similaire sur un projet, et j'ai créé une classe utilitaire Spring pour aider à la place. Je n'ai pas le code source disponible pour le moment, donc je vais décrire comment implémenter ce que j'ai fait.

1) Refactoriser les types d'événements ont écouté dans une interface MyListener

public interface MyListener extends Listener { 
    public Enum[] getEventTypes() 
} 

Ce qui change la méthode d'inscription à

public void addListener(MyListener listener) 

2) Créer printemps classe d'aide qui trouve tous les auditeurs pertinents dans le contexte , et appelle le mainteneur # addListener pour chaque écouteur trouvé. Je voudrais commencer par BeanFilteringSupport, et également mettre en œuvre BeanPostProcessor (ou ApplicationListener) pour enregistrer les beans après que tous les beans ont été instanciés.

0

Merci à tous pour les réponses. D'abord, un suivi rapide de toutes les réponses.
1. (alexvictor) Oui, vous pouvez avoir concret enum comme paramètre d'annotation, mais pas java.lang.Enum.
2. Réponse fournie par flicken est correct, mais malheureusement un peu effrayant. Je ne suis pas un expert de Spring mais je fais les choses de cette façon (en créant des méthodes pour faciliter l'accès Spring) cela semble être un peu exagéré, tout comme la solution MethodInvokingFactoryBean. Bien que je voulais exprimer mes sincères remerciements pour votre temps et vos efforts.
3. La réponse de Phill est un peu inhabituel (au lieu d'injecter le bean auditeur, injecter son mainteneur!), Mais, je crois, le plus propre de tous disponibles. Je pense que je vais suivre ce chemin.

Encore une fois, un grand merci pour votre aide.

2

légèrement offtopic (comme on ne parle pas du printemps), mais il y a une condition de course dans votre mise en œuvre de addListener:

if((listeners = map.get(eventType)) == null) { 
    listeners = new java.util.concurrent.CopyOnWriteArrayList<Listener>(); 
    map.put(eventType, listeners); 
    } 
    listeners.add(listener); 

Si deux threads appellent cette méthode en même temps (pour un type d'événement qui, auparavant, map.get (eventType) renverra null dans les deux threads, chaque thread créera sa propre CopyOnWriteArrayList (contenant chacun un seul écouteur), un thread remplacera la liste créée par l'autre, et le premier écouteur sera oublié.

Pour résoudre ce problème, le changement:

private Map<Enum, List<Listener>> map; 

... 

map.put(eventType, listeners); 

à:

private ConcurrentMap<Enum, List<Listener>> map; 

... 

map.putIfAbsent(eventType, listeners); 
listeners = map.get(eventType); 
+0

Belle prise, merci beaucoup! – mindas

Questions connexes