Spring之监听器

327 阅读3分钟

Spring 事件

spring 内置事件

Event说明
ContextRefreshedEvent当容器被实例化或refreshed时发布.如调用refresh()方法, 此处的实例化是指所有的bean都已被加载,后置处理器都被激活,所有单例bean都已被实例化, 所有的容器对象都已准备好可使用. 如果容器支持热重载,则refresh可以被触发多次(XmlWebApplicatonContext支持热刷新,而GenericApplicationContext则不支持)
ContextStartedEvent当容器启动时发布,即调用start()方法, 已启用意味着所有的Lifecycle bean都已显式接收到了start信号
ContextStoppedEvent当容器停止时发布,即调用stop()方法, 即所有的Lifecycle bean都已显式接收到了stop信号 , 关闭的容器可以通过start()方法重启
ContextClosedEvent当容器关闭时发布,即调用close方法, 关闭意味着所有的单例bean都已被销毁.关闭的容器不能被重启或refresh
RequestHandledEvent这只在使用spring的DispatcherServlet时有效,当一个请求被处理完成时发布

自定义事件

事件类需要继承ApplicationEvent,代码如下:

public class OrderEvent  extends ApplicationEvent {

    private String name;

    public OrderEvent(Object source, String name) {
        super(source);
        this.name = name;
    }

    public String getName() {
        return name;
    }
}

事件监听器-基于接口

@Component
public class HelloEventListener implements ApplicationListener<OrderEvent> {
  
    @Override
    public void onApplicationEvent(OrderEvent event) {
        if(event.getName().equals("减库存")){
            System.out.println("减库存.......");
        }
    }
}

事件监听器-基于注解

@Component
public class OrderEventListener {
    @EventListener(OrderEvent.class)
    public void onApplicationEvent(OrderEvent event) {
        if(event.getName().equals("减库存")){
            System.out.println("减库存.......");
        }
    }

}

两种方式只是在实现的方式上不同。

事件发布

public static void main(String[] args) {
   AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(MainConfig.class);
   
   ctx.publishEvent(new HelloEvent(this,"xxx"));
}

问题:怎么样可以在所有Bean创建完后做扩展代码?

当Spring容器被实例化或refreshed时发布,会发布ContextRefreshedEvent事件。 image.png

image.png
只需要监听ContextRefreshedEvent事件,即在所有Bean创建后做扩展代码。

@Component
@Lazy
public class ContextRefreshedEventListener  implements ApplicationListener<ContextRefreshedEvent> {

    @Override
   @EventListener(ContextRefreshedEvent.class)
    public void onApplicationEvent(ContextRefreshedEvent event)  {
        if(event.getApplicationContext().getParent() == null)//root application context 没有parent,他就是老大.
        {
            //Thread.sleep(5000);
            //需要执行的逻辑代码,当spring容器初始化完成后就会执行该方法。
            System.out.println("\n\n\n\n\n______________\n\n\n加载了\n\n_________\n\n");
        }

    }

}

源码

spring的事件监听有三个部分组成:

  • 事件(ApplicationEvent) 负责对应相应监听器 事件源发生某事件是特定事件监听器被触发的原因。
  • 监听器(ApplicationListener) 对应于观察者模式中的观察者。监听器监听特定事件,并在内部定义了事件发生后的响应逻辑。
  • 事件发布器(ApplicationEventMulticaster) 对应于观察者模式中的被观察者/主题, 负责通知观察者 对外提供发布事件和增删事件监听器的接口,维护事件和事件监听器之间的映射关系,并在事件发生时负责通知相关监听器。 spring的事件主要是在ApplicationContext接口的抽象实现类AbstractApplicationContext中完成搭建。
    ApplicationContext接口的抽象实现类AbstractApplicationContext中完成。
    AbstractApplicationContext在refresh()这个容器启动方法中搭建了事件的基础设施,其中AbstractApplicationContext的refresh方法实现如下: image.png

初始化多播器

image.png
用户可以在配置文件中为容器定义一个自定义的事件广播器,只要实现ApplicationEventMulticaster就可以了,Spring会通过 反射的机制将其注册成容器的事件广播器,如果没有找到配置的外部事件广播器,Spring自动使用 SimpleApplicationEventMulticaster作为事件广播器。

注册监听器

image.png
Spring根据反射机制,使用ListableBeanFactory的getBeansOfType方法,从BeanDefinitionRegistry中找出所有实现 org.springframework.context.ApplicationListener的Bean,将它们注册为容器的事件监听器,实际的操作就是将其添加到事件广播器所提供的监听器注册表中。

发布事件

image.png
进入到具体的实现SimpleApplicationEventMulticaster image.png