ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

spring的事件监听

2021-01-29 14:02:12  阅读:87  来源: 互联网

标签:spring void 监听 public class 事件 监听器 event


赵云胡说--spring的事件监听

当spring读取解析好了配置文件,将自身所需的类实例化好后,剩下的就是去处理BeanDefinition了.在此之前spring还有一件事情去做,那就是实例化好事件监听器,本篇就是介绍spring的事件监听的原理和实践的

事件监听接口

spring事件监听涉及到三个接口
ApplicationEventMulticaster ,事件广播器,它的作用是存储事件监听器ApplicationListener,当有事件被发布时spring容器会调用multicastEvent方法,从而去通知相应的事件监听器ApplicationListener去执行事件发生后要做的事情
用通俗的话讲,就是把ApplicationListener对象放在一个list里,执行multicastEvent方法时,循环遍历list,找到符合的事件监听器ApplicationListener执行下ApplicationListener里面的onApplicationEvent方法就可以了

public interface ApplicationEventMulticaster {

	void addApplicationListener(ApplicationListener<?> listener);

	void addApplicationListenerBean(String listenerBeanName);
	
	void removeApplicationListener(ApplicationListener<?> listener);

	void removeApplicationListenerBean(String listenerBeanName);
	
	void removeAllListeners();

	void multicastEvent(ApplicationEvent event);

	void multicastEvent(ApplicationEvent event, @Nullable ResolvableType eventType);

}

ApplicationListener,事件的监听器,当某事件发生后,会执行onApplicationEvent方法

@FunctionalInterface
public interface ApplicationListener<E extends ApplicationEvent> extends EventListener {

	void onApplicationEvent(E event);

}

ApplicationEvent ,事件自己定义的某些特殊事件

public abstract class ApplicationEvent extends EventObject {

	private static final long serialVersionUID = 7099057708183571937L;

	private final long timestamp;

	public ApplicationEvent(Object source) {
		super(source);
		this.timestamp = System.currentTimeMillis();
	}

	public final long getTimestamp() {
		return this.timestamp;
	}

}

事件监听实践

层级目录
在这里插入图片描述
该实践中有两个事件,三个监听器,和一个启动的主类.
主类

@ComponentScan
public class EightStart {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(EightStart.class);
        SleepEvent sleepEvent = new SleepEvent("晚安睡觉");
        context.publishEvent(sleepEvent);
    }
}

SleepEvent 睡觉事件

public class SleepEvent extends ApplicationEvent {
    public SleepEvent(Object source) {
        super(source);
    }
}

SleepListener 睡觉事件监听器

@Component
public class SleepListener implements ApplicationListener<SleepEvent> {
    @Override
    public void onApplicationEvent(SleepEvent event) {
        Object source = event.getSource();
        System.out.println(source);
    }
}

ComListener 通用事件监听器

@Component
public class ComListener implements ApplicationListener<ApplicationEvent> {
    @Override
    public void onApplicationEvent(ApplicationEvent event) {
      System.out.println(event.getClass()+"我被执行到了,event的source"+event.getSource());
    }
}

启动一波
在这里插入图片描述
明显看出,通用事件监听器的onApplicationEvent方法被执行了两次,看下触发的事件,分别是ContextRefreshedEvent和我们定义的SleepEvent事件
睡觉事件监听器的onApplicationEvent方法方法被执行了一次

再改下主类,发布了PlayGameEvent的事件

@ComponentScan
public class EightStart {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(EightStart.class);
        PlayGameEvent gameEvent = new PlayGameEvent("超级玛丽");
        context.publishEvent(gameEvent);
    }
}

PlayGameEvent

public class PlayGameEvent extends ApplicationEvent {
    private String gameName;

    public String getGameName() {
        return gameName;
    }

    public void setGameName(String gameName) {
        this.gameName = gameName;
    }
    
    public PlayGameEvent(Object source) {
        super(source);
    }

    public PlayGameEvent(String gameName) {
        super(gameName);
        this.gameName=gameName;
    }
}

PlayGameListener 打游戏事件监听器

@Component
public class PlayGameListener implements ApplicationListener<PlayGameEvent> {
    @Override
    public void onApplicationEvent(PlayGameEvent event) {
        System.out.println(event.getGameName());
    }
}

梅开二度,执行下:
在这里插入图片描述
明显看出,通用事件监听器的onApplicationEvent方法被执行了两次,看下触发的事件,分别是ContextRefreshedEvent和我们定义的PlayGameEvent事件
打游戏事件监听器的onApplicationEvent方法方法被执行了一次

那么从这两个事件中我们能够得出怎么样的结论呢?

我觉得是在spring中事件监听器监听的是:注册的事件和注册的事件子类.

事件监听源码

话不多讲,上源码
initApplicationEventMulticaster初始化事件监听广播的源码,在该源码中,我们发现,我们可以自己定义事件监听广播,只要在配置时,名字设置成applicationEventMulticaster就可以了.如果我们没有设置,spring也会自己初始化一个SimpleApplicationEventMulticaster.

	protected void initApplicationEventMulticaster() {
		//获取容器
		ConfigurableListableBeanFactory beanFactory = getBeanFactory();
		//APPLICATION_EVENT_MULTICASTER_BEAN_NAME就是applicationEventMulticaster,判断下是否已经加载到BeanDenifition
		if (beanFactory.containsLocalBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME)) {
			this.applicationEventMulticaster =
					beanFactory.getBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, ApplicationEventMulticaster.class);
			if (logger.isTraceEnabled()) {
				logger.trace("Using ApplicationEventMulticaster [" + this.applicationEventMulticaster + "]");
			}
		}
		else {
			//没有的话,就自己初始化一个SimpleApplicationEventMulticaster.
			this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
			beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, this.applicationEventMulticaster);
			if (logger.isTraceEnabled()) {
				logger.trace("No '" + APPLICATION_EVENT_MULTICASTER_BEAN_NAME + "' bean, using " +
						"[" + this.applicationEventMulticaster.getClass().getSimpleName() + "]");
			}
		}
	}

registerListeners将监听器注册到容器的事件监听广播

protected void registerListeners() {
		//循环,加入事件监听广播
		for (ApplicationListener<?> listener : getApplicationListeners()) {
			getApplicationEventMulticaster().addApplicationListener(listener);
		}
		String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false);
		//循环,加入事件监听广播
		for (String listenerBeanName : listenerBeanNames) {
			getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);
		}
		//这个比较特殊是容器初始化后就要执行的ApplicationEvents,在这儿是直接执行的
		Set<ApplicationEvent> earlyEventsToProcess = this.earlyApplicationEvents;
		this.earlyApplicationEvents = null;
		if (!CollectionUtils.isEmpty(earlyEventsToProcess)) {
			for (ApplicationEvent earlyEvent : earlyEventsToProcess) {
				//就是在这儿执行的
				getApplicationEventMulticaster().multicastEvent(earlyEvent);
			}
		}
	}

spring中SimpleApplicationEventMulticaster的multicastEvent

	@Override
	public void multicastEvent(ApplicationEvent event) {
		multicastEvent(event, resolveDefaultEventType(event));
	}

	@Override
	public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
		ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
		Executor executor = getTaskExecutor();
		//在这里判断监听器是否监听到了自己订阅的事件
		for (ApplicationListener<?> listener : getApplicationListeners(event, type)) {
			if (executor != null) {
				//如果有设置executor属性,也就是线程池的顶级类,就会使用线程池中的线程去执行方法
				executor.execute(() -> invokeListener(listener, event));
			}
			else {
				//没有则单线程执行
				invokeListener(listener, event);
			}
		}
	}

那么如何实现一个并行的执行方法呢?
试一下:
主类变化:

@ComponentScan
public class EightStart {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(EightStart.class);
        PlayGameEvent gameEvent = new PlayGameEvent("超级玛丽");
        context.publishEvent(gameEvent);
        SleepEvent sleepEvent = new SleepEvent("");
        context.publishEvent(sleepEvent);
    }
}

SleepListener

@Component
public class SleepListener implements ApplicationListener<SleepEvent> {
    @Override
    public void onApplicationEvent(SleepEvent event) {
        System.out.println(Thread.currentThread().getName()+"开始执行SleepListener");
        try {
            Thread.sleep(10000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(Thread.currentThread().getName()+"结束执行SleepListener");
    }
}

PlayGameListener

@Component
public class PlayGameListener implements ApplicationListener<PlayGameEvent> {
    @Override
    public void onApplicationEvent(PlayGameEvent event) {
        System.out.println(Thread.currentThread().getName()+"开始执行PlayGameListener");
        try {
            Thread.sleep(10000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(Thread.currentThread().getName()+"结束执行PlayGameListener");
    }
}

新增一个类:
EnentPostProcessor

@Component
public class EnentPostProcessor implements BeanFactoryPostProcessor {
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        if (beanFactory instanceof BeanDefinitionRegistry) {
            BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;
            GenericBeanDefinition beanDefinition = new GenericBeanDefinition();
            beanDefinition.setBeanClass(SimpleApplicationEventMulticaster.class);
            MutablePropertyValues propertyValues = new MutablePropertyValues();
            propertyValues.add("beanFactory",beanFactory);
            propertyValues.add("taskExecutor", Executors.newFixedThreadPool(2));
            beanDefinition.setPropertyValues(propertyValues);
          registry.registerBeanDefinition(AbstractApplicationContext.APPLICATION_EVENT_MULTICASTER_BEAN_NAME,beanDefinition);
        }
    }
}

看下运行结果
在这里插入图片描述
实现了并行异步的事件执行了

设计模式思考

spring的事件监听机制,使用了观察者模式的设计思想,
在spring的这个观察者模式中,事件监听广播就是担任观察者这一职位,在观察者中注册各自监听的事件和处理方法,当事件发生时,由观察者去匹配相应的监听器去执行这个监听器的方法
在spring中使用的观察者模式,无疑是给予了spring良好的拓展性,但是也对源码的阅读产生了一些困难.
另外,观察者模式的升级版本叫发布-订阅模式,它是完全无耦合的.

spring单机版的事件监听其实应用的不是很多,但是观察者模式的思想需要我们细细品味.当随着源码阅读越多,发现spring确实是一个很强悍的框架.至此,继续加油!

标签:spring,void,监听,public,class,事件,监听器,event
来源: https://blog.csdn.net/weixin_41046569/article/details/112994206

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有