Pregunta

Supongamos que tenemos el siguiente código 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 );
   }
}

Este fragmento de código es nada pero un poco mejorado escucha patrón donde cada oyente está diciendo qué tipo de evento que está interesado en, y el método mantiene un concurrente mapa de estas relaciones.

Al principio, yo quería que este método sea llamado a través de mi propia anotación de marco, pero se topó con una pared de ladrillo de varios anotación limitaciones (por ejemplo,usted no puede tener java.lang.Enum como anotación param, también hay un conjunto de diversos cargador de clases de problemas), por lo que decidió utilizar la Primavera.

Alguien podría decirme cómo puedo Spring_ify_ esto?Lo que quiero conseguir es:
1.Definir Mantenedor de la clase como un Resorte de frijol.
2.Se hacen para que todo tipo de oyentes sería capaz de registrar para Mantenedor de a través de XML mediante el uso de addListener método.La primavera doc ni Google son muy generosas en los ejemplos.

Hay una manera de lograr esto fácilmente?

¿Fue útil?

Solución

¿Qué sería malo en hacer algo como lo siguiente:

La definición de un "Mantenedor" de la interfaz con el método addListener(el que Escucha, Enum) método.

Crear un DefaultMaintainer de clase (como el anterior), que implementa el Mantenedor.

Luego, en cada clase de Escucha, 'inyectar' el Mantenedor de la interfaz (inyección de constructor podría ser una buena opción).El oyente puede registrarse a sí mismo con el Mantenedor.

aparte de eso, yo no estoy 100% claro sobre exactamente lo que su dificultad es con la Primavera en el momento!:)

Otros consejos

Ligeramente offtopic (como esto no es acerca de la Primavera), pero no es una condición de carrera en la implementación de AddListener:

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

Si dos hilos de llamar a este método al mismo tiempo (para un tipo de evento que anteriormente no había ninguna oyentes), mapa.get( eventType ) devolverá el valor null en ambos hilos, cada hilo va a crear su propio CopyOnWriteArrayList (cada una contiene un único oyente), un hilo reemplazará a la lista creada por el otro, y el primer oyente va a ser olvidado.

Para solucionar este problema, cambie:

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) Definir el Mantenedor de la clase como un Resorte de frijol.

Estándar de la Primavera sintaxis se aplica:

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

2) Hacer que todo tipo de oyentes sería capaz de registrar para Mantenedor a través de XML mediante el método addListener.La primavera doc ni Google son muy generosas en los ejemplos.

Esto es más complicado.Usted podría uso MethodInvokingFactoryBean para llamar de forma individual maintainer#addListener, así:

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

Sin embargo, esto es difícil de manejar, y potencialmente propenso a errores.He intentado algo similar en un proyecto, y creó un Resorte clase de utilidad para ayudar en su lugar.No tengo el código fuente disponible en el momento, así que voy a describir cómo implementar lo que hice.

1) Refactorizar los tipos de eventos escuchado en un MyListener interfaz

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

Lo que cambia el método de registro a

public void addListener(MyListener listener)

2) Crear la Primavera de clase auxiliar que se encuentra todos los oyentes en el contexto, y las llamadas mantenedor#addListener para cada oyente encontrado.Me gustaría empezar con BeanFilteringSupport, y también implementar BeanPostProcessor (o ApplicationListener) para el registro de los granos después de que todos los granos se han instanciado.

Usted dijo "...usted no puede tener java.lang.Enum como" anotación param ..."

Creo que estás equivocado en eso.Recientemente he utilizado en un proyecto algo como esto :

public @interface MyAnnotation {
    MyEnum value();
}

Gracias a todos por las respuestas.En primer lugar, Un rápido seguimiento de todas las respuestas.
1.(alexvictor) Sí, usted puede tener de hormigón enum como anotación param, pero no java.lang.Enum.
2.La respuesta proporcionada por flicken es correcta, pero lamentablemente un poco de miedo.Yo no soy un Resorte experto, pero haciendo las cosas de esta manera (la creación de métodos para facilitar la Primavera de acceso) esto parece ser un poco excesivo, como es el MethodInvokingFactoryBean solución.Aunque yo quería expresar mi más sincero agradecimiento por su tiempo y esfuerzo.
3.La respuesta por Phill es un poco inusual (en lugar de la inyección de agente de escucha de frijol, inyecta su mantenedor!), pero, creo, el más limpio de todos los disponibles.Creo que voy a ir por este camino.

De nuevo, mil gracias por su ayuda.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top