Spring 事件驱动模型开发

一. 监听器与事件与发布事件

概述

  1. 什么是事件驱动模型开发: 由Spring的: 事件,监听器, 播放器三大部分构成,Spring底层提供了播放器, 只需要发布事件,监听器监听指定事件进行指定的业务操作,主要是为系统业务进行解耦,提高扩展性,维护性(实际开发中像小应用很少使用这种模式,大应用又有MQ,主要是Spring底层有利于事件监听来做扩展), 主要的核心机制是观察者模式,监听器对应观察者模式中的观察者,发布的事件对应被观察者
  2. 监听器: ApplicationListener< E extends ApplicationEvent> ,监听 Spring 容器中发布的事件,

ApplicationListener< E extends ApplicationEvent>是一个接口,该接口中有onApplicationEvent(E var1) 该方法就是触发事件后的回调方法,

  1. 什么叫发布事件: 先简单理解为通过 AnnotationConfigApplicationContext IOC 容器对象调用 publishEvent() 方法,向方法中传递一个 ApplicationEvent 类型的对象,就是发布事件, 自定义发布事件示例
	@org.junit.Test
    public void test(){
        //创建ioc容器
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MyConfiguration.class);
        //创建 ApplicationEvent 事件对象,由于ApplicationEvent是一个抽象类,此处使用匿名类的方法创建
        ApplicationEvent event = new ApplicationEvent(new String("aaa")){
        };
        //通过 IOC 容器对象调用 publishEvent() 发布事件
        context.publishEvent(event);
    }
  1. 事件: ApplicationEvent 在代码层面看就是 ApplicationListener 接口中的泛型对象,监听器监听这个类型的事件是否发布触发,不同的监听器根据泛型中设置的事件类型不同,监听不同的事件
  2. Spring 关于容器的,默认提供了,继承ApplicationEvent 接口的,容器刷新事件,容器开始事件,容器停止事件,容器关闭事件,也有对应事件的监听器
    在这里插入图片描述

二. 通过 Spring 提供的容器刷新事件查看原理

发布事件的原理

  1. Spring启动创建IOC容器时调用 refresh() 方法,该方法中调用了this.finishRefresh() 方法,会执行一个创建容器事件
    在这里插入图片描述
  2. 查看 finishRefresh() 方法,该方法中调用了publishEvent() ,创建了ContextRefreshedEvent 刷新容器事件对象,传递给了 publishEvent() 方法, ContextRefreshedEvent 继承了 ApplicationContextEvent 接口是一个事件对象,此处调用的publishEvent() 方法就是发布事件
    在这里插入图片描述
  3. 查看 publishEvent() 方法,事件的派发,获取 ApplicationEventMulticaster 多播器,通过多播器将事件派发给对应的监听器
 protected void publishEvent(Object event, ResolvableType eventType) {
        Assert.notNull(event, "Event must not be null");
        if (this.logger.isTraceEnabled()) {
            this.logger.trace("Publishing event in " + this.getDisplayName() + ": " + event);
        }

        Object applicationEvent;
        if (event instanceof ApplicationEvent) {
            applicationEvent = (ApplicationEvent)event;
        } else {
            applicationEvent = new PayloadApplicationEvent(this, event);
            if (eventType == null) {
                eventType = ((PayloadApplicationEvent)applicationEvent).getResolvableType();
            }
        }

        if (this.earlyApplicationEvents != null) {
            this.earlyApplicationEvents.add(applicationEvent);
        } else {
        	//1.调用 getApplicationEventMulticaster() 方法获取一个ApplicationEventMulticaster"多播器"也叫派发器
        	//2.通过多播器调用 multicastEvent() 方法执行派发事件
            this.getApplicationEventMulticaster().multicastEvent((ApplicationEvent)applicationEvent, eventType);
        }
        if (this.parent != null) {
            if (this.parent instanceof AbstractApplicationContext) {
                ((AbstractApplicationContext)this.parent).publishEvent(event, eventType);
            } else {
                this.parent.publishEvent(event);
            }
        }
    }
  1. 查看 multicastEvent() 方法
public void multicastEvent(final ApplicationEvent event, ResolvableType eventType) {
        ResolvableType type = eventType != null ? eventType : this.resolveDefaultEventType(event);
        //获取所有通过发布的事件对象获取对应的 ApplicationListener 监听器
        Iterator var4 = this.getApplicationListeners(event, type).iterator();
		//遍历获取到的监听器
        while(var4.hasNext()) {
            final ApplicationListener<?> listener = (ApplicationListener)var4.next();
            Executor executor = this.getTaskExecutor();
            //判断是否可以异步执行,如果可以则使用多线程方式进行异步执行
            if (executor != null) {
            	//多线程方式异步执行
                executor.execute(new Runnable() {
                    public void run() {
                        SimpleApplicationEventMulticaster.this.invokeListener(listener, event);
                    }
                });
            } else {
            	//同步执行
                this.invokeListener(listener, event);
            }
        }
    }
  1. 同样,例如在调用close() 方法关闭容器时,在该方法中也是调用了publishEvent() 方法,传递了一个关闭事件,获取多播器,通过多播器,找到对象的监听器,执行监听器中的逻辑

IOC 容器注册多播器

  1. 发布事件时通过多播器,将事件传递给对应的监听器,进而调用监听器中的方法,实现该事件要完成的功能,我们也可以自定义多播器,指定多播器使用的 Executor,进而实现事件执行的同步或异步功能
  2. 多播器的注册过程: 在Spring启动调用refresh() 方法后,该方法中调用了 initApplicationEventMulticaster()在创建其它 bean 对象之前通过该方法初始化 ApplicationEventMulticaster 多播器
    在这里插入图片描述
  3. 查看 initApplicationEventMulticaster() 方法默认会创建SimpleApplicationEventMulticaster事件多播器注入到容器中
	protected void initApplicationEventMulticaster() {
        ConfigurableListableBeanFactory beanFactory = this.getBeanFactory();
        //1.通过BeanFactory 在IOC 容器中寻找有没有 id 为"applicationEventMulticaster"的bean,这个bean 就是多播器
        if (beanFactory.containsLocalBean("applicationEventMulticaster")) {
        	//如果有,直接通过id 在容器你中获取
            this.applicationEventMulticaster = (ApplicationEventMulticaster)beanFactory.getBean("applicationEventMulticaster", ApplicationEventMulticaster.class);
            if (this.logger.isDebugEnabled()) {
                this.logger.debug("Using ApplicationEventMulticaster [" + this.applicationEventMulticaster + "]");
            }
        } else {
        	//如果没有new 一个多播器
            this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
            //将new 出来的多播器注册到容器中
            beanFactory.registerSingleton("applicationEventMulticaster", this.applicationEventMulticaster);
            if (this.logger.isDebugEnabled()) {
                this.logger.debug("Unable to locate ApplicationEventMulticaster with name 'applicationEventMulticaster': using default [" + this.applicationEventMulticaster + "]");
            }
        }
    }

IOC 容器注册监听器

  1. 在创建 IOC 容器时 调用 refresh() 方法,该方法内部调用 this.finishRefresh() 刷新容器发布创建容器事件以前调用了 registerListeners() 方法,注册监听器
    在这里插入图片描述
  2. 查看 registerListeners() 注册监听器的方法
  1. 获取所有监听器到ApplicationListener
  2. 遍历监听器注册到多播器中
protected void registerListeners() {
		//1.获取 ApplicationListener 监听器迭代器(第一次执行时可能没有)
        Iterator var1 = this.getApplicationListeners().iterator();
		//如果有遍历获取每一个监听器,将监听器注册到多播器中
        while(var1.hasNext()) {
            ApplicationListener<?> listener = (ApplicationListener)var1.next();
            //将监听器注册到多播器中
            this.getApplicationEventMulticaster().addApplicationListener(listener);
        }
		//如果没有,通过类型,在容器中获取所有监听器的名字
        String[] listenerBeanNames = this.getBeanNamesForType(ApplicationListener.class, true, false);
        String[] var7 = listenerBeanNames;
        int var3 = listenerBeanNames.length;
		//注册监听器,将将监听器注册到多播器中
        for(int var4 = 0; var4 < var3; ++var4) {
            String listenerBeanName = var7[var4];
            this.getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);
        }

        Set<ApplicationEvent> earlyEventsToProcess = this.earlyApplicationEvents;
        this.earlyApplicationEvents = null;
        if (earlyEventsToProcess != null) {
            Iterator var9 = earlyEventsToProcess.iterator();

            while(var9.hasNext()) {
                ApplicationEvent earlyEvent = (ApplicationEvent)var9.next();
                this.getApplicationEventMulticaster().multicastEvent(earlyEvent);
            }
        }
    }

三. 自定义事件驱动模型开发

  1. 步骤:
  1. 创建自定义事件对象(实现 ApplicationEvent 接口)
  2. 创建与自定义事件对应的监听器,
  1. 实现 ApplicationListener 接口 方式:重写接口中的 onApplicationEvent() 回调方法编写监听到对应的实际后要做的逻辑功能,接口中的泛型中指定要监听的事件类型
  2. 还有使用@EventListener注解方式: 该方式修饰方法,任何方法都可以监听事件,通过该注解的class属性值指定该方法要监听的事件类型"@EventListener(classes=事件Event.class)"
  1. 设置自定义监听器注入到容器中
  2. 接受请求执行发布自定义事件的逻辑代码
  1. 创建自定义事件
import org.springframework.context.ApplicationEvent;
//自定义事件,继承 ApplicationEvent 接口,事件一般都会传递数据
//在发生事件后,监听器通过事件对象获取要处理的数据,有个带参构造
//通过带参构造传递数据,对属性赋值
public class MyApplicationEvent extends ApplicationEvent  {

    //这个变量可以看为事件要处理的数据
    public Object source;

    public MyApplicationEvent(Object source) {
        super(source);
        this.source = source;
    }

    @Override
    public Object getSource() {
        return source;
    }
}
  1. 创建自定义监听器
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.stereotype.Component;

//不要忘记将自定义监听器注入到容器中
@Component
public class MyApplicationListener <MyApplicationEvent>implements ApplicationListener {
    //实现 ApplicationListener 接口,泛型中指定要监控的事件类型
    //重写onApplicationEvent()方法编写事件发生后要执行的逻辑
    //当向容器中发布事件时,,会触发该方法
    @Override
    public void onApplicationEvent(ApplicationEvent applicationEvent) {
        //获取事件中保存的数据
        applicationEvent.getSource();
        System.out.println("我是对应 MyApplicationEvent 事件的监听器,执行...");
    }
}
  1. 触发事件
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Component;
//不要忘记注入到容器中
@Component
public class PublishEvent implements ApplicationContextAware {
    //通过继承 ApplicationContextAware 接口的方式,
    //在启动 Spring 时,自动获取Spring创建的IOC容器,赋值给,当前类中的属性

    //通过 ApplicationContext 调用 publishEvent() 方法发布事件使用
    private ApplicationContext context;

	//重写 ApplicationContextAware 接口中的 setApplicationContext() 方法拿到 Spring 自己创建的 IOC 容器
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.context = applicationContext;
    }

	//通过该方法可以触发事件
    public void publishTest(){
        System.out.println("我被触发,我要发布事件");
        //创建事件对象,设置事件数据
        MyApplicationEvent event = new MyApplicationEvent(new String("我是事件数据"));
        //通过 IOC 容器调用 publishEvent() 方法发布事件
        context.publishEvent(event);
    }
}

@EventListener 设置监听方法注解

通过方法监听事件示例

	//使用注解方式,设置监听事件的方法(该方法的类不要忘记注入到容器中)
    @EventListener(classes = {MyApplicationEvent.class})
    public void listenerMethod(MyApplicationEvent event){
        System.out.println("我是监听方法,监听 MyApplicationEvent 事件");
        //获取事件中的数据
        System.out.println(event.source);
    }

四. 了解 SmartInitializingSingleton

  1. SmartInitializingSingleton 是一个接口,该接口中有一个 afterSingletonsInstantiated() 抽象方法该方法在什么时候执行: 当创建 IOC 容器时,调用 refresh() 方法,在refresh() 方法中调用 finishBeanFactoryInitialization(beanFactory) 方法,该方法中又调用了preInstantiateSingletons(),实现对单实例 bean 的创建初始化,当所有注意,是所有 bean 创建初始化完成以后,遍历所以bean的名字获取出来,判断这个bean是否是 SmartInitializingSingleton 类型,如果是执行 SmartInitializingSingleton 中的 afterSingletonsInstantiated() 方法
    注意点: 是所有 bean 创建初始化完成后,再遍历执行这个 afterSingletonsInstantiated() 方法的
public void preInstantiateSingletons() throws BeansException {
        if (this.logger.isDebugEnabled()) {
            this.logger.debug("Pre-instantiating singletons in " + this);
        }
		//==================1.获取所有 bean 的名字===================
        List<String> beanNames = new ArrayList(this.beanDefinitionNames);
        Iterator var2 = beanNames.iterator();

        while(true) {
            while(true) {
                String beanName;
                RootBeanDefinition bd;
                 //========do while循环,查看下面的条件,判断所有bean是否全部初始化完成===================================
                do {
                    do {
                        do {
                            if (!var2.hasNext()) {
                                var2 = beanNames.iterator();
								//=========2.遍历获取到的 bean 的名字======================
                                while(var2.hasNext()) {
                                    beanName = (String)var2.next();
                                   //=======3.通过获取到额benaName,去容器中查找这个bean=================
                                    Object singletonInstance = this.getSingleton(beanName);
                                    //=====4.判断这个bean是否是SmartInitializingSingleton类型====================
                                    if (singletonInstance instanceof SmartInitializingSingleton) {
                                    	//===========5.如果是转换回来=====================
                                        final SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton)singletonInstance;
                                        if (System.getSecurityManager() != null) {
                                            AccessController.doPrivileged(new PrivilegedAction<Object>() {
                                                public Object run() {
                                                    smartSingleton.afterSingletonsInstantiated();
                                                    return null;
                                                }
                                            }, this.getAccessControlContext());
                                        } else {
                                        	//6.=======执行afterSingletonsInstantiated ()方法===================
                                            smartSingleton.afterSingletonsInstantiated();
                                        }
                                    }
                                }

                                return;
                            }

                            beanName = (String)var2.next();
                            bd = this.getMergedLocalBeanDefinition(beanName);
                        } while(bd.isAbstract());
                    } while(!bd.isSingleton());
                    
                  //========判断所有bean是否全部初始化完成===================================
                } while(bd.isLazyInit());

                if (this.isFactoryBean(beanName)) {
                    final FactoryBean<?> factory = (FactoryBean)this.getBean("&" + beanName);
                    boolean isEagerInit;
                    if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
                        isEagerInit = (Boolean)AccessController.doPrivileged(new PrivilegedAction<Boolean>() {
                            public Boolean run() {
                                return ((SmartFactoryBean)factory).isEagerInit();
                            }
                        }, this.getAccessControlContext());
                    } else {
                        isEagerInit = factory instanceof SmartFactoryBean && ((SmartFactoryBean)factory).isEagerInit();
                    }

                    if (isEagerInit) {
                        this.getBean(beanName);
                    }
                } else {
                	//=在Spring容器首次启动时,前面的都没有,会首先走这里创建所有的bean,初始化============
                    this.getBean(beanName);
                }
            }
        }
    }

SmartInitializingSingleton 使用示例

@EventListener 注解设置监听方法,底层就是通过这个接口,对该接口中的方法在 EventListenerMethodProcessor 子类中进行了实现

五. 异步发布事件的核心机制是什么

  1. 利用多线程,在发布事件时使用@Async,或使用taskExecutor来实现
  2. 以taskExecutor为例,通过EventMulticaster调用setTaskExecutor()方法,设置SimpleAsyncTaskExecutor
    在这里插入图片描述
  3. 当我们调用publishEvent()发布事件后,底层会判断是否存在异步多播也就是taskExecutor,如果存在会通过Executor创建异步线程,进行异步发布
    在这里插入图片描述
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值