Java事件监听器原理以及使用Spring的事件监听

事件监听包括必不可少的三个元素:事件、事件源和监听器。

事件:容易理解,点击一下鼠标是一个事件,更改某个类属性也可以抽象为一个事件。

事件源:发布事件的地方,也就是事件产生的地方。

监听器:定义事件发生后要采取的操作。

1,接下来举例说明Java如何实现监听模式

事件:

package com.wxy.popcorn.eventlistener.model;
 
import java.util.EventObject;
 
public class MyEvent extends EventObject {
    private String name;
 
    /**
     * Constructs a prototypical Event.
     *
     * @param source The object on which the Event initially occurred.
     * @throws IllegalArgumentException if source is null.
     */
    public MyEvent(Object source, String name) {
        super(source);
        this.name = name;
    }
 
    public String getName() {
        return name;
    }
}

事件源:

package com.wxy.popcorn.eventlistener.model;
 
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
 
import com.wxy.popcorn.eventlistener.listener.MyListener;
 
public class EventSource {
    private String name;
    private Set<MyListener> listeners = new HashSet<MyListener>();
 
    public void addListener(MyListener myListener) {
        listeners.add(myListener);
    }
 
    public void removeListener(MyListener myListener) {
        listeners.remove(myListener);
    }
 
    public void notifyEvent(MyEvent myEvent) {
        Iterator<MyListener> iterator = listeners.iterator();
        while(iterator.hasNext()) {
            MyListener listener = iterator.next();
            listener.handleEvent(myEvent);
        }
    }
 
    //当name属性发生了改变时发布一个事件。当然,完全可以在其他的逻辑下发布事件
    public void updateName(String name) {
        if(name==null && this.name==null) {
            return;
        }
        if (name==null || this.name==null || !name.equals(this.name)) {
            this.name = name;
            notifyEvent(new MyEvent(this, name));
        }
    }
}


监听器接口:

package com.wxy.popcorn.eventlistener.listener;
 
import java.util.EventListener;
 
import com.wxy.popcorn.eventlistener.model.MyEvent;
 
public interface MyListener extends EventListener{
    void handleEvent(MyEvent myEvent);
}


监听器实现:

package com.wxy.popcorn.eventlistener.listener;
 
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
 
import com.wxy.popcorn.eventlistener.model.MyEvent;
 
public class MyListenerImpl implements MyListener{
    private Logger logger = LoggerFactory.getLogger(this.getClass());
    public void handleEvent(MyEvent myEvent) {
        logger.info("the name was set to {}", myEvent.getName());
    }
}


测试类:

package com.wxy.popcorn;
 
import org.junit.Test;
 
import com.wxy.popcorn.eventlistener.listener.MyListenerImpl;
import com.wxy.popcorn.eventlistener.model.EventSource;
 
public class EventlistenerTest {
 
    @Test
    public void test() {
        EventSource eventSource = new EventSource();
        eventSource.addListener(new MyListenerImpl());
        eventSource.updateName("popcorn");
    }
}

运行结果:
2018-01-07 19:01:36.886 [main] INFO  [MyListenerImpl.java:11] the name was set to popcorn

2,Spring事件监听

有事件,即有事件监听器. 有人问你spring监听器有哪些你看了下文即也知道了。
 
事件传播
ApplicationContext基于Observer模式(java.util包中有对应实现),提供了针对Bean的事件传
播功能。通过Application. publishEvent方法,我们可以将事件通知系统内所有的
ApplicationListener。
事件传播的一个典型应用是,当Bean中的操作发生异常(如数据库连接失败),则通过事件传播
机制通知异常监听器进行处理。在笔者的一个项目中,就曾经借助事件机制,较好的实现了当系统
异常时在监视终端上报警,同时发送报警SMS至管理员手机的功能。
 
ApplicationContext容器提供了容器内部事件发布功能,是继承自JavaSE标准自定义事件类而实现的。

JavaSE标准自定义事件结构不在此详细描述,一张图很直观的描述清楚:

EventObject,为JavaSE提供的事件类型基类,任何自定义的事件都继承自该类,例如上图中右侧灰色的各个事件。Spring中提供了该接口的子类ApplicationEvent。

EventListener为JavaSE提供的事件监听者接口,任何自定义的事件监听者都实现了该接口,如上图左侧的各个事件监听者。Spring中提供了该接口的子类ApplicationListener接口。

JavaSE中未提供事件发布者这一角色类,由各个应用程序自行实现事件发布者这一角色。Spring中提供了ApplicationEventPublisher接口作为事件发布者,并且ApplicationContext实现了这个接口,担当起了事件发布者这一角色。但ApplicationContext在具体实现上有所差异,Spring提供了ApplicationEventMulticaster接口,负责管理ApplicationListener和发布ApplicationEvent。ApplicationContext会把相应的事件相关工作委派给ApplicationEventMulticaster接口实现类来做。类图如下所示:

事件发布时序图如下:

 
-------------------------------------------------------------------------------------------------
Spring中提供一些Aware相关的接口,BeanFactoryAware、 ApplicationContextAware、ResourceLoaderAware、ServletContextAware等等,其中最常用到的是ApplicationContextAware。实现ApplicationContextAware的Bean,在Bean被初始后,将会被注入ApplicationContext的实例。ApplicationContextAware提供了publishEvent()方法,实现Observer(观察者)设计模式的事件传播机,提供了针对Bean的事件传播功能。通过Application.publishEvent方法,我们可以将事件通知系统内所有的ApplicationListener。

Spring事件处理一般过程:

◆定义Event类,继承org.springframework.context.ApplicationEvent。
◆编写发布事件类Publisher,实现org.springframework.context.ApplicationContextAware接口。
◆覆盖方法setApplicationContext(ApplicationContext applicationContext)和发布方法publish(Object obj)。
◆定义时间监听类EventListener,实现ApplicationListener接口,实现方法onApplicationEvent(ApplicationEvent event)。

原文:https://blog.csdn.net/it_man/article/details/8440737 
 

 

 


事件:继承于ApplicationEvent,当然也可以不从ApplicationEvent继承,任意Object都可以作为事件发布。

事件源:事件源必须实现 ApplicationEventPublisherAware 接口,调用ApplicationEventPublisher.publishEvent()发布事件。

监听:使用@EventListener注解来标注事件处理方法,方法参数是事件对象。如果需要异步监听,则增加@Async注解。

事件类:

package com.wxy.popcorn.eventlistener.model;
 
import org.springframework.context.ApplicationEvent;
 
public class SpringEvent extends ApplicationEvent {
 
    private String name;
 
    public SpringEvent(Object source, String name) {
        super(source);
        this.name = name;
    }
 
    public String getName() {
        return name;
    }
}

事件源:

package com.wxy.popcorn.eventlistener.model;
 
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.ApplicationEventPublisherAware;
import org.springframework.stereotype.Service;
 
@Service
public class SpringEventSource implements ApplicationEventPublisherAware {
    private String name;
 
    @Autowired
    private ApplicationEventPublisher applicationEventPublisher;
 
    public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
        this.applicationEventPublisher = applicationEventPublisher;
    }
 
    public void updateName(String name) {
        if(name==null && this.name==null) {
            return;
        }
        if (name==null || this.name==null || !name.equals(this.name)) {
            this.name = name;
            applicationEventPublisher.publishEvent(new SpringEvent(this, name));
        }
    }
}

监听器:

package com.wxy.popcorn.eventlistener.listener;
 
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.event.EventListener;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
 
import com.wxy.popcorn.eventlistener.model.SpringEvent;
 
@Service
public class SpringListener {
    Logger logger = LoggerFactory.getLogger(this.getClass());
 
    @EventListener
    @Async //异步监听
    public void handleEvent(SpringEvent springEvent) {
        logger.info("the name was set to {}", springEvent.getName());
    }
}

测试类:

package com.wxy.popcorn;
 
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
 
import com.wxy.popcorn.eventlistener.App;
import com.wxy.popcorn.eventlistener.model.SpringEventSource;
@RunWith(SpringRunner.class)
@SpringBootTest(classes = App.class)
public class SpringEventlistenerTest {
 
    @Autowired
    SpringEventSource springEventSource;
 
    @Test
    public void test() {
        springEventSource.updateName("popcorn");
    }
}


测试结果:
2018-01-07 19:11:37.479 [main] INFO  [SpringListener.java:18] the name was set to popcorn

转自:https://blog.csdn.net/yange1025/article/details/78996470 
 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值