在设计模式中,观察者模式中主要由观察者和主题事件这两个角色组成,而Spring中的监听器设计相对设计模式中的观察者模式来说更加抽象,主要多出了一些额外的角色,目的是为了能够更好的让观察者和事件解耦,一起来学习一下吧!
设计模式中的观察者模式 V.S Spring监听器
设计模式中的观察者模式角色:
- 抽象主题(Subject):
它把所有观察者对象的引用保存到一个聚集里,每个主题都可以有任何数量的观察者。 抽象主题提供一个接口,可以增加和删除观察者对象。 - 具体主题(Concrete Subject):
将有关状态存入具体观察者对象;在具体主题内部状态改变时,给所有登记过的观察者发出通知。 - 抽象观察者(Observer):
为所有的具体观察者定义一个接口,在得到主题通知时更新自己。 - 具体观察者(Concrete Observer):
实现抽象观察者角色所要求的更新接口,以便使本身的状态与主题状态协调
Spring监听器主要角色
- ApplicationEvent :
事件抽象类,根据不同的事件 - ApplicationListener:
接口,只有一个方法,传递了一个事件 - ApplicationEventMulticaster:
事件多播器,主要就是用来负责对ApplicationListener的管理,添加、删除、事件广播。 - ApplicationEventPublisher:
接口,主要用于发布事件
类的设计图
Spring启动时发布事件源码分析
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// Prepare this context for refreshing.
prepareRefresh();
// Tell the subclass to refresh the internal bean factory.
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// Prepare the bean factory for use in this context.
prepareBeanFactory(beanFactory);
try {
// Allows post-processing of the bean factory in context subclasses.
postProcessBeanFactory(beanFactory);
// Invoke factory processors registered as beans in the context.
invokeBeanFactoryPostProcessors(beanFactory);
// Register bean processors that intercept bean creation.
registerBeanPostProcessors(beanFactory);
// Initialize message source for this context.
initMessageSource();
// Initialize event multicaster for this context.
//初始化事件多播器
initApplicationEventMulticaster();
// Initialize other special beans in specific context subclasses.
onRefresh();
// Check for listener beans and register them.
//注册监听器
registerListeners();
// Instantiate all remaining (non-lazy-init) singletons.
finishBeanFactoryInitialization(beanFactory);
// Last step: publish corresponding event.
//改方法中包含了:发布事件
finishRefresh();
}
catch (BeansException ex) {
if (logger.isWarnEnabled()) {
logger.warn("Exception encountered during context initialization - " +
"cancelling refresh attempt: " + ex);
}
// Destroy already created singletons to avoid dangling resources.
destroyBeans();
// Reset 'active' flag.
cancelRefresh(ex);
// Propagate exception to caller.
throw ex;
}
finally {
// Reset common introspection caches in Spring's core, since we
// might not ever need metadata for singleton beans anymore...
resetCommonCaches();
}
}
}
1、创建一个事件多播器,方法入口在refresh方法中。
protected void initApplicationEventMulticaster() {
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
//第一次进来工厂中肯定没有这个bean
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() + "]");
}
}
}
2、注册监听器
protected void registerListeners() {
// Register statically specified listeners first.
//获取应用程序中的监听器集合,添加到applicationListeners集合中
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接口的类,并放入applicationListenerBeans集合中
String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false);
for (String listenerBeanName : listenerBeanNames) {
getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);
}
// Publish early application events now that we finally have a multicaster...
Set<ApplicationEvent> earlyEventsToProcess = this.earlyApplicationEvents;
this.earlyApplicationEvents = null;
if (earlyEventsToProcess != null) {
for (ApplicationEvent earlyEvent : earlyEventsToProcess) {
getApplicationEventMulticaster().multicastEvent(earlyEvent);
}
}
}
3、发布事件
protected void finishRefresh() {
// Clear context-level resource caches (such as ASM metadata from scanning).
clearResourceCaches();
// Initialize lifecycle processor for this context.
initLifecycleProcessor();
// Propagate refresh to lifecycle processor first.
getLifecycleProcessor().onRefresh();
// Publish the final event.
//发布事件
publishEvent(new ContextRefreshedEvent(this));
// Participate in LiveBeansView MBean, if active.
LiveBeansView.registerApplicationContext(this);
}
protected void publishEvent(Object event, @Nullable ResolvableType eventType) {
Assert.notNull(event, "Event must not be null");
// Decorate event as an ApplicationEvent if necessary
ApplicationEvent applicationEvent;
if (event instanceof ApplicationEvent) {
applicationEvent = (ApplicationEvent) event;
}
else {
applicationEvent = new PayloadApplicationEvent<>(this, event);
if (eventType == null) {
eventType = ((PayloadApplicationEvent<?>) applicationEvent).getResolvableType();
}
}
// Multicast right now if possible - or lazily once the multicaster is initialized
if (this.earlyApplicationEvents != null) {
this.earlyApplicationEvents.add(applicationEvent);
}
else {
//调用多播器的multicastEvent方法发布事件
getApplicationEventMulticaster().multicastEvent(applicationEvent, eventType);
}
// Publish event via parent context as well...
if (this.parent != null) {
if (this.parent instanceof AbstractApplicationContext) {
((AbstractApplicationContext) this.parent).publishEvent(event, eventType);
}
else {
this.parent.publishEvent(event);
}
}
}
public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
Executor executor = getTaskExecutor();
//从第二步注册时,准备好的两个集合中获取监听器。applicationListenerBeans、applicationListeners
for (ApplicationListener<?> listener : getApplicationListeners(event, type)) {
if (executor != null) {
//调用给定事件的监听器方法
executor.execute(() -> invokeListener(listener, event));
}
else {
invokeListener(listener, event);
}
}
}
protected void invokeListener(ApplicationListener<?> listener, ApplicationEvent event) {
ErrorHandler errorHandler = getErrorHandler();
if (errorHandler != null) {
try {
doInvokeListener(listener, event);
}
catch (Throwable err) {
errorHandler.handleError(err);
}
}
else {
//具体调用
doInvokeListener(listener, event);
}
}
private void doInvokeListener(ApplicationListener listener, ApplicationEvent event) {
try {
//最终回调到了接口方法,由实现者自行实现。
listener.onApplicationEvent(event);
}
catch (ClassCastException ex) {
String msg = ex.getMessage();
if (msg == null || matchesClassCastMessage(msg, event.getClass())) {
// Possibly a lambda-defined listener which we could not resolve the generic event type for
// -> let's suppress the exception and just log a debug message.
Log logger = LogFactory.getLog(getClass());
if (logger.isTraceEnabled()) {
logger.trace("Non-matching event type for listener: " + listener, ex);
}
}
else {
throw ex;
}
}
}
如何发布一个自己的事件
1、注解+实现ApplicationListener接口
package com.wyl.learn.listen;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.stereotype.Component;
@Component
public class MyListener implements ApplicationListener {
@Override
public void onApplicationEvent(ApplicationEvent event) {
System.out.println(event);
System.out.println("my listener event===============");
}
}
package com.wyl.learn;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class TestSpring {
public static void main(String[] args) {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext("com.wyl.learn");
}
}
通过上述分析现在应该清楚,onApplicationEvent方法的调用就是在启动时,发布了一个publishEvent(new ContextRefreshedEvent(this));事件时触发的。
当没有指定具体事件类型时,任何事件的发布都会调用到onApplicationEvent方法。
指定一个自定义的事件类型。
public class MyEvent extends ApplicationEvent {
/**
* Create a new {@code ApplicationEvent}.
*
* @param source the object on which the event initially occurred or with
* which the event is associated (never {@code null})
*/
public MyEvent(Object source) {
super(source);
}
}
package com.wyl.learn.listen;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.stereotype.Component;
@Component
public class MyListener implements ApplicationListener<MyEvent> {
/*@Override
public void onApplicationEvent(ApplicationEvent event) {
System.out.println(event);
System.out.println("my listener event===============");
}*/
@Override
public void onApplicationEvent(MyEvent event) {
System.out.println(event);
System.out.println("my listener event===============");
}
}
此时再启动Spring时,则不会触发MyListener的onApplicationEvent方法调用。
2、手动发布
对于自定义的事件,只需通过手动发布即可。
package com.wyl.learn;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class TestSpring {
public static void main(String[] args) {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext("com.wyl.learn");
//发布指定事件
applicationContext.publishEvent(new MyEvent("自定义事件发布"));
}
}
3、@EventListener注解
使用@EventListener注解的方式可以使代码更加简洁,减少Listener的创建。
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Component;
@Component
public class MyAnnotationListener {
@EventListener
public void myEvent(MyEvent myEvent){
System.out.println("使用@EventListener注解方式发布事件");
System.out.println(myEvent.toString());
}
}
有了注解MyListener类就用不到了,MyEvent还是和之前的一样,启动方法也不变。
package com.wyl.learn;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class TestSpring {
public static void main(String[] args) {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext("com.wyl.learn");
//发布指定事件
applicationContext.publishEvent(new MyEvent("自定义事件发布"));
}
}
SpringBoot中的运用
SpringBoot中run方法也用到了一些监听器,当你理解了spring的监听器设计后,再看SpringBoot时则会非常轻松。
public ConfigurableApplicationContext run(String... args) {
StopWatch stopWatch = new StopWatch();
stopWatch.start();
ConfigurableApplicationContext context = null;
Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
configureHeadlessProperty();
SpringApplicationRunListeners listeners = getRunListeners(args);
//看看这个监听器是如何使用的
listeners.starting();
try {
ApplicationArguments applicationArguments = new DefaultApplicationArguments(
args);
ConfigurableEnvironment environment = prepareEnvironment(listeners,
applicationArguments);
configureIgnoreBeanInfo(environment);
Banner printedBanner = printBanner(environment);
context = createApplicationContext();
exceptionReporters = getSpringFactoriesInstances(
SpringBootExceptionReporter.class,
new Class[] { ConfigurableApplicationContext.class }, context);
prepareContext(context, environment, listeners, applicationArguments,
printedBanner);
refreshContext(context);
afterRefresh(context, applicationArguments);
stopWatch.stop();
if (this.logStartupInfo) {
new StartupInfoLogger(this.mainApplicationClass)
.logStarted(getApplicationLog(), stopWatch);
}
listeners.started(context);
callRunners(context, applicationArguments);
}
catch (Throwable ex) {
handleRunFailure(context, ex, exceptionReporters, listeners);
throw new IllegalStateException(ex);
}
try {
listeners.running(context);
}
catch (Throwable ex) {
handleRunFailure(context, ex, exceptionReporters, null);
throw new IllegalStateException(ex);
}
return context;
}
public void starting() {
for (SpringApplicationRunListener listener : this.listeners) {
listener.starting();
}
}
看看这个方法,不就和上面spring启动时使用的方法一样嘛,连多播器都是spring中默认的SimpleApplicationEventMulticaster,后面方法已经不用看了。