spring4.2更好的应用事件

来源:互联网 发布:修车技术资料大全软件 编辑:程序博客网 时间:2024/05/22 12:16
参考:http://spring.io/blog/2015/02/11/better-application-events-in-spring-framework-4-2
对于spring4.2之前的版本,spring事件请参考:http://blog.csdn.net/xiejx618/article/details/43268307


1.基于注解驱动事件监听器:现在可以在一个Bean的方法上使用@EventListener注解来自动注册一个ApplicationListener来匹配方法签名.

@Componentpublic class MyListener {    @EventListener    public void handleContextRefresh(ContextRefreshedEvent event) {            }}
此方法签名定义了你感兴趣的事件类型.也可以定义SpELg表达式来匹配处理这个事件.假设事件的定义如下:
public class OrderCreatedEvent implements CreationEvent<Order> {    private boolean awesome;    public boolean isAwesome() {         return this.awesome;     }}
下面的例子事件监听器将同时满足以下情况才会被调用:a.它是CreationEvent<Order>类型的事件;b.此事件的awesome标志为true.

@Componentpublic class MyComponent {  @EventListener(condition = "#creationEvent.awesome")  public void handleOrderCreatedEvent(CreationEvent<Order> creationEvent) {      }}

2.上面只提到了注册事件和事件定义,再来看看事件的发布.
对于任何一个使用@EventListener注解的方法,你可以定义一个非void返回类型.如果你返回一个非null值作为处理一个常规事件的结果,我们会将此结果作为一个新事件来发送.

你可能注意到OrderCreatedEvent并没有继承ApplicationEvent,我们觉得是时候让你灵活发布任意事件,而不强迫你去继承ApplicationEvent.ApplicationEventPublisher已被扩展来允许你发布任意对象.当这个对象不是一个ApplicationEvent,我们会使用PayloadApplicationEvent来为你包装.以下例子演示了你如何使用ApplicationEventPublisher来发送一个OrderCreatedEvent:

@Componentpublic class MyComponent {    private final ApplicationEventPublisher publisher;    @Autowired    public MyComponent(ApplicationEventPublisher publisher) {this.publisher=publisher;    }    public void createOrder(Order order) {        this.publisher.publishEvent(new OrderCreatedEvent(order));     }}

3.事务边界事件
另一个受欢迎的改善是一个事件的监听器绑定到该事务一个阶段的能力。典型的例子是当事务成功完成时,再处理这个事件.下面以这样的方式重写上面的例子,当生产者运行的事务已成功完成时,此订单创建事件才会被处理.

@Componentpublic class MyComponent {  @TransactionalEventListener(condition = "#creationEvent.awesome")  public void handleOrderCreatedEvent(CreationEvent<Order> creationEvent) {   }}


功能的实现大致:

a.注册Listener:实例化spring容器的时候会注册一个org.springframework.context.event.EventListenerMethodProcessor这样的Bean,完成初始化,会调用它的兵后置回调afterSingletonsInstantiated()方法:

@Overridepublic void afterSingletonsInstantiated() {List<EventListenerFactory> factories = getEventListenerFactories();String[] allBeanNames = this.applicationContext.getBeanNamesForType(Object.class);for (String beanName : allBeanNames) {if (!ScopedProxyUtils.isScopedTarget(beanName)) {Class<?> type = this.applicationContext.getType(beanName);try {processBean(factories, beanName, type);}catch (RuntimeException e) {throw new BeanInitializationException("Failed to process @EventListener " +"annotation on bean with name '" + beanName + "'", e);}}}}
迭代每个Bean进行processBean(factories, beanName, type)处理.
protected void processBean(List<EventListenerFactory> factories, String beanName, final Class<?> type) {Class<?> targetType = getTargetClass(beanName, type);if (!this.nonAnnotatedClasses.contains(targetType)) {final Set<Method> annotatedMethods = new LinkedHashSet<Method>(1);Method[] methods = ReflectionUtils.getUniqueDeclaredMethods(targetType);for (Method method : methods) {//在这个方法上查找EventListener注解EventListener eventListener = AnnotationUtils.findAnnotation(method, EventListener.class);if (eventListener == null) {continue;}for (EventListenerFactory factory : factories) {if (factory.supportsMethod(method)) {if (!type.equals(targetType)) {method = getProxyMethod(type, method);}//使用这个方法创建一个ApplicationListener对象ApplicationListener<?> applicationListener =factory.createApplicationListener(beanName, type, method);if (applicationListener instanceof ApplicationListenerMethodAdapter) {((ApplicationListenerMethodAdapter)applicationListener).init(this.applicationContext, this.evaluator);}//添加到applicationContext的事件广播器this.applicationContext.addApplicationListener(applicationListener);annotatedMethods.add(method);break;}}}if (annotatedMethods.isEmpty()) {this.nonAnnotatedClasses.add(type);if (logger.isTraceEnabled()) {logger.trace("No @EventListener annotations found on bean class: " + type);}}else {// Non-empty set of methodsif (logger.isDebugEnabled()) {logger.debug(annotatedMethods.size() + " @EventListener methods processed on bean '" + beanName +"': " + annotatedMethods);}}}}
b.通过ApplicationEventPublisher发布事件:入口在org.springframework.context.support.AbstractApplicationContext#publishEvent(java.lang.Object),再调用重载方法
protected void publishEvent(Object event, ResolvableType eventType) {Assert.notNull(event, "Event must not be null");if (logger.isTraceEnabled()) {logger.trace("Publishing event in " + getDisplayName() + ": " + event);}final ApplicationEvent applicationEvent;//这里可以看出如果event不是ApplicationEvent类型,就会使用PayloadApplicationEvent进行包装if (event instanceof ApplicationEvent) {applicationEvent = (ApplicationEvent) event;}else {applicationEvent = new PayloadApplicationEvent<Object>(this, event);if (eventType == null) {eventType = ResolvableType.forClassWithGenerics(PayloadApplicationEvent.class, event.getClass());}}//通过事件广播器进行广播事件getApplicationEventMulticaster().multicastEvent(applicationEvent, eventType);if (this.parent != null) {if (this.parent instanceof AbstractApplicationContext) {((AbstractApplicationContext) this.parent).publishEvent(event, eventType);}else {this.parent.publishEvent(event);}}}


0 4