Frage

Nehmen wir an, wir folgende Java-Code haben:

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

Dieser Code-Schnipsel ist nichts anderes als ein Zuhörer Musterbit verbessert, wo jeder Zuhörer erzählt, welche Art von Veranstaltung ist es Interesse an, und die bereitgestellte Verfahren unterhält eine gleichzeitige Karte dieser Beziehungen.

Am Anfang wollte ich diese Methode über meine eigene Anmerkung Rahmen genannt werden, sondern in eine Mauer von verschiedenen Anmerkung Einschränkungen gestoßen (zB kann man nicht haben java.lang.Enum als Annotation param , auch eine Reihe von verschiedenen Classloader Fragen gibt es) daher beschlossen, Frühling zu verwenden.

Kann mir jemand sagen, wie kann ich das Spring_ify_? Was ich will, ist achive:
1. Definieren Sie Maintainer Klasse als Spring-Bean.
2. Machen Sie es sich so, dass alle Arten von Zuhörern wäre in der Lage, sich zu Maintainer registrieren über XML mithilfe von addListener Methode. Frühling doc noch Google ist sehr großzügig in den Beispielen.

Gibt es eine Möglichkeit, dies leicht zu erreichen?

War es hilfreich?

Lösung

Was ist mit etwas zu tun, wie die folgenden falsch wäre:

einen 'Maintainer' Schnittstelle mit dem addListener definieren (Listener, Enum) Methode.

Erstellen Sie eine DefaultMaintainer Klasse (wie oben), die Maintainer implementiert.

Dann in jeder Listener Klasse ‚Inject‘ die Maintainer-Schnittstelle (Konstruktor Injektion könnte eine gute Wahl sein). Der Hörer kann dann registriert sich mit dem Maintainer.

anders als das, ich bin nicht 100% klar auf genau das, was Ihre Schwierigkeit ist mit Frühling im Moment! :)

Andere Tipps

Ein wenig offtopic (da dies nicht zu Spring), aber es ist eine Race-Bedingung in Ihrer Implementierung von AddListener:

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

Wenn zwei Threads diese Methode zur gleichen Zeit aufrufen (für einen Ereignistyp, die zuvor keine Hörer hatte), map.get (eventtype) werden in beiden Gewinden null zurückkehren, wird jeder Faden seine eigene CopyOnWriteArrayList erstellen (die jeweils eine einzige Hörer), wird ein Thread die Liste nach dem anderen, und der erste Hörer vergessen wird erstellt ersetzen.

Um dies zu beheben, ändern:

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

...

map.put( eventType, listeners );

zu:

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

...

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

1) definieren Maintainer-Klasse als Spring-Bean.

Standard Feder Syntax gilt:

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

2) Machen Sie es sich so, dass alle Arten von Hörern selbst wäre in der Lage zu registrieren über XML-Maintainer von addListener Methode. Frühling doc noch Google ist sehr großzügig in den Beispielen.

Das ist schwieriger. Sie könnte Verwendung MethodInvokingFactoryBean einzeln anrufen maintainer#addListener, etwa so:

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

Dies ist jedoch unhandlich und potentiell fehleranfällig. Ich habe versucht, etwas Ähnliches an einem Projekt, und eine Feder Utility-Klasse erstellt, anstatt zu helfen. Ich habe nicht den Quellcode zur Zeit zur Verfügung, also werde ich beschreiben, wie das umzusetzen, was ich tat.

1) Umgestalten der Ereignistypen hörten in eine MyListener Schnittstelle

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

Welche das Registrierungsverfahren

ändert
public void addListener(MyListener listener)

2) Federhilfsklasse erstellen, die alle relevanten Zuhörer im Kontext findet, und fordert Maintainer # addListener für jeden Zuhörer gefunden. Ich würde mit BeanFilteringSupport beginnen, und auch BeanPostProcessor (oder ApplicationListener) zu implementieren, um die Bohnen zu registrieren, nachdem alle Bohnen instanziiert wurden.

  

Du hast gesagt, „... Sie können nicht java.lang.Enum haben als“   Anmerkung param ... "

Ich glaube, Sie auf das falsch sind. Ich habe an einem Projekt so etwas wie dies vor kurzem verwendet:

public @interface MyAnnotation {
    MyEnum value();
}

Vielen Dank für die Antworten. Zuerst folgen Eine schnelle auf alle Antworten auf.
1. (alexvictor) Ja, Sie können Beton haben Enum als Annotation param, aber nicht java.lang.Enum .
2. Antwort von Flicken versehen ist richtig, aber leider ein bisschen beängstigend. Ich bin kein Experte, aber Frühlings Dinge auf diese Weise zu tun (Methoden zum leichteren Frühling Zugang zu schaffen) scheint ein bisschen übertrieben zu sein, wie die MethodInvokingFactoryBean Lösung. Obwohl ich wollte meinen aufrichtigen Dank für Ihre Zeit und Mühe zum Ausdruck bringen.
3. Die Antwort von Phill ist etwas ungewöhnlich (anstelle Zuhörer Bohne Injektion injizieren ihre Betreuer!), Aber, wie ich glaube, die sauberste aller zur Verfügung. Ich denke, ich werde diesen Weg gehen.

Auch ein großes Dankeschön für Ihre Hilfe.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top