Spring事件机制之ApplicationListener与ApplicationEvent 一、一些概念 二、spring事件机制

Easter79
• 阅读 651

一、一些概念

 事件是可以被控件识别的操作,如按下确定按钮,选择某个单选按钮或者复选框。每一种控件有自己可以识别的事件,如窗体的加载、单击、双击等事件, 编辑框(文本框)的文本改变事,等等。事件有系统事件和用户事件。系统事件由系统激发,如时间每隔24小时,银行储户的存款日期增加一天。用户事件由用户 激发,如用户点击按钮,在文本框中显示特定的文本。事件驱动控件执行某项功能。

 触发事件的对象称为事件发送者;接收事件的对象称为事件接收者。

 事件模型一般用到了观察者模式,下面简单介绍下:

Spring事件机制之ApplicationListener与ApplicationEvent 一、一些概念 二、spring事件机制

  • SUBJECT
    • 目标知道它的观察者。可以有任意多个观察者观察同一个目标。
    • 提供注册和删除观察者对象的接口。
  • Observer(观察者)
    • 为那些在目标发生改变时需获得通知的对象定义一个更新接口。
  • ConcreteSubject(具体目标)
    • 将有关状态存入各ConcreteObserver对象。
    • 当它的状态发生改变时,向它的各个观察者发出通知。
  • ConcreteObserver(具体观察者)
    • 维护一个指向ConcreteSubject对象的引用。
    • 存储有关状态,这些状态应与目标的状态保持一致。
    • 实现Observer的更新接口以使自身状态与目标的状态保持一致。

二、spring事件机制

首先上图一张:

Spring事件机制之ApplicationListener与ApplicationEvent 一、一些概念 二、spring事件机制

  • ApplicationListener 就是我们的 Observer,需要到容器中注册。他要关心他所关心的ApplicationEvent 。一般有如下代码:if (event instanceof BlackListEvent) {}
  • ApplicationEventMulticaster是我们的SUBJECT一个代理。他会管理我们的 ApplicationListener 。
  • ApplicationEvent 是事件,它就是媒介,充当介质的作用。

在spring中,容器管理所有的 bean。是ApplicationEvent 驱动的,一个ApplicationEvent  publish了,观察这个事件的监听者就会送到通知。

下面我们使用spring的事件机制完成特定情况的功能,假设有如下使用场景:

应用场景:很多时候我们想要在某个类加载完毕时干某件事情,但是使用了spring管理对象,我们这个类引用了其他类(可能是更复杂的关联),所以当我们 去使用这个类做事情时发现包空指针错误,这是因为我们这个类有可能已经初始化完成,但是引用的其他类不一定初始化完成,所以发生了空指针错误,解决方案如 下:

1、写一个类继承spring的ApplicationListener监听,并监控ContextRefreshedEvent事件(容易初始化完成事件)

2、定义简单的bean:

或者直接使用@Component("BeanDefineConfigue")注解方式

完整的类如下:

package com.creatar.portal.webservice;

import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.stereotype.Component;

@Component("BeanDefineConfigue")
public class BeanDefineConfigue implements
ApplicationListener{//ContextRefreshedEvent为初始化完毕事件,spring还有很多事件可以利用 

@Autowired
  private IRoleDao roleDao;
/**
* 当一个ApplicationContext被初始化或刷新触发
*/
@Override
public void onApplicationEvent(ContextRefreshedEvent event) {
// roleDao.getUserList();//spring容器初始化完毕加载用户列表到内存
System.out.println("spring容易初始化完毕================================================");
}

}

或者使用xml配置方式(非注解),简单配置个bean即可

其他定义方式:

完整的类如下:

package com.creatar.portal.webservice;

import java.util.ArrayList;
import java.util.List;

import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.stereotype.Component;

@Component("BeanDefineConfigue2")
public class BeanDefineConfigue2 implements ApplicationListener{

Listlist = new ArrayList();

/**
* 当一个ApplicationContext被初始化或刷新触发
*/
@Override
public void onApplicationEvent(ApplicationEvent event) {
if (event instanceof ContextRefreshedEvent) {
System.out.println("spring容易初始化完毕================================================888");
}

}
}

spring其他事件:

spring中已经内置的几种事件:

ContextClosedEvent   、ContextRefreshedEvent  、ContextStartedEvent  、ContextStoppedEvent   、RequestHandleEvent

遇到的问题:
applicationontext和使用MVC之后的webApplicationontext会两次调用上面的方法,如何区分这个两种容器呢?

但是这个时候,会存在一个问题,在web 项目中(spring mvc),系统会存在两个容器,一个是root application context ,另一个就是我们自己的 projectName-servlet context(作为root application context的子容器)。

这种情况下,就会造成onApplicationEvent方法被执行两次。为了避免上面提到的问题,我们可以只在root application context初始化完成后调用逻辑代码,其他的容器的初始化完成,则不做任何处理,修改后代码

如下:

    @Override  
      public void onApplicationEvent(ContextRefreshedEvent event) {  
        if(event.getApplicationContext().getParent() == null){//root application context 没有parent,他就是老大.  
             //需要执行的逻辑代码,当spring容器初始化完成后就会执行该方法。  
        }  
      }

本文同步分享在 博客“kailing”(other)。
如有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。

点赞
收藏
评论区
推荐文章
御弟哥哥 御弟哥哥
3年前
完美解决Android RyclerView嵌套滑动事件冲突
在Android项目开发中,为了实现需求和兼并用户体验,相信很多人都碰到滑动事件冲突的问题。在Android系统中事件分发机制是一个很重要的组成部分,由于这事件分发机制不是本文重点,故不在此多述,如果有想详细了解的可以自己搜下,网上有很多相关资料详细描述了Android事件分发机制。一、问题场景由于RecyclerView自身的优点,使得它已经基本
Stella981 Stella981
3年前
Android Hook技术
1\.什么是HookHook英文翻译过来就是「钩子」的意思,那我们在什么时候使用这个「钩子」呢?在Android操作系统中系统维护着自己的一套事件分发机制。应用程序,包括应用触发事件和后台逻辑处理,也是根据事件流程一步步地向下执行。而「钩子」的意思,就是在事件传送到终点前截获并监控事件的传输,像个钩子钩上事件一样,并且能够在钩上事件时
Stella981 Stella981
3年前
IOS IBOutlet & IBAction
一 IBActionIBAction用于事件和方法建立联系,谁触发,就传递谁。事件有两种形式有参和无参,他们的区别是,有参数可以区分按钮,有可能一个事件监听多个按钮。(IBAction)functionName;(IBAction)functionName:(UIButton )sender;//se
Easter79 Easter79
3年前
Swing中事件的三种处理方法
 Swing是目前Java中不可缺少的窗口工具组,是用户建立图形化用户界面(GUI)程序的强大工具。JavaSwing组件自动产生各种事件来响应用户行为。如当用户点击按钮或选择菜单项目时,Swing组件会产生一个ActionEvent。Swing组件会产生许多事件,如ActionEvents,ChangeEvents,ItemEvents等,来响应用户的鼠
Stella981 Stella981
3年前
Android的消息循环与Handler机制理解
一、概念1、事件驱动型什么是事件驱动?就是有事了才去处理,没事就躺着不动。假如把用户点击按钮,滑动页面等这些都看作事件,事件产生后程序就执行相应的处理方法,就是属于事件驱动型。2、消息循环把需要处理的事件表示成一个消息,并且把这个消息放入一个队列。消息循环就是一循环,for或者while都一样。从消息队列里面取出未处理的消息,然后调用该消息的
Easter79 Easter79
3年前
Spring中ApplicationContext的事件机制
   ApplicationContext事件机制是观察者设计模式的实现,通过ApplicationEvent类和ApplicationListener接口,可以实现ApplicationContext事件处理。如果容器中有一个ApplicationListenerBean,每当ApplicationContext发布ApplicationEvent时,
Stella981 Stella981
3年前
ExtJS表单提交时,不用鼠标点击按钮提交,直接通过回车键提交
用ExtJs实现登陆界面,输入用户名和密码,点击确定后登陆。然而人们习惯于在输入两者后按回车键进行登陆。在extjs中,Button本身是支持回车事件的,前提是:焦点在按钮上,此时回车和单击事件是一回事。form中的field事件中有specilkey事件,可以响应回车键。在输入用户名,或者密码后点击"回车",让field响应回车事件,然后通过form提
Stella981 Stella981
3年前
Noark入门之异步事件
引入异步事件主要是为了各模块的解耦,每当完成一个动作时,向系统发布一个事件,由关心的模块自己监听处理,可选择同步处理,异步处理,延迟处理。何时发布事件,当其他模块关心此动作时<br比如获得道具时,任务系统模块要判定完成进度,BI模块需要上报等等都可以监听此事件,已达模块解耦0x00事件源一个实现xyz.noark.core.event
Stella981 Stella981
3年前
JavaScript事件 ——常见事件
1.什么是事件?      当我们与浏览器中Web页面进行某些类型的交互时,事件就发生了。事件可能是用户在某些内容上的点击、鼠标经过某个特定元素或按下键盘上的某些按键。事件还可能是Web浏览器中发生的事情,比如说某个Web页面加载完成,或者是用户滚动窗口或改变窗口大小。常见事件:(http://www.runoo
Stella981 Stella981
3年前
Javascript高级编程学习笔记(57)—— 事件(1)事件流
事件JS与HTML的交互是通过事件实现的而事件指的就是:文档或浏览器窗口特定的交互瞬间可以通过侦听器来预定事件,以便在事件发生时执行相应的代码这种模式也是设计模式中的观察者模式事件流有了事件,也就有了事件流的概念事件流故名思意:也就是事件的流向,所以事件流描述的是从页面中接收事件的顺序虽然事件流描述的都是事件的流
Easter79
Easter79
Lv1
今生可爱与温柔,每一样都不能少。
文章
2.8k
粉丝
5
获赞
1.2k