Spring框架中事件发布及其原理
在业务系统中,当多个模块之间需要进行通信的时候,事件可以作为信使传递消息,从而使模块之间免于耦合,因此利用事件机制十分常见。那么,在spring中如何发布一个事件,又如何监听并处理一个事件呢?
事件源发布事件
定义事件源
事件源通常是某个业务类,当它处理完自身的业务逻辑后,向外某个事件发布事件。
//业务类
public void produceData{
...
springContextHolder.publishEvent(new DataEvent("数据产生了"))
...
}
定义事件
事件源中发布的事件DateEvent是一个继承了applicationEvent的自定义类
public class DataEvent extends ApplicationEvent{
String field1;
public DataEvent(String msg){
super("DataEvent");
this.field1=msg;
}
....
}
定义监听器
事件、发布事件的事件源都定义好了,那么由谁来发出事件呢?DataEvent事件的监听器DataEventListener是一个实现了ApplicationListener的类,通过重写onApplicationEvent方法,可以实现监听器接收到相应事件后的处理逻辑。
为了简单起见,这里就直接输出dataEvent事件中携带的msg。
public class DataEventListener implements ApplicationListener<DataEvent>
{
@Override
public void onApplicationEvent(DataEvent dataEvent)
{
//这里可以写自己的逻辑
System.out.print(dataEvent.getField1());
}
}
测试
//业务类执行produceData方法
produceData();
//控制台会输出
"数据产生了"
上述是一个spring发布事件的例子。
作为程序员不能只会用,不懂其中的原理。这样长久下去会让自己在职场上失去议价能力,在互联网行业是很危险的。
说个题外话吧,我记得之前有段时间公司的业务比较忙,于是就把一部分非核心工作交给了外包公司的人,外包的人员在我们公司驻场开发。所以和他们之间有一段比较密切的接触。
一开始不太熟悉的时候,我内心替他们感到不公,觉得都是同行,都一样上下班,为啥他们待遇那么低(那时候年轻,圣母心泛滥)。但是时间一久,我就发现问题所在了。他们基本上有一个很普遍的问题,就是不求甚解。当他们拿到一个需求后,不会多问,不会深究。基本就是照着模板代码替换和修改,称之为“像素级”的模仿都不为过。
由于不清楚其中的原理,所以经常会被一些小问题给卡住。不知道为什么,总是感觉他们很焦虑,被卡住就直接copy异常提示赶紧上百度搜,甚至不会自己去加工和提炼一下异常提示再去搜。大多数时候,逻辑问题是搜不出来的,然后他们会变得越来越焦躁,压力越来越大,最后查不到就束手无策。
久而久之,个人自信心下降,更加没有心情和决心去探究一个问题。最后是啥结局,可能不用多说,我们都明白。
不过凡事都有例外,当时那一批驻场员工中有一个小伙年龄不大,小时候在农村教育条件不好,后来上了个大专。毕业以后大公司卡学历,最后没办法才去的外包。但是,他和别人不太一样。他的决心和求知欲都明显超过那一批中的其他人。他遇到问题,也不会,有时候也焦虑,他也上网查。但是和别人不一样。他查过的东西,绝对不会再卡住他第二次。甚至查过一个问题,相似的问题也难不住他。他人并不聪明,就是有一股往里钻的劲儿支撑着他。
我对他印象特别深刻,当时就觉得他和其他人那种应付交差的态度很不一样。果然,后来听同事说这个小伙有次去另外一个一线大厂驻场,被那个组的leader看中,最后留下来变成正式员工了。
顺便给自己的公粽号打个广告吧,欢迎围观“趣论编程”。
好了,说了太多题外话。说回正题,我们探究一下spring为什么能够发布事件吧,探究一下它背后的机理是啥。
springContextHolder
从上边可以看出,springContextHolder.publishEvent向外推送了数据。springContextHolder是自己定义的类,它实现了ApplicationContextAware接口。
public class SpringContextHolder implements ApplicationContextAware {
private ApplicationContext applicationContext;
@Override
public void setApplicationContext(ApplicationContext applicationContext)throws BeansException {
this.applicationContext=applicationContext;
}
public ApplicationContext getApplicationContext()
{
return applicationContext;
}
/**
* 发布事件
* @param applicationEvent
*/
public void publishEvent(ApplicationEvent applicationEvent)
{
applicationContext.publishEvent(applicationEvent);
}
//这里省略无关代码
}
我们可以得出两点:
第一:springContextHolder继承了ApplicationContextAware接口。
第二:springContextHolder也不是真正发送事件的对象,而是委托了applicationContext发布事件。
那么我们分别来讨论下边两点。
1.springContextHolder为什么能拿到applicationContext,是什么时候被初始化的?
2.委托给applicationContext的事件又是如何被发布的?
ApplicationContextAware接口
Spring提供了大量的aware接口,spring的aware接口赋予bean获得spring容器服务的能力。
aware接口 | 作用 |
---|---|
BeanNameAware | 可以获取容器中bean的名称 |
BeanFactoryAware | 获取当前bean factory这也可以调用容器的服务 |
MessageSourceAware | 获得message source,这也可以获得文本信息 |
ResourceLoaderAware | 获得资源加载器,可以获得外部资源文件的内容 |
applicationEventPulisherAware | 应用事件发布器,可以发布事件 |
ApplicationCo |