Spring Application Event Example

简介: Spring Application Event项目结构工程下载https://github.com/xiaoheike/SpringApplicationEventExample.gitSportEventpackage nd.

Spring Application Event

项目结构

spring application event项目结构

工程下载

https://github.com/xiaoheike/SpringApplicationEventExample.git

SportEvent

package nd.esp.com.event;

import org.springframework.context.ApplicationEvent;

public class SportEvent extends ApplicationEvent {
    private static final long serialVersionUID = 1L;

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

SportEvent是所有体育运动的父类,继承Spring ApplicationEvent,必须实现带参数构造函数,如上述代码所示。带参数构造函数传入参数可用于携带其他的信息。具体在NBAEvent中可以看到作用。

NBAEvent

package nd.esp.com.event;

public class NBAEvent extends SportEvent {

    private static final long serialVersionUID = 1L;

    private String text;

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

    public NBAEvent(String source, String text) {
        super(source);
        this.text = text;
    }

    public String news() {
        return text;
    }

    @Override
    public String getSource() {
        return String.class.cast(super.getSource());
    }
}

NBAEvent主题,用于显示NBA相关信息,上述getSource()方法重写了Spring ApplicationEvent 的父类EventObject,可以用于获得构造函数传入的参数。

SoccerEvent

package nd.esp.com.event;

public class SoccerEvent extends SportEvent {

    private static final long serialVersionUID = 1L;

    private String text;

    public SoccerEvent(String source) {
        super(source);
    }

    public SoccerEvent(Object source, String text) {
        super(source);
        this.text = text;
    }

    public String news() {
        return text;
    }

    @Override
    public String getSource() {
        return String.class.cast(super.getSource());
    }
}

SoccerEvent主题,用于显示足球先关信息,和NBAEvent功能类似。

SportEventListener

SportEventListener1

package nd.esp.com.listener;

import nd.esp.com.event.NBAEvent;
import nd.esp.com.event.SoccerEvent;
import nd.esp.com.event.SportEvent;

import org.springframework.context.ApplicationListener;

public class SportEventListener implements ApplicationListener<SportEvent> {

    public void onApplicationEvent(SportEvent event) {
        if (event instanceof NBAEvent) {
            System.out.println("SportEventListener1:" + NBAEvent.class.cast(event).getSource());
        }
        if (event instanceof SoccerEvent) {
            SoccerEvent soccerEvent = SoccerEvent.class.cast(event);
            System.out.println("SportEventListener1:" + soccerEvent.getSource() + "   " + soccerEvent.news());
        }
    }
}

SportEventListener2

package nd.esp.com.listener;

import nd.esp.com.event.NBAEvent;
import nd.esp.com.event.SoccerEvent;
import nd.esp.com.event.SportEvent;

import org.springframework.context.ApplicationListener;

public class SportEventListener2 implements ApplicationListener<SportEvent> {

    public void onApplicationEvent(SportEvent event) {
        if (event instanceof NBAEvent) {
            System.out.println("SportEventListener2:" + NBAEvent.class.cast(event).getSource());
        }
        if (event instanceof SoccerEvent) {
            SoccerEvent soccerEvent = SoccerEvent.class.cast(event);
            System.out.println("SportEventListener2:" + soccerEvent.getSource() + "   " + soccerEvent.news());
        }
    }
}

SportEventListener是观察者,当有新事件到来会被调用。SportEvent的功能在这里得到体现,通过创建父类,可以同时监控一类相似的主题,比如NBA事件以及足球事件。这样可以少些监听者。可以有多个观察者监听相同的时间,这里是指SportEvent。

SportEventPublisher

package nd.esp.com.publisher;

import nd.esp.com.event.NBAEvent;
import nd.esp.com.event.SoccerEvent;
import nd.esp.com.event.SportEvent;

import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class SportEventPublisher implements ApplicationContextAware {
    private ApplicationContext applicationEventPulisher = null;

    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationEventPulisher = applicationContext;
    }

    public void publishEvent(SportEvent sportEvent) {
        applicationEventPulisher.publishEvent(sportEvent);
    }

    public static void main(String[] args) {
        String[] xmlConfig = new String[] { "applicationContext.xml" };
        // 使用ApplicationContext来初始化系统
        ApplicationContext context = new ClassPathXmlApplicationContext(xmlConfig);
        SportEventPublisher publisher = (SportEventPublisher) context.getBean("applicationContextAware");
        publisher.publishEvent(new NBAEvent("NBA sport:骑士队获得总冠军"));
        publisher.publishEvent(new SoccerEvent("Scorrer sport:标题:中国获得世界杯冠军", "中国击败世界各国,取得10连冠"));

    }

}

SportEventPublisher当有新的时间时,由它发布,这个类继承Spring ApplicationContextAware,能够自动注入ApplicationContext对象。这个类实现了主题的通知功能。

appicationContext.xml(单线程)

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:jdbc="http://www.springframework.org/schema/jdbc" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc-3.0.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
    <bean id="applicationContextAware" class="nd.esp.com.publisher.SportEventPublisher"></bean>
    <bean id="applicationListener1" class="nd.esp.com.listener.SportEventListener1"></bean>
    <bean id="applicationListener2" class="nd.esp.com.listener.SportEventListener2"></bean>
</beans>

这两个bean是必须的,id可以任意,spring针对SportEventPublisher肯定是有经过特殊处理的,要不然该类中的ApplicationEventPublisher无法注入对应类。

这样的配置默认是采用单线程,为了提高效率可以使用多线程。修改application.xml文件如下即可。

applicationContext.xml(多线程)

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:jdbc="http://www.springframework.org/schema/jdbc" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc-3.0.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">

    <bean id="applicationContextAware" class="nd.esp.com.publisher.SportEventPublisher"></bean>
    <bean id="applicationListener1" class="nd.esp.com.listener.SportEventListener1"></bean>
    <bean id="applicationListener2" class="nd.esp.com.listener.SportEventListener2"></bean>
    
    <bean id="taskExecutor"  
        class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor">  
        <property name="corePoolSize" value="5" />  
        <property name="keepAliveSeconds" value="30000" />  
        <property name="maxPoolSize" value="1000" />  
        <property name="queueCapacity" value="200" />  
    </bean>  
    <bean id="applicationEventMulticaster"  
        class="org.springframework.context.event.SimpleApplicationEventMulticaster">  
        <property name="taskExecutor" ref="taskExecutor" />  
    </bean>
</beans>

idapplicationEventMulticaster不能够改变,猜测是spring需要根据这个id注入对象。

SimpleApplicationEventMulticaster

多线程或者单线程可以通过该类中的方法

@SuppressWarnings("unchecked")
public void multicastEvent(final ApplicationEvent event) {
    for (final ApplicationListener listener : getApplicationListeners(event)) {
        Executor executor = getTaskExecutor();
        if (executor != null) {
            executor.execute(new Runnable() {
                public void run() {
                    listener.onApplicationEvent(event);
                }
            });
        }
        else {
            listener.onApplicationEvent(event);
        }
    }
}

多线程产经下变量executor的值不为空,单线程则相反。

运行结果

spring application event example执行结果

教程结束,感谢阅读。
欢迎转载,但请注明本文链接,谢谢。
2016.5.12 17:49

目录
相关文章
|
6月前
|
Java Spring
Command line is too long. Shorten command line for Application or also for Spring Boot default confi
Command line is too long. Shorten command line for Application or also for Spring Boot default confi
14 1
|
6月前
|
Java Spring
Spring Event陷阱重重,我为何含泪放弃?
网络上比较推崇使用Spring Event 优雅的实现观察者模式。我在调研后也确实觉得这种方式能实现业务逻辑上的解耦,但线上的一次事故,让我意识到 Spring Event远远没有那么简单。
492 1
Spring Event陷阱重重,我为何含泪放弃?
|
10月前
|
Java Spring
深入理解Spring IOC之扩展篇(十)、SpringBoot中重要event介绍,顺便简单讲下SB的启动流程(二)
深入理解Spring IOC之扩展篇(十)、SpringBoot中重要event介绍,顺便简单讲下SB的启动流程(二)
72 0
|
10月前
|
XML Java 数据格式
深入理解Spring IOC之扩展篇(九)、SpringBoot中重要event介绍,顺便简单讲下SB的启动流程(一)
深入理解Spring IOC之扩展篇(九)、SpringBoot中重要event介绍,顺便简单讲下SB的启动流程(一)
95 0
|
10月前
|
设计模式 缓存 Java
深入理解Spring IOC之扩展篇(七)、Spring中的event以及自定义event
深入理解Spring IOC之扩展篇(七)、Spring中的event以及自定义event
81 0
|
11月前
|
Java Linux Spring
每日一博 - Spring Boot Application as a Service
每日一博 - Spring Boot Application as a Service
71 0
|
11月前
|
消息中间件 存储 架构师
【首席架构师看Event Hub】Kafka深挖 -第2部分:Kafka和Spring Cloud Stream
【首席架构师看Event Hub】Kafka深挖 -第2部分:Kafka和Spring Cloud Stream
|
11月前
|
消息中间件 缓存 前端开发
「首席看Event Hub」如何在您的Spring启动应用程序中使用Kafka
「首席看Event Hub」如何在您的Spring启动应用程序中使用Kafka
|
11月前
|
消息中间件 架构师 Java
「首席架构师看Event Hub」Kafka的Spring 深入挖掘 -第1部分
「首席架构师看Event Hub」Kafka的Spring 深入挖掘 -第1部分
|
12月前
|
消息中间件 JavaScript 小程序
Spring Event + DDD = 王炸!!下
Spring Event + DDD = 王炸!!下