Spring5 IOC源码解读系列9—registerListeners方法

一 概述

Spring的事件监听主要涉及三个角色:1)事件:ApplicationEvent抽象类的继承者;
2)事件发布者:事件多播器ApplicationEventMulticaster接口的实现类,比如SimpleApplicationEventMulticaster;3)事件监听器:ApplicationListener 接口的实现类。

registerListeners方法主要将实现监听器接口(即ApplicationListener接口)的bean们注册到多播器中,即存储到applicationListenerBeans集合中。

二 内置事件监听

Spring提供了很多内置事件,这里以ContextRefreshedEvent举例说明。ContextRefreshedEvent是ApplicationEvent继承者,,当ApplicationContext被初始化或刷新时,会触发ContextRefreshedEvent事件。

2.1 事件

ContextRefreshedEvent是ApplicationEvent继承者,关系图如下所示。
在这里插入图片描述

ContextRefreshedEvent的源码:

public class ContextRefreshedEvent extends ApplicationContextEvent {

	/**
	 * Create a new ContextRefreshedEvent.
	 * @param source the {@code ApplicationContext} that has been initialized
	 * or refreshed (must not be {@code null})
	 */
	public ContextRefreshedEvent(ApplicationContext source) {
		super(source);
	}

}

2.2 监听器

public class LearnListener implements ApplicationListener<ContextRefreshedEvent> {

    @Override
    public void onApplicationEvent(ContextRefreshedEvent event) {
        // 打印容器中出事Bean的数量
        System.out.println("监听器获得容器中初始化Bean数量:" + event.getApplicationContext().getBeanDefinitionCount());
        String[] names = event.getApplicationContext().getBeanDefinitionNames();
        for (String name : names){
            System.out.println(name);
        }
    }
}

2.3 修改配置文件

在Spring的配置文件中添加监听器的配置

<bean id="learnListener" class="com.service.LearnListener"/>

2.4 启动类

public class BeanLifeCycle{

    public static void main(String[] args) {

        System.out.println("现在开始初始化容器");

        ApplicationContext factory = new ClassPathXmlApplicationContext("beans.xml");

    //触发监听器
  ((ClassPathXmlApplicationContext) factory).refresh();

        ((ClassPathXmlApplicationContext) factory).close();

    }
}

2.5 日志

监听器获得容器中初始化Bean数量:4
监听器获得容器中初始化Bean数量:4

从日志上看,监听器的onApplicationEvent方法被调用了2次,因为刷新方法refresh()被调用了2次。第一次是在容器初始化中,Spring自身调用refresh()方法。第二次是在代码中手动调用refresh()方法。

三 自定义事件监听

3.1 事件

public class MyApplicationEvent extends ApplicationEvent {

      //公共变量,存储消息
    private Object meg;

      //构造函数
    public MyApplicationEvent(Object source, Object meg) {
        super(source);
        this.meg = meg;
        System.out.println("这是MyApplicationEvent实现类构造器");
        System.out.println("事件发生了改变:" + meg);
    }

    //获取消息
    public Object getMeg() {
        return meg;
    }

}

3.2 监听器

public class MyApplicationListener implements ApplicationListener<MyApplicationEvent> {

    //构造函数
    public MyApplicationListener() {
        System.out.println("这是MyApplicationListener实现类构造器");
    }

    @Override
    public void onApplicationEvent(MyApplicationEvent event) {
        System.out.println("事件监听器收到消息: " + event.getMeg());

    }
}

3.3 修改配置文件

在Spring的配置文件中添加监听器的配置

<bean id="learnListener" class="com.service.MyApplicationListener"/>

3.4 启动类

public class BeanLifeCycle{

    public static void main(String[] args) {

        System.out.println("现在开始初始化容器");

        ApplicationContext factory = new ClassPathXmlApplicationContext("beans.xml");

        MyApplicationEvent myApplicationEvent = new MyApplicationEvent(factory, "Event changes!");

        //发布事件
        factory.publishEvent(myApplicationEvent);

        System.out.println("现在开始关闭容器!");
        ((ClassPathXmlApplicationContext) factory).close();

    }
}

3.5 日志

事件发生了改变:Event changes!
事件监听器收到消息: Event changes!

四 源码

4.1 registerListeners方法

protected void registerListeners方法() {
		// Register statically specified listeners first.
        //优先在事件多播器中 注册静态指定的监听器
		for (ApplicationListener<?> listener : getApplicationListeners()) {
			getApplicationEventMulticaster().addApplicationListener(listener);
		}

		// Do not initialize FactoryBeans here: We need to leave all regular beans
		// uninitialized to let post-processors apply to them!
        
        //获取实现ApplicationListener接口的监听器
        //这个阶段监听器没有初始化
		String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false);
		for (String listenerBeanName : listenerBeanNames) {
			
 //获取事件多播器 ,并将实现ApplicationListener接口的Bean注册到applicationListenerBeans中
 
 getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);
		}

		// Publish early application events now that we finally have a multicaster...
        //earlyApplicationEvents是早期的事件,在Spring IOC整个生命周期中,比多播期的初始化要早出现
		Set<ApplicationEvent> earlyEventsToProcess = this.earlyApplicationEvents;
        //赋值为null, help gc
		this.earlyApplicationEvents = null;
        
        /存储早期事件的集合被初始化
		if (earlyEventsToProcess != null) {
        //存储早期事件的集合中存在事件
			for (ApplicationEvent earlyEvent : earlyEventsToProcess) {
            //添加到多播器中
				getApplicationEventMulticaster().multicastEvent(earlyEvent);
			}
		}
	}

五 参考文献

1)JDK7在线文档
https://tool.oschina.net/apidocs/apidoc?api=jdk_7u4
2) JDK8在线文档
https://docs.oracle.com/javase/8/docs/api/
3)Spring Framework 5 中文文档
https://www.cntofu.com/book/95/index.html
4) Bruce Eckel. Java编程思想,第4版,2007,机械工业出版社
5)方腾飞,魏鹏,程晓明. Java并发编程的艺术,第1版,2015年,机械工业出版社
6)克雷格.沃斯. Spring实战,第5版,2020年,人民邮电出版社

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值