手写Spring:第11章-容器事件和事件监听器

文章目录

  • 一、目标:容器事件和事件监听器
  • 二、设计:容器事件和事件监听器
  • 三、实现:容器事件和事件监听器
    • 3.1 工程结构
    • 3.2 容器事件和事件监听器类图
    • 3.3 定义和实现事件
      • 3.3.1 定义事件抽象类
      • 3.3.2 定义应用上下文事件实现类
      • 3.3.3 上下文刷新事件类
      • 3.3.4 上下文关闭事件类
    • 3.4 事件监听器
      • 3.4.1 类工具类添加判断代理对象
      • 3.4.2 事件监听器
    • 3.5 事件广播器
      • 3.5.1 事件广播器接口
      • 3.5.2 事件广播器抽象类
      • 3.5.3 简单事件广播器
    • 3.6 事件发布者的定义和实现
      • 3.6.1 定义事件发布者
      • 3.6.2 应用上下文接口
      • 3.6.3 应用上下文抽象类
  • 四、测试:容器事件和事件监听器
    • 4.1 添加测试配置
      • 4.1.1 创建自定义事件
      • 4.1.2 自定义事件监听器
      • 4.1.3 自定义事件刷新监听器
      • 4.1.4 自定义事件关闭监听器
      • 4.1.5 配置文件
    • 4.2 单元测试
  • 五、总结:容器事件和事件监听器

一、目标:容器事件和事件监听器

如何处理解耦?什么是事件?如何使用事件功能?

  • Spring 中有一个 Event 事件功能,它可以提供事件的定义、发布以及监听事件来完成一些自定义的动作。
    • 比如:你可以定义一个新用户注册的事件,当有用户执行注册完成后,在事件监听中给用户发送一些优惠券和短信提醒。
    • 这样的操作就可以把属于基本功能的注册和对应的策略服务分开,降低系统的耦合。
    • 以后再扩展注册服务,比如需要添加风控策略、添加实名认证、判断用户属性等都不会影响到依赖注册成功后执行的动作。
  • 本节需要以观察者模式的方式,设计和实现 Spring Event 的容器事件和事件监听器功能。
    • 最终可以让 Spring 框架可以定义、监听和发布自己的事件信息。

二、设计:容器事件和事件监听器

设计:观察者模式,实现 Spring Event 容器时间和事件监听器。

  • 事件 的设计本身就是一种观察者模式的实现,它所要解决的就是一个对象状态改变给其他对象通知的问题,而且要考虑到易用和低耦合,保证高度的协作。
  • 再功能上我们需要定义:事件类、事件监听、事件发布。
    • 这些类的功能需要结合到 SpringAbstractApplicationContext#refresh(),以便于处理事件初始化和注册事件监听器的操作。

手写Spring:第11章-容器事件和事件监听器_第1张图片

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

三、实现:容器事件和事件监听器

3.1 工程结构

spring-step-10
|-src
	|-main
	|	|-java
	|		|-com.lino.springframework
	|			|-beans
	|			|	|-factory
	|			|	|	|-config
	|			|	|	|	|-AutowireCapableBeanFactory.java
	|			|	|	|	|-BeanDefinition.java
	|			|	|	|	|-BeanFactoryPostProcessor.java
	|			|	|	|	|-BeanPostProcessor.java
	|			|	|	|	|-BeanReference.java
	|			|	|	|	|-ConfigurableBeanFactory.java
	|			|	|	|	|-SingletonBeanRegistry.java
	|			|	|	|-support
	|			|	|	|	|-AbstractAutowireCapableBeanFactory.java
	|			|	|	|	|-AbstractBeabDefinitionReader.java
	|			|	|	|	|-AbstractBeabFactory.java
	|			|	|	|	|-BeabDefinitionReader.java
	|			|	|	|	|-BeanDefinitionRegistry.java
	|			|	|	|	|-CglibSubclassingInstantiationStrategy.java
	|			|	|	|	|-DefaultListableBeanFactory.java
	|			|	|	|	|-DefaultSingletonBeanRegistry.java
	|			|	|	|	|-DisposableBeanAdapter.java
	|			|	|	|	|-FactoryBeanRegistrySupport.java
	|			|	|	|	|-InstantiationStrategy.java
	|			|	|	|	|-SimpleInstantiationStrategy.java
	|			|	|	|-support
	|			|	|	|	|-XMLBeanDefinitionReader.java
	|			|	|	|-Aware.java
	|			|	|	|-BeanClassLoaderAware.java
	|			|	|	|-BeanFactory.java
	|			|	|	|-BeanFactoryAware.java
	|			|	|	|-BeanNameAware.java
	|			|	|	|-ConfigurableListableBeanFactory.java
	|			|	|	|-DisposableBean.java
	|			|	|	|-FactoryBean.java
	|			|	|	|-HierarcgicalBeanFactory.java
	|			|	|	|-InitializingBean.java
	|			|	|	|-ListableBeanFactory.java
	|			|	|-BeansException.java
	|			|	|-PropertyValue.java
	|			|	|-PropertyValues.java
	|			|-context
	|			|	|-event
	|			|	|	|-AbstractApplicationEventMulticaster.java
	|			|	|	|-ApplicationContextEvent.java
	|			|	|	|-ApplicationEventMulticaster.java
	|			|	|	|-ContextclosedEvent.java
	|			|	|	|-ContextRefreshedEvent.java
	|			|	|	|-SimpleApplicationEventMulticaster.java
	|			|	|-support
	|			|	|	|-AbstractApplicationContext.java
	|			|	|	|-AbstractRefreshableApplicationContext.java
	|			|	|	|-AbstractXmlApplicationContext.java
	|			|	|	|-ApplicationContextAwareProcessor.java
	|			|	|	|-ClassPathXmlApplicationContext.java
	|			|	|-ApplicationContext.java
	|			|	|-ApplicationContextAware.java
	|			|	|-ApplicationEvent.java
	|			|	|-ApplicationEventPublisher.java
	|			|	|-ApplicationListener.java
	|			|	|-ConfigurableApplicationContext.java
	|			|-core.io
	|			|	|-ClassPathResource.java
	|			|	|-DefaultResourceLoader.java
	|			|	|-FileSystemResource.java
	|			|	|-Resource.java
	|			|	|-ResourceLoader.java
	|			|	|-UrlResource.java
	|			|-util
	|			|	|-ClassUtils.java
	|-test
		|-java
			|-com.lino.springframework.test
                |-event
                |	|-CustomClosedEventListener.java
                |	|-CustomEvent.java
                |	|-CustomEventListener.java
                |	|-CustomRefreshedEventListener.java
                |-ApiTest.java
		|-resources
			|-spring.xml

3.2 容器事件和事件监听器类图

手写Spring:第11章-容器事件和事件监听器_第2张图片

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

3.3 定义和实现事件

3.3.1 定义事件抽象类

ApplicationEvent.java

package com.lino.springframework.context;

import java.util.EventObject;

/**
 * @description: 定义事件抽象类
 */
public abstract class ApplicationEvent extends EventObject {
    /**
     * Constructs a prototypical Event.
     *
     * @param source The object on which the Event initially occurred.
     * @throws IllegalArgumentException if source is null.
     */
    public ApplicationEvent(Object source) {
        super(source);
    }
}
  • 以继承 java.util.EventObject 定义出具备事件功能的抽象类 ApplicationEvent,后续所有事件的类都需要继承这个类。

3.3.2 定义应用上下文事件实现类

ApplicationContextEvent.java

package com.lino.springframework.context.event;

import com.lino.springframework.context.ApplicationContext;
import com.lino.springframework.context.ApplicationEvent;

/**
 * @description: 定义应用上下文事件实现类
 */
public class ApplicationContextEvent extends ApplicationEvent {
    /**
     * Constructs a prototypical Event.
     *
     * @param source The object on which the Event initially occurred.
     * @throws IllegalArgumentException if source is null.
     */
    public ApplicationContextEvent(Object source) {
        super(source);
    }

    /**
     * 获取应用上下文
     *
     * @return 应用上下文
     */
    public final ApplicationContext getApplicationContext() {
        return (ApplicationContext) getSource();
    }
}

3.3.3 上下文刷新事件类

ContextRefreshedEvent.java

package com.lino.springframework.context.event;

/**
 * @description: 上下文刷新事件类
 */
public class ContextRefreshedEvent extends ApplicationContextEvent {

    /**
     * Constructs a prototypical Event.
     *
     * @param source The object on which the Event initially occurred.
     * @throws IllegalArgumentException if source is null.
     */
    public ContextRefreshedEvent(Object source) {
        super(source);
    }
}

3.3.4 上下文关闭事件类

ContextClosedEvent.java

package com.lino.springframework.context.event;

/**
 * @description: 上下文关闭事件类
 */
public class ContextClosedEvent extends ApplicationContextEvent {

    /**
     * Constructs a prototypical Event.
     *
     * @param source The object on which the Event initially occurred.
     * @throws IllegalArgumentException if source is null.
     */
    public ContextClosedEvent(Object source) {
        super(source);
    }
}
  • ApplicationContextEvent 是定义事件的类,所有的事件包括关闭、刷新,以及用户自己实现的事件,都需要继承这个类。
  • ContextRefreshedEventContextClosedEvent,分别是 Spring 框架自己实现的两个事件类,可以用于监听刷新和关闭动作。

3.4 事件监听器

3.4.1 类工具类添加判断代理对象

ClassUtils.java

package com.lino.springframework.util;

/**
 * @description: 类工具类
 */
public class ClassUtils {

    /**
     * 获取默认类加载器
     *
     * @return 类加载器
     */
    public static ClassLoader getDefaultClassLoader() {
        ClassLoader cl = null;
        try {
            cl = Thread.currentThread().getContextClassLoader();
        } catch (Throwable ex) {
            // Cannot access thread context ClassLoader - falling back to system class loader...
        }
        if (cl == null) {
            // No thread context class loader -> use class loader of this class.
            cl = ClassUtils.class.getClassLoader();
        }
        return cl;
    }

    /**
     * 判断类是否是cglib代理对象
     *
     * @param clazz 类
     * @return 是否是cglib代理对象
     */
    public static boolean isCglibProxyClass(Class<?> clazz) {
        return (clazz != null && isCglibProxyClassName(clazz.getName()));
    }

    /**
     * 判断类名是否符合cglib代理类命名
     *
     * @param className 类名
     * @return 是否符合cglib代理类命名
     */
    public static boolean isCglibProxyClassName(String className) {
        return (className != null && className.contains("$$"));
    }
}
  • 添加判断是否是 cglib 代理对象和是否符合 cglib 代理名称的方法。

3.4.2 事件监听器

ApplicationListener.java

package com.lino.springframework.context;

import java.util.EventListener;

/**
 * @description: 事件监听器
 * @author: lingjian
 * @createDate: 2022/12/1 15:01
 */
public interface ApplicationListener<E extends ApplicationEvent> extends EventListener {

    /**
     * 处理事件
     *
     * @param event 事件
     */
    void onApplicationEvent(E event);
}
  • 添加监听器开放接口,后续开放给外部实现调用。

3.5 事件广播器

3.5.1 事件广播器接口

ApplicationEventMulticaster.java

package com.lino.springframework.context.event;

import com.lino.springframework.context.ApplicationEvent;
import com.lino.springframework.context.ApplicationListener;

/**
 * @description: 事件广播器
 */
public interface ApplicationEventMulticaster {

    /**
     * 添加监听器
     *
     * @param listener 监听器
     */
    void addApplicationListener(ApplicationListener<?> listener);

    /**
     * 删除监听器
     *
     * @param listener 监听器
     */
    void removeApplicationListener(ApplicationListener<?> listener);

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

3.5.2 事件广播器抽象类

AbstractApplicationEventMulticaster.java

package com.lino.springframework.context.event;

import com.lino.springframework.beans.BeansException;
import com.lino.springframework.beans.factory.BeanFactory;
import com.lino.springframework.beans.factory.BeanFactoryAware;
import com.lino.springframework.context.ApplicationEvent;
import com.lino.springframework.context.ApplicationListener;
import com.lino.springframework.util.ClassUtils;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.Collection;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.Set;

/**
 * @description: 事件广播器抽象类
 */
public abstract class AbstractApplicationEventMulticaster implements ApplicationEventMulticaster, BeanFactoryAware {

    public final Set<ApplicationListener<ApplicationEvent>> applicationListeners = new LinkedHashSet<>();

    private BeanFactory beanFactory;

    @Override
    public void addApplicationListener(ApplicationListener<?> listener) {
        applicationListeners.add((ApplicationListener<ApplicationEvent>) listener);
    }

    @Override
    public void removeApplicationListener(ApplicationListener<?> listener) {
        applicationListeners.remove(listener);
    }

    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        this.beanFactory = beanFactory;
    }

    /**
     * 获取事件监听器
     *
     * @param event 事件
     * @return 监听器列表
     */
    protected Collection<ApplicationListener> getApplicationListeners(ApplicationEvent event) {
        LinkedList<ApplicationListener> allListeners = new LinkedList<>();
        for (ApplicationListener<ApplicationEvent> listener : applicationListeners) {
            if (supportsEvent(listener, event)) {
                allListeners.add(listener);
            }
        }
        return allListeners;
    }

    /**
     * 监听器是否该事件感兴趣
     *
     * @param applicationListener 监听器
     * @param event               事件
     * @return 是否感兴趣
     */
    protected boolean supportsEvent(ApplicationListener<ApplicationEvent> applicationListener, ApplicationEvent event) {
        Class<? extends ApplicationListener> listenerClass = applicationListener.getClass();

        // 按照 CglibSubclassingInstantiationStrategy、SimpleInstantiationStrategy 不同的实例化类型,需要判断后获取目标 class
        Class<?> targetClass = ClassUtils.isCglibProxyClass(listenerClass) ? listenerClass.getSuperclass() : listenerClass;
        Type genericInterface = targetClass.getGenericInterfaces()[0];

        Type actualTypeArgument = ((ParameterizedType) genericInterface).getActualTypeArguments()[0];
        String className = actualTypeArgument.getTypeName();
        Class<?> eventClassName;
        try {
            eventClassName = Class.forName(className);
        } catch (ClassNotFoundException e) {
            throw new BeansException("wrong event class name:" + className);
        }

        // 判断此 eventClassName 对象所表示的类或接口与指定的 event.getClass() 参数所表示的类或接口是否相同,或是否是超类或超接口
        // isAssignableFrom是用来判断子类和父类的关系的,或者接口的实现类和接口的关系的,默认所有的类的终极父类都是Object。
        // 如果A.isAssignableFrom(B)结果是true,证明B可以转换成为A,也就是A可以由B转换而来。
        return eventClassName.isAssignableFrom(event.getClass());
    }
}
  • AbstractApplicationEventMulticaster 是对事件广播器的公用方法提取,在这个类中可以实现一些基本功能,避免所有直接实现接口还需要处理细节。
  • 除了像 addApplicationListenerremoveApplicationListener 这样的通用方法。这里主要是对 getApplicationListenerssupportsEvent 的处理。
    • getApplicationListeners:主要是摘取符合广播事件中的监听处理器,具体过滤动作在 supportsEvent 方法中。
    • supportsEvent
      • 主要包括对 Cglib、Simple 不同实例化需要获取父类的 ClassCglib 代理类需要获取父类的 Class。普通实例化则不需要。
      • 接下来就是通过提取接口和对应的 ParameterizedTypeeventClassName,方便最后确认是否为子类和父类的关系,以此证明此事件归这个符合的类处理。

手写Spring:第11章-容器事件和事件监听器_第3张图片

  • 从结果看出,最终 eventClassNameevent.getClass()isAssignableFrom 判断下为 true
  • 关于 CglibSubclassingInstantiationStrategy、SimpleInstantiationStrategy 可以尝试在 AbstractApplicationContext 类中更换验证。

3.5.3 简单事件广播器

SimpleApplicationEventMulticaster.java

package com.lino.springframework.context.event;

import com.lino.springframework.beans.factory.BeanFactory;
import com.lino.springframework.context.ApplicationEvent;
import com.lino.springframework.context.ApplicationListener;

/**
 * @description: 简单事件广播器
 */
public class SimpleApplicationEventMulticaster extends AbstractApplicationEventMulticaster {

    public SimpleApplicationEventMulticaster(BeanFactory beanFactory) {
        setBeanFactory(beanFactory);
    }

    @SuppressWarnings("unchecked")
    @Override
    public void multicastEvent(final ApplicationEvent event) {
        for (final ApplicationListener listener : getApplicationListeners(event)) {
            listener.onApplicationEvent(event);
        }
    }
}

3.6 事件发布者的定义和实现

3.6.1 定义事件发布者

ApplicationEventPublisher.java

package com.lino.springframework.context;

/**
 * @description: 事件发布者接口
 */
public interface ApplicationEventPublisher {

    /**
     * 发布事件
     *
     * @param event 事件
     */
    void publishEvent(ApplicationEvent event);
}
  • ApplicationEventPublisher 是一个事件的发布接口,所有的事件都需要从这个接口发布出去。

3.6.2 应用上下文接口

ApplicationContext.java

package com.lino.springframework.context;

import com.lino.springframework.beans.factory.HierarchicalBeanFactory;
import com.lino.springframework.beans.factory.ListableBeanFactory;
import com.lino.springframework.core.io.ResourceLoader;

/**
 * @description: 应用上下文接口
 */
public interface ApplicationContext extends ListableBeanFactory, HierarchicalBeanFactory, ResourceLoader, ApplicationEventPublisher {
}

3.6.3 应用上下文抽象类

AbstractApplicationContext.java

package com.lino.springframework.context.support;

import com.lino.springframework.beans.BeansException;
import com.lino.springframework.beans.factory.ConfigurableListableBeanFactory;
import com.lino.springframework.beans.factory.config.BeanFactoryPostProcessor;
import com.lino.springframework.beans.factory.config.BeanPostProcessor;
import com.lino.springframework.context.ApplicationEvent;
import com.lino.springframework.context.ApplicationListener;
import com.lino.springframework.context.ConfigurableApplicationContext;
import com.lino.springframework.context.event.ApplicationEventMulticaster;
import com.lino.springframework.context.event.ContextClosedEvent;
import com.lino.springframework.context.event.ContextRefreshedEvent;
import com.lino.springframework.context.event.SimpleApplicationEventMulticaster;
import com.lino.springframework.core.io.DefaultResourceLoader;
import java.util.Collection;
import java.util.Map;

/**
 * @description: 抽象应用上下文
 */
public abstract class AbstractApplicationContext extends DefaultResourceLoader implements ConfigurableApplicationContext {

    public static final String APPLICATION_EVENT_MULTICASTER_BEAN_NAME = "applicationEventMulticaster";

    private ApplicationEventMulticaster applicationEventMulticaster;

    @Override
    public void refresh() throws BeansException {
        // 1.创建 BeanFactory,并加载 BeanDefinition
        refreshBeanFactory();

        // 2.获取 BeanFactory
        ConfigurableListableBeanFactory beanFactory = getBeanFactory();

        // 3.添加 ApplicationContextAwareProcessor,让继承自 ApplicationContextAware 的 Bean 对象都能感知所属的 ApplicationContext
        beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));

        // 4.在 Bean 实例化之前,执行 BeanFactoryPostProcess
        invokeBeanFactoryPostProcessor(beanFactory);

        // 5.BeanPostProcessor 需要提前与其他 Bean 对象实例化之前执行注册操作
        registerBeanPostProcessor(beanFactory);

        // 6.初始化事件发布者
        initApplicationEventMulticaster();

        // 7.注册事件监听器
        registerListeners();

        // 8.提前实例化单例 Bean 对象
        beanFactory.preInstantiateSingletons();

        // 9.发布容器刷新完成事件
        finishRefresh();
    }

    ...

    private void initApplicationEventMulticaster() {
        ConfigurableListableBeanFactory beanFactory = getBeanFactory();
        applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
        beanFactory.registerSingletonBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, applicationEventMulticaster);
    }

    private void registerListeners() {
        Collection<ApplicationListener> applicationListeners = getBeansOfType(ApplicationListener.class).values();
        for (ApplicationListener listener : applicationListeners) {
            applicationEventMulticaster.addApplicationListener(listener);
        }
    }

    private void finishRefresh() {
        publishEvent(new ContextRefreshedEvent(this));
    }

    @Override
    public void publishEvent(ApplicationEvent event) {
        applicationEventMulticaster.multicastEvent(event);
    }

    ...

    @Override
    public void close() {
        // 发布容器关闭事件
        publishEvent(new ContextClosedEvent(this));

        // 执行销毁单例bean的销毁方法
        getBeanFactory().destroySingletons();
    }

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

四、测试:容器事件和事件监听器

4.1 添加测试配置

4.1.1 创建自定义事件

CustomEvent.java

package com.lino.springframework.test.event;

import com.lino.springframework.context.event.ApplicationContextEvent;

/**
 * @description: 自定义事件
 */
public class CustomEvent extends ApplicationContextEvent {

    private Long id;
    private String message;

    /**
     * Constructs a prototypical Event.
     *
     * @param source The object on which the Event initially occurred.
     * @throws IllegalArgumentException if source is null.
     */
    public CustomEvent(Object source, Long id, String message) {
        super(source);
        this.id = id;
        this.message = message;
    }

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }
}
  • 创建一个自定义事件,在事件类的构造函数中可以添加自己想要的入参信息。这个事件类最终会被完成的监听类监听到,所以你添加的属性也会被获得到。

4.1.2 自定义事件监听器

CustomEventListener.java

package com.lino.springframework.test.event;

import com.lino.springframework.context.ApplicationListener;
import java.util.Date;

/**
 * @description: 自定义事件监听器
 */
public class CustomEventListener implements ApplicationListener<CustomEvent> {

    @Override
    public void onApplicationEvent(CustomEvent event) {
        System.out.println("收到:" + event.getSource() + "消息;时间:" + new Date());
        System.out.println("消息:" + event.getId() + ":" + event.getMessage());
    }
}
  • 这是一个用于监听 CustomEvent 事件的监听器,这里可以处理自定义操作。

4.1.3 自定义事件刷新监听器

CustomRefreshedEventListener.java

package com.lino.springframework.test.event;

import com.lino.springframework.context.ApplicationListener;
import com.lino.springframework.context.event.ContextRefreshedEvent;

/**
 * @description: 自定义事件刷新监听器
 * @author: lingjian
 * @createDate: 2022/12/1 15:48
 */
public class CustomRefreshedEventListener implements ApplicationListener<ContextRefreshedEvent> {

    @Override
    public void onApplicationEvent(ContextRefreshedEvent event) {
        System.out.println("刷新事件:" + this.getClass().getName());
    }
}

4.1.4 自定义事件关闭监听器

CustomClosedEventListener.java

package com.lino.springframework.test.event;

import com.lino.springframework.context.ApplicationListener;
import com.lino.springframework.context.event.ContextClosedEvent;

/**
 * @description: 自定义事件关闭监听器
 */
public class CustomClosedEventListener implements ApplicationListener<ContextClosedEvent> {

    @Override
    public void onApplicationEvent(ContextClosedEvent event) {
        System.out.println("关闭事件:" + this.getClass().getName());
    }
}

4.1.5 配置文件

spring.xml


<beans>
    <bean class="com.lino.springframework.test.event.CustomEventListener"/>
    <bean class="com.lino.springframework.test.event.CustomRefreshedEventListener"/>
    <bean class="com.lino.springframework.test.event.CustomClosedEventListener"/>
beans>
  • spring.xml 配置文件中,添加了三个事件监听器,监听刷新、监控自定义事件、监听关闭事件。

4.2 单元测试

ApiTest.java

@Test
public void test_event() {
    // 1.初始化 BeanFactory
    ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:spring.xml");
    applicationContext.publishEvent(new CustomEvent(applicationContext, 1019129009086763L, "成功监听到了"));

    applicationContext.registerShutdownHook();
}
  • 通过使用 applicationContext 新增加的发布事件接口方法,发布一个自定义事件 CustomEvent,并传了相应的参数信息。

测试结果

刷新事件:com.lino.springframework.test.event.CustomRefreshedEventListener$$EnhancerByCGLIB$$b3c3d48f
收到:com.lino.springframework.context.support.ClassPathXmlApplicationContext@4cdbe50f消息;时间:Thu Dec 01 17:07:43 CST 2022
消息:1019129009086763:成功监听到了
关闭事件:com.lino.springframework.test.event.CustomClosedEventListener$$EnhancerByCGLIB$$20578a33
  • 从测试结果看,我们自定义的事件和监听,以及监听系统的事件信息,都可以在控制台完成的输出。

五、总结:容器事件和事件监听器

  • 在现有的 Spring 的实现过程中,可以逐步看到很多设计模式的使用。
    • 比如:简单工厂 BeanFactory、工厂方法 FactoryBean、策略模式访问资源、观察者模式 Event
  • 本节关于观察者模式的实现过程,主要包括了事件的定义、事件的监听和发布事件,发布完成后根据匹配策略,监听器就会收到属于自己的事件内容,并做相应的处理动作。在结合 Spring 后,可以看到如何把观察者的实现和应用上下文结合。

你可能感兴趣的:(手写spring,spring,java)