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);
}