Domanda

Supponiamo di avere il seguente codice Java:

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

Questo frammento di codice non è altro che un modello di ascolto leggermente migliorato in cui ciascun ascoltatore indica il tipo di evento a cui è interessato e il metodo fornito mantiene una mappa simultanea di queste relazioni.

Inizialmente, volevo che questo metodo fosse chiamato tramite il mio framework di annotazione, ma mi sono scontrato con un muro di varie limitazioni di annotazione (ad es.non puoi avere java.lang.Enum come parametro di annotazione, c'è anche una serie di vari problemi del classloader) quindi ho deciso di utilizzare Spring.

Qualcuno potrebbe dirmi come faccio a Spring_ify_ questo?Ciò che voglio ottenere è:
1.Definire Manutentore classe come un fagiolo primaverile.
2.Fai in modo che tutti i tipi di ascoltatori possano registrarsi Manutentore tramite XML utilizzando aggiungiListener metodo.Spring Doc né Google sono molto generosi negli esempi.

C'è un modo per raggiungere questo obiettivo facilmente?

È stato utile?

Soluzione

Cosa ci sarebbe di sbagliato nel fare qualcosa del genere:

Definizione di un'interfaccia 'Maintainer' con il metodo addListener(Listener, Enum).

Crea una classe DefaultMaintainer (come sopra) che implementa il manutentore.

Quindi, in ciascuna classe Listener, "inietta" l'interfaccia del manutentore (l'iniezione del costruttore potrebbe essere una buona scelta).L'ascoltatore può quindi registrarsi presso il manutentore.

a parte questo, non mi è chiaro al 100% quale sia esattamente la tua difficoltà con la Primavera in questo momento!:)

Altri suggerimenti

Leggermente fuori tema (poiché non si tratta della primavera) ma c'è una condizione di competizione nella tua implementazione di AddListener:

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

Se due thread chiamano questo metodo contemporaneamente (per un tipo di evento che in precedenza non aveva ascoltatori), map.get( eventType ) restituirà null in entrambi i thread, ogni thread creerà il proprio CopyOnWriteArrayList (ciascuno contenente un singolo ascoltatore), un thread sostituirà l'elenco creato dall'altro e il primo ascoltatore verrà dimenticato.

Per risolvere questo problema, modificare:

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

...

map.put( eventType, listeners );

A:

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

...

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

1) Definire la classe Manutentore come Spring bean.

Si applica la sintassi standard di Spring:

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

2) Fare in modo che tutti i tipi di ascoltatori possano registrarsi al Manutentore tramite XML utilizzando il metodo addListener.Spring Doc né Google sono molto generosi negli esempi.

Questo è più complicato.Voi Potevo utilizzo MethodInvokingFactoryBean chiamare individualmente maintainer#addListener, così:

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

Tuttavia, questo è ingombrante e potenzialmente soggetto a errori.Ho tentato qualcosa di simile su un progetto e invece ho creato una classe di utilità Spring per dare una mano.Non ho il codice sorgente disponibile al momento, quindi descriverò come implementare quello che ho fatto.

1) Rifattorizzare i tipi di eventi ascoltati in a MyListener interfaccia

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

Che cambia il metodo di registrazione in

public void addListener(MyListener listener)

2) Crea una classe helper Spring che trova tutti gli ascoltatori rilevanti nel contesto e chiama il manutentore#addListener per ogni ascoltatore trovato.Inizierei con BeanFilteringSupport, e anche implementare BeanPostProcessor (O ApplicationListener) per registrare i bean dopo che tutti i bean sono stati istanziati.

Hai detto "...Non puoi avere java.lang.enum come "Annotation Param ..."

Penso che tu abbia torto su questo.Recentemente ho utilizzato in un progetto qualcosa del genere:

public @interface MyAnnotation {
    MyEnum value();
}

Grazie a tutti per le risposte.Innanzitutto, un rapido follow-up su tutte le risposte.
1.(alexvictor) Sì, puoi avere del cemento enum come parametro di annotazione, ma non java.lang.Enum.
2.La risposta fornita da Flicken è corretta, ma sfortunatamente un po' spaventosa.Non sono un esperto di Spring, ma fare le cose in questo modo (creando metodi per facilitare l'accesso a Spring) sembra essere un po' eccessivo, così come lo è MetodoInvokingFactoryBean soluzione.Anche se volevo esprimere i miei sinceri ringraziamenti per il tuo tempo e il tuo impegno.
3.La risposta di Phill è un po' insolita (invece di inserire il bean del listener, inserire il suo manutentore!), ma, credo, la più pulita di tutte quelle disponibili.Penso che seguirò questa strada.

Ancora una volta, un grande grazie per il tuo aiuto.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top