Spring ApplicationContext事件机制:ApplicationEvent与ApplicationListener

来源:互联网 发布:扫码查价软件 编辑:程序博客网 时间:2024/05/29 04:22

最近看一个项目的demo的时候,无意间看到了一个listener,跟进去看了下,对spring的事件机制有了个大致的了解。先看看几个概念:

  • ApplicationContext:这个接口功能有些强大,应该是spring框架的核心和基础。从它下面的接口声明就可以看出来。你会认为这个是spring的上下文,没错。但是我更偏向于它是一个具有丰富功能和主要地位的容器。
public interface ApplicationContext extends EnvironmentCapable, ListableBeanFactory, HierarchicalBeanFactory,MessageSource, ApplicationEventPublisher, ResourcePatternResolver
  • ApplicationEvent:这是抽象类, java.util.EventObject的子类,里面有一个timestamp的属性用于记录事件发生的时间和一个source对象纪录event source。 我的理解是它是一个事件, 但是更是一个事件信息/数据的载体。Srping 内置几个实现:ContextClosedEvent, ContextStartedEvent,ContextRefreshedEvent,ContextStoppedEvent。这几个事件实例包含的数据就是ApplicationContext对象。
  • ApplicationListener:顾名思义,这个是个listener,spring的事件机制是基于观察者设计模式的。里面有个onApplicationEvent方法,用于对事件的处理。
public interface ApplicationListener<E extends ApplicationEvent> extends EventListener {    /**     * Handle an application event.     * @param event the event to respond to     */    void onApplicationEvent(E event);}

这三者是什么关系,应该很显然了。ApplicationContext 通过publishEvent方法(该方法继承于接口ApplicationEventPublisher)发布事件(ApplicaitonEvent), 然后由ApplicationListener监听处理。
具体是怎么协作的呢?来看一个spring的实现:
ApplicationContext的实现类ClassPathXmlApplicationContext的publishEvent方法。

public void publishEvent(ApplicationEvent event) {.......          getApplicationEventMulticaster().multicastEvent(event);    if (this.parent != null) {        this.parent.publishEvent(event);    }}
public void multicastEvent(final ApplicationEvent event) {        for (final ApplicationListener listener : getApplicationListeners(event)) {            Executor executor = getTaskExecutor();            if (executor != null) {                executor.execute(new Runnable() {                    @Override                    public void run() {                        listener.onApplicationEvent(event);                    }                });            }            else {                listener.onApplicationEvent(event);            }        }    }

其中multicastEvent方法会根据注册进来的事件的类型,找到对应的监听者listener,(其实就是根据class type的一个map缓存中查找)。有兴趣的同学可以参考实现AbstractApplicationEventMulticaster。 那么你会问,这个map啥
时候构建的?啥时候注册时间进去的?当然是spring 加载你的配置的时候啊。你得注册!!! 还是看下面的demo 吧。˜讲了这么多了,应该来看个demo啦… …


首先我们创建listener

/** * @author mian.hem * */public class DemoApplicationListener implements ApplicationListener<DemoApplicationEvent> {    @Override    public void onApplicationEvent(DemoApplicationEvent event) {        System.out.println("on application event");        System.out.println("the event object is :" + event);        System.out.println("the event name is :" + event.getEventName());    }}
/** * @author mian.hem * */public class ContextStartedListener implements ApplicationListener<ContextStartedEvent> {    @Override    public void onApplicationEvent(ContextStartedEvent event) {        DemoApplicationListener listener = event.getApplicationContext().getBean("listener",                DemoApplicationListener.class);        if (listener != null) {            System.out.println("listener got.");        } else {            System.out.println("listener absent, please check!");        }    }}

然后就是对应的event,很简单,当中包括一个属性eventName。

public class DemoApplicationEvent extends ApplicationEvent {    private String eventName;    public String getEventName() {        return eventName;    }    public void setEventName(String eventName) {        this.eventName = eventName;    }    public DemoApplicationEvent(Object source) {        super(source);    }    /**     *      */    private static final long serialVersionUID = -3452985719192365159L;}

再者, 就是对应的spring配置:

<beans xmlns="http://www.springframework.org/schema/beans"    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"    xmlns:context="http://www.springframework.org/schema/context"    xsi:schemaLocation="http://www.springframework.org/schema/beans        http://www.springframework.org/schema/beans/spring-beans-3.1.xsd        http://www.springframework.org/schema/aop         http://www.springframework.org/schema/aop/spring-aop-3.0.xsd        http://www.springframework.org/schema/context         http://www.springframework.org/schema/context/spring-context-3.0.xsd">    <bean id="listener" name="listener"        class="com.maywe.spring.applicationlistener.DemoApplicationListener">    </bean>    <bean id="ctxStartedlistener" name="ctxStartedlistener"        class="com.maywe.spring.applicationlistener.ContextStartedListener">    </bean></beans>

最后, 就是我们的DemoRunner

public class DemoRunner {    /**     * @param args     * @throws InterruptedException     */    public static void main(String[] args) throws InterruptedException {        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(                "classpath*:/context/spring-context-application-listener.xml");        context.start();        String targetObj = "i am the target object";        DemoApplicationEvent event = new DemoApplicationEvent(targetObj);        event.setEventName("event name");        context.publishEvent(event);        Thread.sleep(3000);        context.close();    }}

一起来看看结果吧 --->

listener got.on application eventthe event object is :com.maywe.spring.applicationlistener.DemoApplicationEvent[source=i am the target object]the event name is :event name

注意:DemoRunner当中的一行代码:context.start(). 这个里面会发布一个ContextStartedEvent。里面包括applicationContext,从中我们可以获取所有注册的Bean。

1 0
原创粉丝点击