10.容器事件和事件监听器

工程结构

lqf-spring-step-10
├── main
│   ├── java
│   │   └── lqf
│   │       └── springframework
│   │           ├── beans
│   │           │   ├── BeansException.java
│   │           │   ├── PropertyValue.java
│   │           │   ├── PropertyValues.java
│   │           │   └── factory
│   │           │       ├── Aware.java
│   │           │       ├── BeanClassLoaderAware.java
│   │           │       ├── BeanFactory.java
│   │           │       ├── BeanFactoryAware.java
│   │           │       ├── BeanNameAware.java
│   │           │       ├── ConfigurableListableBeanFactory.java
│   │           │       ├── DisposableBean.java
│   │           │       ├── FactoryBean.java
│   │           │       ├── HierarchicalBeanFactory.java
│   │           │       ├── InitializingBean.java
│   │           │       ├── ListableBeanFactory.java
│   │           │       ├── config
│   │           │       │   ├── AutowireCapableBeanFactory.java
│   │           │       │   ├── BeanDefinition.java
│   │           │       │   ├── BeanFactoryPostProcessor.java
│   │           │       │   ├── BeanPostProcessor.java
│   │           │       │   ├── BeanReference.java
│   │           │       │   ├── ConfigurableBeanFactory.java
│   │           │       │   └── SingletonBeanRegistry.java
│   │           │       ├── support
│   │           │       │   ├── AbstractAutowireCapableBeanFactory.java
│   │           │       │   ├── AbstractBeanDefinitionReader.java
│   │           │       │   ├── AbstractBeanFactory.java
│   │           │       │   ├── BeanDefinitionReader.java
│   │           │       │   ├── BeanDefinitionRegistry.java
│   │           │       │   ├── CglibSubclassingInstantiationStrategy.java
│   │           │       │   ├── DefaultListableBeanFactory.java
│   │           │       │   ├── DefaultSingletonBeanRegistry.java
│   │           │       │   ├── DisposableBeanAdapter.java
│   │           │       │   ├── FactoryBeanRegistrySupport.java
│   │           │       │   ├── InstantiationStrategy.java
│   │           │       │   └── SimpleInstantiationStrategy.java
│   │           │       └── xml
│   │           │           └── XmlBeanDefinitionReader.java
│   │           ├── context
│   │           │   ├── ApplicationContext.java
│   │           │   ├── ApplicationContextAware.java
│   │           │   ├── ApplicationEvent.java
│   │           │   ├── ApplicationEventPublisher.java
│   │           │   ├── ApplicationListener.java
│   │           │   ├── ConfigurableApplicationContext.java
│   │           │   ├── event
│   │           │   │   ├── AbstractApplicationEventMulticaster.java
│   │           │   │   ├── ApplicationContextEvent.java
│   │           │   │   ├── ApplicationEventMulticaster.java
│   │           │   │   ├── ContextClosedEvent.java
│   │           │   │   ├── ContextRefreshedEvent.java
│   │           │   │   └── SimpleApplicationEventMulticaster.java
│   │           │   └── support
│   │           │       ├── AbstractApplicationContext.java
│   │           │       ├── AbstractRefreshableApplicationContext.java
│   │           │       ├── AbstractXmlApplicationContext.java
│   │           │       ├── ApplicationContextAwareProcessor.java
│   │           │       └── ClassPathXmlApplicationContext.java
│   │           ├── core
│   │           │   └── io
│   │           │       ├── ClassPathResource.java
│   │           │       ├── DefaultResourceLoader.java
│   │           │       ├── FileSystemResource.java
│   │           │       ├── Resource.java
│   │           │       ├── ResourceLoader.java
│   │           │       └── UrlResource.java
│   │           └── util
│   │               └── ClassUtils.java
│   └── resources
└── test
    ├── java
    │   └── lqf
    │       └── springframework
    │           ├── SpringTest.java
    │           └── event
    │               ├── ContextClosedEventListener.java
    │               ├── ContextRefreshedEventListener.java
    │               ├── CustomEvent.java
    │               └── CustomEventListener.java
    └── resources
        ├── important.properties
        ├── spring.xml
        └── springPostProcessor.xml

容器事件和事件监听器实现类关系,如图:

  • 以上整个类关系图以围绕实现 event 事件定义、发布、监听功能实现和把事件的相关内容使用 AbstractApplicationContext#refresh
    进行注册和处理操作。
  • 在实现的过程中主要以扩展 spring context 包为主,事件的实现也是在这个包下进行扩展的,当然也可以看出来目前所有的实现内容,仍然是以IOC为主。
  • ApplicationContext 容器继承事件发布功能接口 ApplicationEventPublisher,并在实现类中提供事件监听功能。
  • ApplicationEventMulticaster 接口是注册监听器和发布事件的广播器,提供添加、移除和发布事件方法。
  • 最后是发布容器关闭事件,这个仍然需要扩展到 AbstractApplicationContext#close 方法中,由注册到虚拟机的钩子实现。

设计

在 Spring 框架中,事件监听器的设计和实现,是为了让使用者可以在容器初始化、刷新、关闭等过程中,可以自定义一些操作,这样就可以在容器的生命周期
中,做一些自己想要的操作。

在功能实现上我们需要定义出事件类、事件监听、事件发布,而这些类的功能需要结合到 Spring 的
AbstractApplicationContext#refresh(),以便于处理事件初始化和注册事件监听器的操作。
整体设计结构如下图:

  • 在整个功能实现过程中,仍然需要在面向用户的应用上下文 AbstractApplicationContext
    中添加相关事件内容,包括:初始化事件发布者、注册事件监听器、发布容器刷新完成事件。
  • 使用观察者模式定义事件类、监听类、发布类,同时还需要完成一个广播器的功能,接收到事件推送时进行分析处理符合监听事件接受者感兴趣的事件,也就是使用
    isAssignableFrom 进行判断。
  • isAssignableFrom 和 instanceof 相似,不过 isAssignableFrom
    是用来判断子类和父类的关系的,或者接口的实现类和接口的关系的,默认所有的类的终极父类都是Object。如果A.isAssignableFrom(B)
    结果是true,证明B可以转换成为A,也就是A可以由B转换而来。

实现

定义和实现事件

源码1: lqf.springframework.context.ApplicationEvent

  • 以继承 java.util.EventObject 定义出具备事件功能的抽象类 ApplicationEvent,后续所有事件的类都需要继承这个类。

源码2: lqf.springframework.context.event.ApplicationContextEvent
源码3: lqf.springframework.context.event.ContextClosedEvent
源码4: lqf.springframework.context.event.ContextRefreshedEvent

  • ApplicationEvent 是定义事件的抽象类,所有的事件包括关闭、刷新,以及用户自己实现的事件,都需要继承这个类。
  • ContextClosedEvent、ContextRefreshedEvent,分别是 Spring 框架自己实现的两个事件类,可以用于监听刷新和关闭动作。

事件广播器

源码1: lqf.springframework.context.event.ApplicationEventMulticaster

  • 在事件广播器中定义了添加监听和删除监听的方法以及一个广播事件的方法 multicastEvent 最终推送时间消息也会经过这个接口方法来处理谁该接收事件。

源码2: lqf.springframework.context.event.AbstractApplicationEventMulticaster

  • 在 AbstractApplicationEventMulticaster 中实现了 ApplicationEventMulticaster 接口,提供了一个监听器的注册和移除的操作,以及一个广播事件的操作。
  • 除了像 addApplicationListener、removeApplicationListener,这样的通用方法,这里这个类中主要是对 getApplicationListeners 和
    supportsEvent 的处理。 getApplicationListeners 方法主要是摘取符合广播事件中的监听处理器,具体过滤动作在 supportsEvent
    方法中。
  • 在 supportsEvent 方法中,主要包括对Cglib、Simple不同实例化需要获取目标Class,Cglib代理类需要获取父类的Class,普通实例化的不需要。接下来就是通过提取接口和对应的
    ParameterizedType 和 eventClassName,方便最后确认是否为子类和父类的关系,以此证明此事件归这个符合的类处理。

supportsEvent 方法运行截图

  • 在代码调试中可以看到,最终 eventClassName 和 event.getClass() 在 isAssignableFrom 判断下为 true
  • 关于 CglibSubclassingInstantiationStrategy、SimpleInstantiationStrategy 可以尝试在 AbstractApplicationContext 类中更换验证。

事件发布者的定义和实现

源码1: lqf.springframework.context.ApplicationEventPublisher

  • ApplicationEventPublisher 是整个一个事件的发布接口,所有的事件都需要从这个接口发布出去。

源码2: lqf.springframework.context.support.AbstractApplicationContext

  • 在抽象应用上下文 AbstractApplicationContext#refresh
    中,主要新增了 初始化事件发布者注册事件监听器发布容器刷新完成事件,三个方法用于处理事件操作。
  • 初始化事件发布者(initApplicationEventMulticaster),主要用于实例化一个 SimpleApplicationEventMulticaster,这是一个事件广播器。
  • 注册事件监听器(registerListeners),通过 getBeansOfType 方法获取到所有从 spring.xml 中加载到的事件配置 Bean 对象。
    发布容器刷新完成事件(finishRefresh),发布了第一个服务器启动完成后的事件,这个事件通过 publishEvent 发布出去,其实也就是调用了
    applicationEventMulticaster.multicastEvent(event); 方法。
  • 最后是一个 close 方法中,新增加了发布一个容器关闭事件。publishEvent(new ContextClosedEvent(this));

总结

  • 在整个手写 Spring 框架的学习过程中,可以逐步看到很多设计模式的使用,比如:简单工厂BeanFactory、工厂方法FactoryBean、策略模式访问资源,现在又实现了一个观察者模式的具体使用。所以学习
    Spring 的过程中,要更加注意关于设计模式的运用。

  • 关于观察者模式的实现过程,主要包括了事件的定义、事件的监听和发布事件,发布完成后根据匹配策略,监听器就会收到属于自己的事件内容,并做相应的处理动作,这样的观察者模式其实日常我们也经常使用,不过在结合Spring 以后,除了设计模式的学习,还可以学到如何把相应观察者的实现和应用上下文结合。

    返回目录