• spring事件机制


    前置知识补充:

     程序里面所谓的“上下文”就是程序的执行环境,打个比方:你就相当于web程序,你的房子就相当于web程序的上下文,你可以在家里放东西,也可以取东西,你的衣食住行都依赖这个房子,这个房子就是你生活的上下文环境~

    ServletContext:

      ServletContext是web应用级上下文(包含listener,filter,servlet等)。web容器(比如tomcat、jboss、weblogic等)启动的时候,它会为每个web应用程序创建一个ServletContext对象 它代表当前web应用的上下文(注意:是每个web应用有且仅创建一个ServletContext,一个web应用,就是你一个web工程)。一个web中的所有servlet共享一个ServletContext对象,可以通过ServletContext对象来实现Servlet之间的通讯。HttpServlet对象可通过this.getServletContext来获取ServletContext。

    ApplicationContext:

    //ServletContext和ApplicationContext的区别和联系https://blog.csdn.net/bai_bug/article/details/80218202

      web应用中的spring的上下文,在servletContext初始化后,进行初始化,然后通过ServletContext加载applicationContext.xml。

      在web程序中使用spring的时候,我们需要配置:

    <listener>  
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>  
     </listener>  

      在web容器启动时,会触发容器初始化事件,此时ContextLoaderListener会监听到这个事件,其contextInitialized方法会被调用,在这个方法中,spring会初始化一个启动上下文,这个上下文被称为根上下文,即WebApplicationContext,这是一个接口(这个接口继承ApplicationContext这个接口),确切的说,其实际的实现类是XmlWebApplicationContext。这个就是Spring的IoC容器,在这个IoC容器初始化完毕后,Spring以WebApplicationContext.ROOTWEBAPPLICATIONCONTEXTATTRIBUTE为属性Key,将其存储到ServletContext中,便于获取。

     

    spring事件分类:

    总体框图:EventObject抽象类记录事件源,子接口ApplicationEvent记录时间戳

    Spring 提供了以下5中标准的事件:

    1. 上下文更新事件(ContextRefreshedEvent):该事件会在ApplicationContext被初始化或者更新时发布。也可以在调用ConfigurableApplicationContext 接口中的refresh()方法时被触发。
    2. 上下文开始事件(ContextStartedEvent):当容器调用ConfigurableApplicationContext的Start()方法开始/重新开始容器时触发该事件。
    3. 上下文停止事件(ContextStoppedEvent):当容器调用ConfigurableApplicationContext的Stop()方法停止容器时触发该事件。
    4. 上下文关闭事件(ContextClosedEvent):当ApplicationContext被关闭时触发该事件。容器被关闭时,其管理的所有单例Bean都被销毁。
    5. 请求处理事件(RequestHandledEvent):在Web应用中,当一个http请求(request)结束触发该事件。

    在web项目中如果同时集成了spring和springMVC的话,上下文中会存在两个容器,即spring的applicationContext.xml的父容器和springMVC的applicationContext-mvc.xml的子容器。

    在通过applicationContext发送通知的时候,事件会被两个容器发布,也就是发送用applicationContext.publishEvent()发送消息,相应的监听者会收到两次

    1. @Component  
    2. public class BeanFactory implements ApplicationContextAware {  
    3.   
    4.     private static ApplicationContext applicationContext;  
    5.   
    6.     public static <T> T getBean(String beanName, Class<T> clazz) {  
    7.         return (T) applicationContext.getBean(beanName);  
    8.     }  
    9.   
    10.     /** 
    11.      * 通知事件 
    12.      * 
    13.      * @param applicationEvent 
    14.      */  
    15.     public static void pushEvent(ApplicationEvent applicationEvent) {  
    16.         //获取父容器发送事件  
    17.         //ContextLoader.getCurrentWebApplicationContext().publishEvent(applicationEvent);  
    18.         applicationContext.publishEvent(applicationEvent);  
    19.     }  
    20.   
    21.     @Override  
    22.     public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {  
    23.         this.applicationContext = applicationContext;  
    24.     }  
    25.   
    26.     public static ApplicationContext getApplicationContext() {  
    27.         return applicationContext;  
    28.     }  
    29. }  

     解决方案的思路是用父容器去发送通知

    1. public static void pushEvent(ApplicationEvent applicationEvent) {  
    2.     //获取父容器发送事件  
    3.     ContextLoader.getCurrentWebApplicationContext().publishEvent(applicationEvent);  //ContextLoader内部维护了一个ConcurrentHashMap<ClassLoader,WebApplicationContext>//存的是根容器
    4. }

    -------------------------------------------------正题开始------------------------------------------------

    定义一个类实现ApplicationListener<ContextRefreshedEvent>接口,并把该类交给Spring来管理,并在重写方法,实现自己的业务即可,因为ContextRefreshedEvent就是Spring的启动事件,Spring启动完成就会触发该事件.

    有许多时候需要自己定义事件与监听器,如果我们都通过注入对象,调用对象对应的方法来处理,那么代码耦合度高.此时我们可以使用Spring的事件机制来处理.//A——>B,A和B耦合,解耦做法:A->C->B,引入中间者C,完成AB解耦

    接口简介:

           ApplicationEvent : 抽象类,记录了source(事件源)和初始化时间戳:用来定义Event //所有自定义事件都需要继承这个抽象类

           ApplicationEventPublisher// ApplicationEventPublisherAware(自定义发布类实现的接口) // ApplicationPublisher等: 发布消息对象,负责发布消息,调度消息的监听器;

           ApplicationListener : 负责处理某一类消息;

    流程简介:

           事件的接收者其实是一个监听器,必须实现ApplicationListener,注意把事件TradeEvent直接写到泛型中(表面此监听器是专门处理该事件的),//首先创建一个监听器,并注册到Spring容器;

           其次,在某一个事件发生的时候,创建这个事件对应的消息对象(ApplicationEvent);

           最后,通过ApplicationPublisher接口中的publishEvent方法,发布这个消息.//ApplicationContext实现这个接口,并具有调度事件监听器的方法

    补充:

      ApplicationContext这个接口是Spring的上下文,通常获取Bean就需要这个接口,这个接口并不是直接继承于BeanFactory,其中最著名的是

    直接继承了ApplicationPublisher接口,这个接口查看源码可以发现:只有一个方法,那就是主角 void publishEvent(ApplicationEvent event);

         Spring提供的基于Aware相关的接口有ApplicationContextAware,ResourceloaderAware,ServletContextAware(注意:Struts2也有这个接口,注意区分),最常用的就这三个,而Spring的事件发布机制需要用到ApplicationContextAware接口。

         实现了ApplicationContextAware的Bean,在Bean初始化时将会被注入ApplicationContext实例(因为这个感知接口里有set(ApplictationContext ctx)方法

      另外 Spring的事件监听是基于观察者模式

  • 相关阅读:
    Makefile 常用函数表
    情绪管理
    网赚呓语
    Gym 100952C&&2015 HIAST Collegiate Programming Contest C. Palindrome Again !!【字符串,模拟】
    Gym 100952B&&2015 HIAST Collegiate Programming Contest B. New Job【模拟】
    Gym 100952A&&2015 HIAST Collegiate Programming Contest A. Who is the winner?【字符串,暴力】
    HDU 1024 Max Sum Plus Plus【动态规划求最大M子段和详解 】
    HDU 1003 Max Sum【动态规划求最大子序列和详解 】
    HDU 1010 Tempter of the Bone【DFS经典题+奇偶剪枝详解】
    DFS中的奇偶剪枝学习笔记
  • 原文地址:https://www.cnblogs.com/brxHqs/p/9561127.html
Copyright © 2020-2023  润新知