java事件模型

java事件模型

一. java事件机制

java中的事件机制的参与者有3种角色

1. Event Eource:

具体的事件源,比如说,你点击一个button,那么button就是event source,要想使button对某些事件进行响应,你就需要注册特定的listener。

2. Event Object:

事件状态对象,用于 listener 的相应的方法之中,作为参数,一般存在于listerner 的方法之中

3. Event Listener:

当它监听到event object产生的时候,它就调用相应的方法,进行处理。

4. 事件环境

在这个环境中,可以添加事件监听器,可以产生事件,可以触发事件监听器。例如java对象,或者spring的AbstractApplicationContext

二. JDK提供的Event模型:

1. Source:

产生Event事件的对象,产生事件的根源。

2. EventObject

所有事件对象都应该继承EventObject

package java.util;

import java.io.Serializable;

public class EventObject implements Serializable {
    private static final long serialVersionUID = 5516075349620653480L;
    protected transient Object source;

    public EventObject(Object var1) {
        if(var1 == null) {
            throw new IllegalArgumentException("null source");
        } else {
            this.source = var1;
        }
    }

    public Object getSource() {
        return this.source;
    }

    public String toString() {
        return this.getClass().getName() + "[source=" + this.source + "]";
    }
}
3. EventListener:

所有事件侦听器接口必须扩展的标记接口。

package java.util;

public interface EventListener {
}
4. java 事件模型举例

用户在网站注册,系统会发送邮件进行验证

1) 用户对象
public class User {

    private String username;

    private String password;

    private String email;

    public User(String username, String password, String email) {
        this.username = username;
        this.password = password;
        this.email = email;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }
}
2) UserEvent
  • 用户事件对象,继承JDK EventObject对象
public class UserEvent extends EventObject {

    public UserEvent(Object source){
        super(source);
    }
}
  • 具体事件
public class SendEmailEvent extends UserEvent {

    public SendEmailEvent(Object source) {
        super(source);
    }
}
3)UserListener
  • 用户事件监听器接口,继承自JDK EventListener
public interface UserListener extends EventListener{

    public void onRegister(UserEvent event);

}
  • 具体实现
public class SendEmailListener implements UserListener {

    @Override
    public void onRegister(UserEvent event) {

        if (event instanceof SendEmailEvent) {

            Object source = event.getSource();

            User user = (User) source;

            System.out.println("send email to " + user.getEmail());
        }
    }
}
4) UserService

上下文环境,注册监听器,当用户注册的时候,触发事件

public class UserService {

    private List<UserListener> listeneres = new ArrayList<UserListener>();

    //当用户注册的时候,触发发送邮件事件
    public void register(User user){

        System.out.println("save " + user.getUsername() + " : " + user.getPassword() + " to database");

        UserEvent event = new UserEvent(user);

        publishEvent(event);

    }

    public void publishEvent(UserEvent event){

        for(UserListener listener : listeneres){
            listener.onRegister(event);
        }

    }

    public void addListeners(UserListener listener){
        this.listeneres.add(listener);
    }

}
5) 测试程序
public class Test {

    public static void main(String[] args) {

        UserService service = new UserService();

        service.addListeners(new SendEmailListener());

        //添加其他监听器 ...

        User user = new User("zhangsan", "123456", "zhangsan@huawei.com");

        service.register(user);
    }
}

输出:
save zhangsan : 123456 to database
send email to zhangsan@huawei.com

三. Spring事件机制

1. 事件对象

所有的事件对象都要继承自java的EventObject。Spring中所有的事件父接口为ApplicationEvent

package org.springframework.context;

import java.util.EventObject;

public abstract class ApplicationEvent extends EventObject {

    private static final long serialVersionUID = 7099057708183571937L;

    private final long timestamp;

    public ApplicationEvent(Object source) {
        super(source);
        this.timestamp = System.currentTimeMillis();
    }

    public final long getTimestamp() {
        return this.timestamp;
    }

}
2. 事件监听器

所有的事件监听器都要实现java的EventListener接口,EventListener是一个标记接口。spring中
所有的事件监听器父接口为ApplicationListener,一般来说事件监听器的方法参数为事件对象。


package org.springframework.context;

import java.util.EventListener;

public interface ApplicationListener<E extends ApplicationEvent> extends EventListener {

    void onApplicationEvent(E event);

}
3. 事件环境

spring的事件环境为AbstractApplicationContext,在事件环境中,可以注册事件(addApplicationListener),触发事件(publishEvent)


public abstract class AbstractApplicationContext extends DefaultResourceLoader
        implements ConfigurableApplicationContext, DisposableBean {


    /** Helper class used in event publishing */
    private ApplicationEventMulticaster applicationEventMulticaster;

    /** Statically specified listeners */
    private final Set<ApplicationListener<?>> applicationListeners = new LinkedHashSet<ApplicationListener<?>>();

    /** ApplicationEvents published early */
    private Set<ApplicationEvent> earlyApplicationEvents;

    //触发事件
    @Override
    public void publishEvent(ApplicationEvent event) {
        publishEvent(event, null);
    }

    //触发事件
    @Override
    public void publishEvent(Object event) {
        publishEvent(event, null);
    }

    //触发事件
    protected void publishEvent(Object event, ResolvableType eventType) {
        Assert.notNull(event, "Event must not be null");
        if (logger.isTraceEnabled()) {
            logger.trace("Publishing event in " + getDisplayName() + ": " + event);
        }

        // Decorate event as an ApplicationEvent if necessary
        ApplicationEvent applicationEvent;
        if (event instanceof ApplicationEvent) {
            applicationEvent = (ApplicationEvent) event;
        }
        else {
            applicationEvent = new PayloadApplicationEvent<Object>(this, event);
            if (eventType == null) {
                eventType = ((PayloadApplicationEvent)applicationEvent).getResolvableType();
            }
        }

        // Multicast right now if possible - or lazily once the multicaster is initialized
        if (this.earlyApplicationEvents != null) {
            this.earlyApplicationEvents.add(applicationEvent);
        }
        else {
            getApplicationEventMulticaster().multicastEvent(applicationEvent, eventType);
        }

        // Publish event via parent context as well...
        if (this.parent != null) {
            if (this.parent instanceof AbstractApplicationContext) {
                ((AbstractApplicationContext) this.parent).publishEvent(event, eventType);
            }
            else {
                this.parent.publishEvent(event);
            }
        }
    }

    ApplicationEventMulticaster getApplicationEventMulticaster() throws IllegalStateException {
        if (this.applicationEventMulticaster == null) {
            throw new IllegalStateException("ApplicationEventMulticaster not initialized - " +
                    "call 'refresh' before multicasting events via the context: " + this);
        }
        return this.applicationEventMulticaster;
    }

    //添加事件监听器
    @Override
    public void addApplicationListener(ApplicationListener<?> listener) {
        Assert.notNull(listener, "ApplicationListener must not be null");
        if (this.applicationEventMulticaster != null) {
            this.applicationEventMulticaster.addApplicationListener(listener);
        }
        else {
            this.applicationListeners.add(listener);
        }
    }

    //注册事件监听器
    protected void registerListeners() {
        // Register statically specified listeners first.
        for (ApplicationListener<?> listener : getApplicationListeners()) {
            getApplicationEventMulticaster().addApplicationListener(listener);
        }

        // Do not initialize FactoryBeans here: We need to leave all regular beans
        // uninitialized to let post-processors apply to them!
        String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false);
        for (String listenerBeanName : listenerBeanNames) {
            getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);
        }

        // Publish early application events now that we finally have a multicaster...
        Set<ApplicationEvent> earlyEventsToProcess = this.earlyApplicationEvents;
        this.earlyApplicationEvents = null;
        if (earlyEventsToProcess != null) {
            for (ApplicationEvent earlyEvent : earlyEventsToProcess) {
                getApplicationEventMulticaster().multicastEvent(earlyEvent);
            }
        }
    }

    //刷新ApplicationContext的时候触发ContextStartedEvent
    protected void finishRefresh() {
        // Initialize lifecycle processor for this context.
        initLifecycleProcessor();

        // Propagate refresh to lifecycle processor first.
        getLifecycleProcessor().onRefresh();

        // Publish the final event.
        publishEvent(new ContextRefreshedEvent(this));

        // Participate in LiveBeansView MBean, if active.
        LiveBeansView.registerApplicationContext(this);
    }

    //启动时触发ContextStartedEvent
    @Override
    public void start() {
        getLifecycleProcessor().start();
        publishEvent(new ContextStartedEvent(this));
    }

    //关闭时触发ContextStartedEvent
    @Override
    public void stop() {
        getLifecycleProcessor().stop();
        publishEvent(new ContextStoppedEvent(this));
    }

}
4. Spring事件样例

sping容器启动的时候,会自动扫描所有实现applicationListener接口的类,并注册到容器中,
当特定事件发生时,会调用相应事件的监听器。

1)refresh

spring 容器启动的时候会调用AbstractApplicationContext的refresh方法,其中有一步为registerListeners()

@Override
    public void refresh() throws BeansException, IllegalStateException {
        synchronized (this.startupShutdownMonitor) {
            // Prepare this context for refreshing.
            prepareRefresh();

            // Tell the subclass to refresh the internal bean factory.
            ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

            // Prepare the bean factory for use in this context.
            prepareBeanFactory(beanFactory);

            try {
                // Allows post-processing of the bean factory in context subclasses.
                postProcessBeanFactory(beanFactory);

                // Invoke factory processors registered as beans in the context.
                invokeBeanFactoryPostProcessors(beanFactory);

                // Register bean processors that intercept bean creation.
                registerBeanPostProcessors(beanFactory);

                // Initialize message source for this context.
                initMessageSource();

                // Initialize event multicaster for this context.
                initApplicationEventMulticaster();

                // Initialize other special beans in specific context subclasses.
                onRefresh();

                //查找并注册监听器
                // Check for listener beans and register them.
                registerListeners();

                // Instantiate all remaining (non-lazy-init) singletons.
                finishBeanFactoryInitialization(beanFactory);

                //完成刷新,会触发相应事件
                // Last step: publish corresponding event.
                finishRefresh();
            }

            catch (BeansException ex) {
                if (logger.isWarnEnabled()) {
                    logger.warn("Exception encountered during context initialization - " +
                            "cancelling refresh attempt: " + ex);
                }

                // Destroy already created singletons to avoid dangling resources.
                destroyBeans();

                // Reset 'active' flag.
                cancelRefresh(ex);

                // Propagate exception to caller.
                throw ex;
            }

            finally {
                // Reset common introspection caches in Spring's core, since we
                // might not ever need metadata for singleton beans anymore...
                resetCommonCaches();
            }
        }
    }
2) registerListeners

可以看到,在registerListeners();方法中将所有实现了ApplicationListener的类添加到了监听器集合中。

protected void registerListeners() {
        // Register statically specified listeners first.
        for (ApplicationListener<?> listener : getApplicationListeners()) {
            getApplicationEventMulticaster().addApplicationListener(listener);
        }

        // Do not initialize FactoryBeans here: We need to leave all regular beans
        // uninitialized to let post-processors apply to them!

        //查找所有ApplicationListener
        String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false);
        for (String listenerBeanName : listenerBeanNames) {
            getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);
        }

        // Publish early application events now that we finally have a multicaster...
        Set<ApplicationEvent> earlyEventsToProcess = this.earlyApplicationEvents;
        this.earlyApplicationEvents = null;
        if (earlyEventsToProcess != null) {
            for (ApplicationEvent earlyEvent : earlyEventsToProcess) {
                getApplicationEventMulticaster().multicastEvent(earlyEvent);
            }
        }
    }
3)finishRefresh

在finishRefresh方法后调用了publishEvent方法,触发了上下文更新事件。在AbstractApplicationContext类中的很多方法中都可以看到调用了publishEvent方法。

protected void finishRefresh() {
    // Initialize lifecycle processor for this context.
    initLifecycleProcessor();

    // Propagate refresh to lifecycle processor first.
    getLifecycleProcessor().onRefresh();

    //触发ContextRefreshedEvent事件
    // Publish the final event.
    publishEvent(new ContextRefreshedEvent(this));

    // Participate in LiveBeansView MBean, if active.
    LiveBeansView.registerApplicationContext(this);
}
  • 4
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值