spring 事件机制

0 概述

本文将分别从使用、源码层面上,来分析Spring 的ApplicationContext事件机制。。

1 首先来看如何使用

//获取上下文类ApplicationContext,通过ApplicationContext发布事件
@Component
public class SpringContext implements ApplicationContextAware{

    private static ApplicationContext applicationContext;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        SpringContext.applicationContext=applicationContext;
    }
    public static ApplicationContext getApplicationContext(){
        return applicationContext;
    }

}

//事件类

import org.springframework.context.ApplicationEvent;


public class TestEvent extends ApplicationEvent {
    private String data;

    public String getData() {
        return data;
    }

    public void setData(String data) {
        this.data = data;
    }

    public TestEvent(Object source) {
        super(source);
    }
}

//监听器监听某个事件类

@Component
public class TestEventListener implements ApplicationListener<TestEvent> {

    @Override
    public void onApplicationEvent(TestEvent event) {
        System.out.println("---event.getData()---"+event.getData());
    }
}

测试入口类

import com.hsc.study.context.SpringContext;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 * Created by apple on 17/12/2.
 */
public class Test {
    public static void main(String[] args) throws Exception{
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");
        TestEvent testEvent=new TestEvent(new Object());
        testEvent.setData("testEvent");
 //发布事件      SpringContext.getApplicationContext().publishEvent(testEvent);
        //主程序等会退出
        Thread.sleep(10000);
    }
}

1.事件是怎么发出去的?
2.事件怎么找到具体监听器的?
3.是同步还是异步的?

2 原理分析

从代码上可以看出,1)ApplicationContext会从容器中找出符合的Listener(根据事件类的类型找到符合条件的Listener,可能是多个),由此也可以看出Listener必须是bean;2)默认是同步 调用Listener。
发布事件

这里写图片描述

3 如何实现异步方式调用

从SimpleApplicationEventMulticaster类中代码可以看出,如果想做成异步需要给出线程池。

    @Override
    public void multicastEvent(final ApplicationEvent event, ResolvableType eventType) {
        ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
        for (final ApplicationListener<?> listener : getApplicationListeners(event, type)) {
        //返回executor(线程池)不为空,将invokeListener放到线程池中去做(异步方式)
            Executor executor = getTaskExecutor();
            if (executor != null) {
                executor.execute(new Runnable() {
                    @Override
                    public void run() {
                        invokeListener(listener, event);
                    }
                });
            }
            else {
                invokeListener(listener, event);
            }
        }
    }

实现异步方式,值得说明是这个bean name 必须为applicationEventMulticaster。


import org.springframework.context.event.SimpleApplicationEventMulticaster;
import org.springframework.stereotype.Component;

import java.util.concurrent.Executor;
import java.util.concurrent.Executors;

/**
 * Created by apple on 18/1/8.
 * bean 名字必须为applicationEventMulticaster
 */

@Component("applicationEventMulticaster")
public class ApplicationEventMulticaster extends SimpleApplicationEventMulticaster {
    private Executor executor=Executors.newFixedThreadPool(20);
    @Override
    protected Executor getTaskExecutor() {
        return executor;
    }
}

为什么bean name 必须指定为applicationEventMulticaster,从AbstractApplicationContext中代码可以看出,在初始化ApplicationEventMulticaster时候会检查bean 是否存在name为applicationEventMulticaster的bean,如果存在就获取当前bean,如果不存在则new 一个SimpleApplicationEventMulticaster并注册到beanFactory。

    public static final String APPLICATION_EVENT_MULTICASTER_BEAN_NAME = "applicationEventMulticaster";

这里写图片描述

4 总结

通过ApplicationContext事件可以将一些耗时且不重要的操作异步来做而且可以将代码解耦。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值