八、Spring-监听器

1.介绍

  • 本质是“定义对象之间的一对多依赖关系,以便当一个对象改变状态时,其所有依赖关系都会被通知并自动更新”。
  • 发布/订阅模式的子集,它允许许多观察者对象查看事件。

2.分类

2.1传统的监听器模式

      传统的监听器模式分为2类角色,一个是被观察者,一个是观察者。举个例子:假如你去4s店买一个车,当你买了一辆车之后,销售员和经理会分别收到你购买车的这个消息,进行不同的处理流程。这里你买车就是被观察者,经理和销售员就是观察者。

java代码设计的思路就是:

  1. 编写一个关于客户的类,里面定义了客户买车这个动作方法。
  2. 客户类添加一个观察者集合,需要通知那些人的集合。
  3. 当客户发生有关行为时,就要去遍历这个集合进行相关通知。
  4. 不同观察者根据不同行为,做出不同反馈行为。
public interface OrdinaryListener {
    void callback(String event);
}
public class ActionListener {
    private List<OrdinaryListener> list=new ArrayList<OrdinaryListener>();

    public void addListenner(OrdinaryListener listener){this.list.add(listener);}

    public void hand(){list.forEach(s->{s.callback("事件发生了");});}
}
/**
 * 1.监听者: 等待被监听者通知的事件,等待被回调。实现Listener接口。
 * 2.被监听者:ActionListener主要通知监听者事件
 */
public class ListennerMain {
    public static void main(String[] args) {

        ActionListener actionListener = new ActionListener();
        actionListener.addListenner(listener->{
            System.out.println("监听者1收到:"+listener);
        });
        actionListener.addListenner(listener->{
            System.out.println("监听者2收到:"+listener);
        });

        actionListener.hand();
    }
}

2.2 spring监听器模式

   spring里面的监听模式分为:

  1. 事件:观察者具体要执行的动作
  2. 监听器:观察者,可以接受不同的事件做不同的处理
  3. 事件路由器:spring里面叫多播器,其实就是做的就是被观察者发生行为后,遍历被观察者集合进行遍历通知。
  4. 事件源:谁来执行发布具体的事件来源

   具体的执行过程:

  1. 事件源发布不同的事件
  2. 事件发布后,会调用spring里面叫多播器,进行事件的广播路由,触发具体的监听器去执行
  3. 监听器收到不同事件,进行不同处理。

下面是java代码,没有使用spring里面叫多播器那种模式,后面源码分析会有说明。

public class EventObject {

    public EventSource source;

    public EventObject(EventSource source) {
        this.source = source;
    }
}
public interface Listener {
    void callback(EventObject event);
}
public class EventSource {

    public String eventName;

    // 事件源增加监听器对象
    private Set<Listener> listenerSet = new HashSet<>();

    public void registerEventListener(Listener eventListener){
        if (eventListener != null){
            listenerSet.add(eventListener);
        }
    }

    public void handle(){
        for(Listener listener : listenerSet){
            listener.callback(new EventObject(this));
        }
        System.out.println(this.eventName+"开始处理");
    }
}
/**
 * 1.事件源 EventSource 具有注册监听器的方法
 * 2.事件对象 EventObject 事件
 * 3.监听器 Listener 有callback(EventObject)方法,当收到事件发生后的处理。
 * 4.事件对象:主要目的是包装事件源,然后将本身(事件对象)交给监听器。
 */
public class ListenMain {

    public static void main(String[] args) {

        EventSource source1 = new EventSource();

        source1.eventName = "source1";

        source1.registerEventListener(event -> {
            System.out.println("listen1:" + event.source);
        });
        source1.registerEventListener(event -> {
            System.out.println("listen2:" + event.source);
        });
        source1.handle();
    }

}

3.spring关于监听器部分源码分析

大体的处理流程源码中:

  • 提前准备好一些事件
  • 初始化多播器
  • 准备好的监听器
  • 多播器中注册自己有的监听器
  • 准备事件发布,通知多播器进行相关处理

大家可以想看一下AbstractApplicationContext中refresh()方法中有关的代码

public void refresh() throws BeansException, IllegalStateException {

       ...................
        // Prepare this context for refreshing.
		prepareRefresh();
       // Initialize event multicaster for this context.
	   initApplicationEventMulticaster();
       // Check for listener beans and register them.
		registerListeners();
       // Last step: publish corresponding event.
		finishRefresh();
       ...................

}

在prepareRefresh()方法中会初始化一些早起事件集合,早期监听者的集合

// Store pre-refresh ApplicationListeners...
		if (this.earlyApplicationListeners == null) {
			this.earlyApplicationListeners = new LinkedHashSet<>(this.applicationListeners);
		}
		else {
			// Reset local application listeners to pre-refresh state.
			this.applicationListeners.clear();
			this.applicationListeners.addAll(this.earlyApplicationListeners);
		}

		// Allow for the collection of early ApplicationEvents,
		// to be published once the multicaster is available...
		this.earlyApplicationEvents = new LinkedHashSet<>();

在initApplicationEventMulticaster方法中会初始化一个事件多播器,如果容器有,就用已经有的,没有的话,需呀new一个出来,注册到容器,并且赋值beanfatory。

	protected void initApplicationEventMulticaster() {
		ConfigurableListableBeanFactory beanFactory = getBeanFactory();
		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 {
			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()方法中1.查看集合中已经存在的监听器注册到多播器中(这里含有之前的早期监听器集合) 2.查找beanfactory中实现ApplicationListener接口的bean的名字,注册到多播器中 3.因为容器之前初始化了一个早期事件集合,这里面有可能挤压了早期事件,所以这里使用多播器广播早期事件

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!
		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 (!CollectionUtils.isEmpty(earlyEventsToProcess)) {
			for (ApplicationEvent earlyEvent : earlyEventsToProcess) {
				getApplicationEventMulticaster().multicastEvent(earlyEvent);
			}
		}
	}

在finishRefresh()方法中会发布一个ContextRefreshedEvent事件

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.
		if (!NativeDetector.inNativeImage()) {
			LiveBeansView.registerApplicationContext(this);
		}
	}

这里探究一下publishEvent它最后调用的是SimpleApplicationEventMulticaster的multicastEvent方法进行事件路由的。

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.execute(() -> invokeListener(listener, event));
			}
			else {
				invokeListener(listener, event);
			}
		}
	}

感兴趣的话大家可以探索一下这个类

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值