Spring 事件驱动模型开发

事件驱动模型开发

  • 一. 监听器与事件与发布事件
    • 概述
  • 二. 通过 Spring 提供的容器刷新事件查看原理
    • 发布事件的原理
    • IOC 容器注册多播器
    • IOC 容器注册监听器
  • 三. 自定义事件驱动模型开发
    • @EventListener 设置监听方法注解
  • 四. 了解 SmartInitializingSingleton
    • SmartInitializingSingleton 使用示例

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

概述

事件驱动模型开发,当有事件发生时触发事件,通过监听器监听,执行回调方法,完成要实现功能

  1. 监听器: ApplicationListener ,监听 Spring 容器中发布的事件,
  2. ApplicationListener 是一个接口,该接口中有一个 onApplicationEvent(E var1) 方法,该方法就是触发事件后的回调方法,
  3. 什么叫发布事件: 先简单理解为通过 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 提供的容器刷新事件查看原理

发布事件的原理

创建 IOC 容器时,会自动执行一个创建容器事件,查看源码分析创建容器事件的发布与执行

  1. 创建 IOC 容器,调用 refresh() 方法,创建容器中的 bean 对象,刷新容器,查看refresh 方法.在该方法中调用了this.finishRefresh() 方法,
    Spring 事件驱动模型开发_第1张图片
  2. 查看 finishRefresh() 方法,在该方法中调用了 publishEvent() 方法,创建了一个 ContextRefreshedEvent 刷新容器事件对象,传递给了 publishEvent() 方法, ContextRefreshedEvent 继承了 ApplicationContextEvent 接口是一个事件对象,此处调用的publishEvent() 方法就是发布事件
    Spring 事件驱动模型开发_第2张图片
  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);
            }
        }

    }

同样,例如在调用close() 方法关闭容器时,在该方法中也是调用了publishEvent() 方法,传递了一个关闭事件,获取多播器,通过多播器,找到对象的监听器,执行监听器中的逻辑

IOC 容器注册多播器

发布事件时通过多播器,将事件传递给对应的监听器,进而调用监听器中的方法,实现该事件要完成的功能,我们也可以自定义多播器,指定多播器使用的 Executor,进而实现事件执行的同步或异步功能
多播器的注册过程:
在创建 IOC 容器时 调用 refresh() 方法,该方法中调用了 initApplicationEventMulticaster() 方法,在创建其它 bean 对象之前通过该方法初始化 ApplicationEventMulticaster 多播器
Spring 事件驱动模型开发_第3张图片
查看 initApplicationEventMulticaster() 方法

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 容器注册监听器

在创建 IOC 容器时 调用 refresh() 方法,方法中调用 this.finishRefresh() 刷新容器发布创建容器事件以前调用了 registerListeners() 方法,注册监听器
Spring 事件驱动模型开发_第4张图片
查看 registerListeners() 注册监听器的方法

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);
            }
        }

    }

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

步骤:

  • 创建自定义事件对象(实现 ApplicationEvent 接口)
  • 创建与自定义事件对应的监听器,
    1. 实现 ApplicationListener 接口 方式:重写接口中的 onApplicationEvent() 回调方法编写监听到对应的实际后要做的逻辑功能,接口中的泛型中指定要监听的事件类型
    2. 还有使用@EventListener注解方式: 该方式修饰方法,任何方法都可以监听事件,通过该注解的class属性值指定该方法要监听的事件类型"@EventListener(classes=事件Event.class)"
  • 设置自定义监听器注入到容器中
  • 接受请求执行发布自定义事件的逻辑代码

代码
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

SmartInitializingSingleton 是一个接口,该接口中有一个 afterSingletonsInstantiated() 抽象方法
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 子类中进行了实现

你可能感兴趣的:(Spring,#,Spring注解驱动开发,spring)