Spring注解驱动开发——ApplicationListener(事件监听)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/rubulai/article/details/80740557

ApplicationListener:应用监听器,是一个抽象类,spring提供的基于事件驱动开发的功能,通过监听容器中发布的一些事件,事件发生则触发监听器的回调来完成事件驱动模型开发

@Component
public class MyApplicationListener implements ApplicationListener<ApplicationEvent>{

	@Override
	public void onApplicationEvent(ApplicationEvent event) {
		System.out.println("发布事件触发");//当容器发布事件以后就会触发
	}

}

在容器刷新完成和容器关闭时都会触发onApplicationEvent方法,这是为何呢?因为ApplicationContext默认发布了这两个事件,那怎么自己发布事件呢?

@Test
public void test(){
	AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(ExtConfig.class);
	context.publishEvent(new ApplicationEvent(new String("abc")){
		private static final long serialVersionUID = 1L;
		
	});
	context.close();
}

步骤:

1)、写一个监听器(ApplicationListener实现类)来监听某个事件(ApplicationEvent及其子类)

2)、把监听器加入到容器

3)、只要容器中有相关事件的发布,我们就能监听到这个事件

    ContextRefreshedEvent:容器刷新完成(所有bean都完全创建)会发布这个事件
    ContextClosedEvent:关闭容器会发布这个事件
4)、自定义发布一个事件:

    applicationContext.publishEvent();

原理:
     发布的事件:ContextRefreshedEvent、IOCTest_Ext$1[source=我发布的事件]、ContextClosedEvent
     1)、ContextRefreshedEvent事件:
        ①容器创建对象:refresh();
        ②refresh();快要结束的时候执行finishRefresh();容器刷新完成会发布ContextRefreshedEvent事件
     2)、自己发布事件

     3)、context.close();容器关闭会发布ContextClosedEvent

【事件发布流程】:publishEvent(new ContextRefreshedEvent(this))
     1)、获取事件的多播器(派发器):getApplicationEventMulticaster()
     2)、multicastEvent派发事件:
     3)、获取到所有的ApplicationListener;
        for (final ApplicationListener<?> listener : getApplicationListeners(event, type)) 
            1)、如果有Executor,可以支持使用Executor进行异步派发;
                Executor executor = getTaskExecutor();

            2)、否则,同步的方式直接执行listener方法;invokeListener(listener, event);拿到listener回调onApplicationEvent方法

【事件多播器(派发器)】
     1)、容器创建对象:refresh();
     2)、initApplicationEventMulticaster();初始化ApplicationEventMulticaster;
          1)、先去容器中找有没有id=“applicationEventMulticaster”的组件;
         2)、如果没有this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);并且加入到容器中,我们就可以在其他组件需要派发事件时,自动注入这个applicationEventMulticaster;

【容器中有哪些监听器】
     1)、容器创建对象:refresh();
     2)、registerListeners();
        从容器中拿到所有的监听器,把他们注册到applicationEventMulticaster中;
            String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false);
            //将listener注册到ApplicationEventMulticaster中

            getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);

实现事件监听的另一种方式:@EventListener

@Component
public class AnnotationListener {

	@EventListener(classes={ApplicationEvent.class})
	public void eventListen(ApplicationEvent event){
		System.out.println("监听到事件:" + event);
	}
}

事件的监听有什么用处呢?看一个例子:

①自定义事件:注意若在该类上加@Component等注解,需将构造器的入参改为具体类型或者指定入参的id,否则会报错,因为其只有有参构造器,在不修改构造器入参的情况下容器创建其实例的时候需要传一个Object对象,而容器中所有的实例都是Object类型的,就会导致找到很多个实体引起冲突

public class MyApplicationEvent extends ApplicationEvent {

	private static final long serialVersionUID = 1L;

	public MyApplicationEvent(Object source) {
		super(source);
		System.out.println("自定义事件:" + source);
	}
}

②自定义监听器:监听自定义的事件

@Component
public class AnnotationListener {

	@EventListener(classes={MyApplicationEvent.class})
	public void eventListen(ApplicationEvent event){
		System.out.println("监听到自定义事件发布:" + event);
	}
}

③发布事件:

@Test
public void test() {
	AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(ExtConfig.class);
	context.publishEvent(new MyApplicationEvent("hello"));
	context.close();
}

那么发布的所有MyApplicationEvent类型的事件都会被AnnotationListener的eventListener方法监听到。那么就可以使用ApplicationLisener来监听一些状态变化,比如文件传送状态、接口回调状态等,在需要监听事件状态变化的地方都需要发布事件(个人理解)

原理:使用EventListenerMethodProcessor处理器来解析方法上的@EventListener,EventListenerMethodProcessor实现了SmartInitializingSingleton接口

SmartInitializingSingleton原理:->afterSingletonsInstantiated();

1)、ioc容器创建对象并refresh();
2)、finishBeanFactoryInitialization(beanFactory);初始化剩下的单实例bean;
    1)、先创建所有的单实例bean;getBean();
    2)、获取所有创建好的单实例bean,判断是否是SmartInitializingSingleton类型的;
    如果是就调用afterSingletonsInstantiated();

猜你喜欢

转载自blog.csdn.net/rubulai/article/details/80740557