ApplicationListener监听器本身是一个函数式接口,监听对象为ApplicationEvent事件的子类,ApplicationEvent事件本身是一个抽象类,它拥有各式各样的子类,这些子类就是定制化的事件,专门用于特定的场景。ApplicationEvent事件继承EventObject这个事件本体,EventObject事件本体是所有事件的基础,EventObject事件本体拥有一个protected transient Object source;这样一个Object类型的source属性,用于存放事件。

那这个事件数据是如何传递的呢?通过观察源码,我们发现,在事件类继承的层层嵌套链中,子类都需要通过super()方法调用父类的构造方法,通过在super()中传递事件参数可以实现事件数据的层层传递,最终传递到EventObject,然后,在EventObject的构造方法中就可以完成source属性的初始化,也就完成了事件的传递以及最终存储

现在,我们来理一理SpringApplicationRunListenerEventPublishingRunListenerApplicationListener这三者之间的关系。

首先我们需要知道一个基础知识,springboot是基于spring的,一个springboot应用其核心是调用了spring的SpringApplication.run()方法,也就是说,springboot是为简化spring开发进行的封装。现在我们来分析三者关系。

通过观察源码我们可以知道,SpringApplicationRunListener 和 EventPublishingRunListener是由springboot提供的,且EventPublishingRunListener是SpringApplicationRunListener 的唯一实现。ApplicationListener是由spring提供的,监听目标是ApplicationEvent类或者其子类,通过之前的分析我们知道,所有定制化的事件都直接或间接的继承ApplicationEvent,也就是说,定制化的事件都是ApplicationEvent的子类,也就是说,定制化的事件都是ApplicationListener监听器的监听目标,也就是说,EventPublishingRunListener发布的定制化事件间接受ApplicationListener监听。

自定义监听器:

这里以实现ApplicationListener接口为例

@Component
public class CustomeApplicationListener implements ApplicationListener<ApplicationStartedEvent> , Ordered {
    @Override
    public void onApplicationEvent(ApplicationStartedEvent applicationStartingEvent) {
        System.out.println("自定义监听器CustomeApplicationListener,监听springboot启动,监听EventPublishingRunListener发布的启动开始事件");
    }

    @Override
    public int getOrder() {
        return 0;
    }
}

注册监听器的方式

基于监听的事件发生的阶段选择对应的的注册方式,需要注意的是监听器的注册一定要在事件发生之前。以下是三种常见的注册方法:

1、通过启动类注册

@SpringBootApplication
public class CustomeSpringApplication {
    public static void main(String[] args) {
        //SpringApplication.run(CustomeSpringApplication.class, args);
        //等价于上面的启动只不过把过程进行拆分,扩展了中间操作
        SpringApplication application = new SpringApplication(CustomeSpringApplication.class);
        application.addListeners(new CustomeGenericApplicationListener());
        application.run(args);
    }
}

2、通过自动配置文件spring.factories文件注册

org.springframework.context.ApplicationListener=\
    com.classloader.listener.CustomeApplicationListener

3、通过注解注册

直接在自定义监听器上加上@Component、@Configuration等注解注册,不过通过注解注册监听不到容器加载之前的事件的。

@Component
public class CustomeApplicationListener implements ApplicationListener<ApplicationStartedEvent> , Ordered {
    @Override
    public void onApplicationEvent(ApplicationStartedEvent applicationStartingEvent) {
        System.out.println("自定义监听器CustomeApplicationListener,监听springboot启动,监听EventPublishingRunListener发布的启动开始事件");
    }

    @Override
    public int getOrder() {
        return 0;
    }
}

下面附源码以供分析:

@FunctionalInterface
public interface ApplicationListener<E extends ApplicationEvent> extends EventListener {
    //当发生监听事件时
    void onApplicationEvent(E var1);
}
public abstract class ApplicationEvent extends EventObject {
    private static final long serialVersionUID = 7099057708183571937L;
    private final long timestamp = System.currentTimeMillis();

    public ApplicationEvent(Object source) {
        super(source);
    }

    public final long getTimestamp() {
        return this.timestamp;
    }
}
public class EventObject implements java.io.Serializable {

    private static final long serialVersionUID = 5516075349620653480L;

    /**
     * The object on which the Event initially occurred.
     */
    protected transient Object  source;

    /**
     * Constructs a prototypical Event.
     *
     * @param    source    The object on which the Event initially occurred.
     * @exception  IllegalArgumentException  if source is null.
     */
    public EventObject(Object source) {
        if (source == null)
            throw new IllegalArgumentException("null source");

        this.source = source;
    }

    /**
     * The object on which the Event initially occurred.
     *
     * @return   The object on which the Event initially occurred.
     */
    public Object getSource() {
        return source;
    }

    /**
     * Returns a String representation of this EventObject.
     *
     * @return  A a String representation of this EventObject.
     */
    public String toString() {
        return getClass().getName() + "[source=" + source + "]";
    }
}

Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐