zoukankan      html  css  js  c++  java
  • spring4.2更好的应用事件

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

    @Component  
    public 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.

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

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

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

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

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

    功能的实现大致:

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

    @Override  
    public 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 methods  
                if (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);  
            }  
        }  
    }  
  • 相关阅读:
    UNIGUI如何禁止关闭新窗口
    【转】华为编码规范
    awk中 使用shell的环境变量
    【转】SDL与MFC的混合
    MSSQL学习笔记
    转 在.NET环境下为网站增加IP过滤功能
    欢迎加入asp.net交流群
    配置SQL Server2005以允许远程访问
    实用的文件操作类
    VS2005 + VSS2005 实现团队开发、源代码管理、版本
  • 原文地址:https://www.cnblogs.com/xunianchong/p/6839549.html
Copyright © 2011-2022 走看看