En Spring 4.2+, podemos usar la anotación @EventListener con una expresión de "condición".
En mi escenario, necesito hacer coincidir la identificación del objeto de evento con una expresión regular que está configurada en un archivo .properties.
Sin embargo, parece imposible hacer referencia a cualquier propiedad o método de bean desde la expresión regular de la condición, ya que el contexto raíz parece ser el objeto de evento en sí.
Hasta ahora, tengo una clase abstracta que establece la propiedad del patrón de identificación del evento en función del nombre de la clase. El objetivo es hacer que la implementación de cada Event Listener sea lo más limpia y simple posible.
@Service @PropertySource(value = "classpath:subscriberEventMapping.properties") public abstract class AbstractEventHandler implements IEventHandler { private String eventIdPattern; @Autowired Environment env; @Autowired(required = true) public void configureEventIdPattern() { String simpleClassName = this.getClass().getSimpleName(); String resolvedEventIdPattern = env.getProperty( simpleClassName.substring(0,1).toLowerCase() + simpleClassName.substring(1, simpleClassName.length())); this.eventIdPattern = resolvedEventIdPattern == null ? ".*" : resolvedEventIdPattern; } public String getEventIdPattern() { return eventIdPattern; } }El archivo de propiedades se ve así:
regExpEventHandler=^(901|909|998|1000)$ dummyEventHandler=^([1-9][0-9]{0,2}|1000)$Y luego, tengo un detector de eventos de muestra que amplía la clase abstracta anterior:
@Service public class RegExpEventHandler extends AbstractEventHandler { @Log private ILog logger; @Override @EventListener(condition = "#event.eventid matches @regExpEventHandler.getEventIdPattern()") public void onEvent(Event event) { logger.debug("RegExpEventHandler processing : {} with event pattern : {}", event, getEventIdPattern()); } }El problema es que la expresión
"#event.eventid coincide con @regExpEventHandler.getEventIdPattern()"
no funciona, porque el bean "@regExpEventHandler" no se puede encontrar en el contexto utilizado por @EventListener.
¿Hay alguna forma de acceder a los métodos o propiedades de un Spring Bean existente aquí? ¿Algún otro enfoque mejor para este escenario?
Sé que puedo acceder fácilmente a constantes o métodos ESTÁTICOS usando algo como:
#event.eventid matches T(my.package.RegExpEventHandler.MY_CONSTANT)Pero una constante de cadena (final estática) no se puede inicializar desde un archivo de propiedades usando una expresión @Value.
El uso de constantes estáticas NO FINALES puede funcionar, pero luego CADA Event Listener necesita agregar una placa estándar para inicializar la constante estática de una variable no estática usando una expresión @Value, que queremos evitar.
Muchas gracias por adelantado !
Funciona para mí: miré EventExpressionEvaluator y vi que agregó un solucionador de beans al contexto de evaluación ...
public EvaluationContext createEvaluationContext(ApplicationEvent event, Class<?> targetClass, Method method, Object[] args, BeanFactory beanFactory) { Method targetMethod = getTargetMethod(targetClass, method); EventExpressionRootObject root = new EventExpressionRootObject(event, args); MethodBasedEvaluationContext evaluationContext = new MethodBasedEvaluationContext( root, targetMethod, args, getParameterNameDiscoverer()); if (beanFactory != null) { evaluationContext.setBeanResolver(new BeanFactoryResolver(beanFactory)); } return evaluationContext; }Así que escribí una prueba rápida...
@SpringBootApplication public class So43225913Application { public static void main(String[] args) { ConfigurableApplicationContext context = SpringApplication.run(So43225913Application.class, args); context.publishEvent("foo"); } @EventListener(condition = "@bar.accept(event)") public void listen(Object event) { System.out.println("handler:" + event); } @Bean public Bar bar() { return new Bar(); } public static class Bar { public boolean accept(Object o) { System.out.println("bar:" + o); return true; } } }Y funciona bien...
bar:org.springframework.context.PayloadApplicationEvent[... handler:foo(Esto fue con 4.3.7; arranque 1.5.2).