Spring Application Event Example

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的值不为空,单线程则相反。

运行结果

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

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏Elasticsearch实验室

Elasitcsearch 底层系列 Lucene 内核解析之 Doc Value

       Elasticsearch 支持行存和列存,行存用于以文档为单位顺序存储多个文档的原始内容,在 Elasitcsearch 底层系列 Lucene...

2914
来自专栏阿杜的世界

Spring中的资源加载策略

Resouce接口可以根据资源的不同类型,或者资源位置的不同,给出对应的具体实现,Spring框架提供了一些实现类:

832
来自专栏函数式编程语言及工具

Akka(6): become/unbecome:运算行为切换

   通过一段时间的学习了解,加深了一些对Akka的认识,特别是对于Akka在实际编程中的用途方面。我的想法,或者我希望利用Akka来达到的目的是这样的:作为传...

2829
来自专栏与神兽党一起成长

jFinal路由解析源码分析

jFinal的路由解析是在JFinalFilter中做的,这个Filter也需要在web.xml中配置。JFinalFilter实现了javax.servlet...

1422
来自专栏Jed的技术阶梯

zookeeper案例之4个逻辑思维训练小题目

1172
来自专栏一枝花算不算浪漫

[Java 缓存] Java Cache之 Guava Cache的简单应用.

3886
来自专栏一个番茄说

让你在WebView中用JS调Native Object

之所做这个东西,源于之前项目中需要把一些页面用webView来呈现,但是web中需要调用native的方法,比如获取本地存的某些数据、调用摄像头等等,这里也就是...

1013
来自专栏安恒网络空间安全讲武堂

nox&amp;CSAW部分pwn题解

暑假的时候遇到了一群一起学习安全的小伙伴,在他们的诱劝下,开始接触国外的CTF比赛,作为最菜的pwn选手就试着先打两场比赛试试水,结果发现国外比赛真有意思哎嘿。

1653
来自专栏androidBlog

一步步拆解 LeakCanary

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/gdutxiaoxu/article/de...

821
来自专栏码匠的流水账

spring security运行时配置ignore url

以前用shiro的比较多,不过spring boot倒是挺推崇自家的spring security的,有默认的starter,于是也就拿来用了。

701

扫码关注云+社区