本次学习,是在新入公司熟悉项目时候开始的。因为是做页游的项目,所以涉及到gameServer做会将游戏中的业务操作日志交给logServer处理。在本次项目中是采用spring自带的事件驱动模型(Event-Listener)来完成的,所以就花时间深入spring和jdk源码好好分析了其实现原理,收获颇多,故在此记录,留做以后复习查看。
要了解什么是事件驱动模型,首先要知道下面这样几个概念,我以JDK中GUI的按钮点击做说明。
import java.awt.Dimension;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.WindowConstants;
/** * @Description: JDK中GUI按钮的点击事件演示 * @author Yang Gao * @date 2016-3-28 上午9:48:42 * */
public class EventListenerTest {
public static void main(String[] args) {
Dimension d = Toolkit.getDefaultToolkit().getScreenSize();
//当前屏幕中心点的X坐标
final int CONTENT_X = d.width/2;
//当前屏幕中心点的Y坐标
final int CONTENT_Y = d.height/2;
//Windos窗口组件
JFrame f = new JFrame("测试窗口");
//窗口组件大小
f.setSize(300, 200);
//窗口组件位置
f.setLocation((CONTENT_X - f.getWidth()/2), (CONTENT_Y - f.getHeight()/2));
//设置大小不可改变
f.setResizable(false);
//设置可见性为可见
f.setVisible(true);
//设置默认关闭调用事件
f.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
//按钮组件,事件源
JButton btn = new JButton("点击我哟!");
//设置按钮组件的大小
btn.setSize(150, 50);
//面板添加组件
f.add(btn);
//对事件源添加事件监听器
btn.addActionListener(new MyListener());
}
}
/** * @Description: 自定义clickListenert类 * @author Yang Gao * @date 2016-3-28 上午10:17:16 * */
class MyListener implements ActionListener{
@Override
public void actionPerformed(ActionEvent e) {
JButton btn = (JButton)e.getSource();
JOptionPane.showMessageDialog(null,"我是事件监听器的处理程序,我处理的是:【" + btn.getText() + "】");
}
}
在上面的code中btn.addActionListener(new MyListener());至于jdk是如何将用户产生的click事件通知给MyListener,也就是事件发布者这个角色,这里不详细叙述,有兴趣的童鞋可以考虑跟进jdk源码来找到答案。
1.先看看所有事件Event类都要继承的父类EventObject(JDK)代码。
package java.util;
/** * <p> * The root class from which all event state objects shall be derived. * <p> * All Events are constructed with a reference to the object, the "source", * that is logically deemed to be the object upon which the Event in question * initially occurred upon. * * @since JDK1.1 */
public class EventObject implements java.io.Serializable {
private static final long serialVersionUID = 5516075349620653480L;
/** * The object on which the Event initially occurred. */
protected transient Object source;
/** * Constructs a prototypical Event. * * @param source The object on which the Event initially occurred. * @exception IllegalArgumentException if source is null. */
public EventObject(Object source) {
if (source == null)
throw new IllegalArgumentException("null source");
this.source = source;
}
/** * The object on which the Event initially occurred. * * @return The object on which the Event initially occurred. */
public Object getSource() {
return source;
}
/** * Returns a String representation of this EventObject. * * @return A a String representation of this EventObject. */
public String toString() {
return getClass().getName() + "[source=" + source + "]";
}
}
再看看Spring中继承EventObject的类,ApplicationEvent的具体代码
/* * Copyright 2002-2012 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */
package org.springframework.context;
import java.util.EventObject;
/** * Class to be extended by all application events. Abstract as it * doesn't make sense for generic events to be published directly. * * @author Rod Johnson * @author Juergen Hoeller */
public abstract class ApplicationEvent extends EventObject {
/** use serialVersionUID from Spring 1.2 for interoperability */
private static final long serialVersionUID = 7099057708183571937L;
/** System time when the event happened */
private final long timestamp;
/** * Create a new ApplicationEvent. * @param source the component that published the event (never {@code null}) */
public ApplicationEvent(Object source) {
super(source);
this.timestamp = System.currentTimeMillis();
}
/** * Return the system time in milliseconds when the event happened. */
public final long getTimestamp() {
return this.timestamp;
}
}
2.接下来,我们看看所有事件监听器Listener类都要实现的EventListener(JDK)接口。
/* * Copyright (c) 1996, 1999, Oracle and/or its affiliates. All rights reserved. * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. */
package java.util;
/** * A tagging interface that all event listener interfaces must extend. * @since JDK1.1 */
public interface EventListener {
}
那么Spring中实现了这个接口的是接口ApplicationListener< E extends ApplicationEvent > ,很明显使用的泛型,约定了其事件类型,看看具体代码。
package org.springframework.context;
import java.util.EventListener;
/** * Interface to be implemented by application event listeners. * Based on the standard {@code java.util.EventListener} interface * for the Observer design pattern. * * <p>As of Spring 3.0, an ApplicationListener can generically declare the event type * that it is interested in. When registered with a Spring ApplicationContext, events * will be filtered accordingly, with the listener getting invoked for matching event * objects only. * * @author Rod Johnson * @author Juergen Hoeller * @param <E> the specific ApplicationEvent subclass to listen to * @see org.springframework.context.event.ApplicationEventMulticaster */
public interface ApplicationListener<E extends ApplicationEvent> extends EventListener {
/** * Handle an application event. * @param event the event to respond to */
void onApplicationEvent(E event);
}
从上面可以看出,当泛型约定的事件发生时候,会调用其onApplicationEvent的实现方法处理。我们再看看spring中实现这一接口的子接口:SmartApplicationListener的具体代码。
package org.springframework.context.event;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.core.Ordered;
/** * Extended variant of the standard {@link ApplicationListener} interface, * exposing further metadata such as the supported event type. * * @author Juergen Hoeller * @since 3.0 */
public interface SmartApplicationListener extends ApplicationListener<ApplicationEvent>, Ordered {
/** * Determine whether this listener actually supports the given event type. */
boolean supportsEventType(Class<? extends ApplicationEvent> eventType);
/** * Determine whether this listener actually supports the given source type. */
boolean supportsSourceType(Class<?> sourceType);
}
从上面的代码上可以看出,这个子接口添加了更为具体的类型判断,supportsEventType表示仅支持对应的事件类型,supportsSourceType表示仅支持对应的事件类型(这里就对应EventObject类中被transient瞬态修饰符的变量Object source)。
3.最后我们再看看最核心的东东,就是事件分发器(EventDispatcher)。Spring中使用接口ApplicationEventPublisher和接口ApplicationEventMulticaster来共同完成,首先我们来看一下两个接口定义的通用方法有哪些?
package org.springframework.context;
public interface ApplicationEventPublisher {
/** * Notify all listeners registered with this application of an application * event. Events may be framework events (such as RequestHandledEvent) * or application-specific events. * @param event the event to publish * @see org.springframework.web.context.support.RequestHandledEvent */
void publishEvent(ApplicationEvent event);
}
package org.springframework.context.event;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationListener;
public interface ApplicationEventMulticaster {
/** * Add a listener to be notified of all events. * @param listener the listener to add */
void addApplicationListener(ApplicationListener listener);
/** * Add a listener bean to be notified of all events. * @param listenerBeanName the name of the listener bean to add */
void addApplicationListenerBean(String listenerBeanName);
/** * Remove a listener from the notification list. * @param listener the listener to remove */
void removeApplicationListener(ApplicationListener listener);
/** * Remove a listener bean from the notification list. * @param listenerBeanName the name of the listener bean to add */
void removeApplicationListenerBean(String listenerBeanName);
/** * Remove all listeners registered with this multicaster. * <p>After a remove call, the multicaster will perform no action * on event notification until new listeners are being registered. */
void removeAllListeners();
/** * Multicast the given application event to appropriate listeners. * @param event the event to multicast */
void multicastEvent(ApplicationEvent event);
}
从上面可以很清楚的看出,其中ApplicationEventPublisher 接口主要负责将事件发布,ApplicationEventMulticaster 接口主要负责事件通知(回调)。Spring中ApplicationContext接口实现了ApplicationEventPublisher 接口,具体实现类是AbstractApplicationContext,让我们看看源代码中对publishEvent实现的具体代码。
/** * Publish the given event to all listeners. * <p>Note: Listeners get initialized after the MessageSource, to be able * to access it within listener implementations. Thus, MessageSource * implementations cannot publish events. * @param event the event to publish (may be application-specific or a * standard framework event) */
public void publishEvent(ApplicationEvent event) {
Assert.notNull(event, "Event must not be null");
if (logger.isTraceEnabled()) {
logger.trace("Publishing event in " + getDisplayName() + ": " + event);
}
getApplicationEventMulticaster().multicastEvent(event);
if (this.parent != null) {
this.parent.publishEvent(event);
}
}
/** * Return the internal ApplicationEventMulticaster used by the context. * @return the internal ApplicationEventMulticaster (never {@code null}) * @throws IllegalStateException if the context has not been initialized yet */
private 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;
}
大家应该发现了,就和我画的图一样,具体实现的是接口ApplicationEventMulticaster 。那么ApplicationEventMulticaster 接口的具体实现代码是什么呢?我们接着跟进,看看实现ApplicationEventMulticaster 接口中multicastEvent方法的具体类SimpleApplicationEventMulticaster的源代码。
package org.springframework.context.event;
import java.util.concurrent.Executor;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationListener;
public class SimpleApplicationEventMulticaster extends AbstractApplicationEventMulticaster {
private Executor taskExecutor;
/** * Create a new SimpleApplicationEventMulticaster. */
public SimpleApplicationEventMulticaster() {
}
/** * Create a new SimpleApplicationEventMulticaster for the given BeanFactory. */
public SimpleApplicationEventMulticaster(BeanFactory beanFactory) {
setBeanFactory(beanFactory);
}
/** * Set the TaskExecutor to execute application listeners with. * <p>Default is a SyncTaskExecutor, executing the listeners synchronously * in the calling thread. * <p>Consider specifying an asynchronous TaskExecutor here to not block the * caller until all listeners have been executed. However, note that asynchronous * execution will not participate in the caller's thread context (class loader, * transaction association) unless the TaskExecutor explicitly supports this. * @see org.springframework.core.task.SyncTaskExecutor * @see org.springframework.core.task.SimpleAsyncTaskExecutor */
public void setTaskExecutor(Executor taskExecutor) {
this.taskExecutor = taskExecutor;
}
/** * Return the current TaskExecutor for this multicaster. */
protected Executor getTaskExecutor() {
return this.taskExecutor;
}
@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);
}
}
}
}
问题的关键到了,就是这个方法getApplicationListeners(final ApplicationEvent event),从方法的定义上就不难看出,这个方法是根据事件得到其所有监听器的集合。让我们继续跟进AbstractApplicationEventMulticaster类中的getApplicationListeners这个方法查看里面的奥秘。
/**
* Return a Collection of ApplicationListeners matching the given
* event type. Non-matching listeners get excluded early.
* @param event the event to be propagated. Allows for excluding
* non-matching listeners early, based on cached matching information.
* @return a Collection of ApplicationListeners
* @see org.springframework.context.ApplicationListener
*/
protected Collection<ApplicationListener> getApplicationListeners(ApplicationEvent event) {
// 事件字节码(这里我们就是zhangsanEvent和WangwuEvent两个事件)
Class<? extends ApplicationEvent> eventType = event.getClass();
// 事件源信息的字节码(这里就是我们定义的两个事件的区别:eventName构造方法里面的source)
Object source = event.getSource();
Class<?> sourceType = (source != null ? source.getClass() : null);
// ListenerCacheKey 保存上面的两个字节码信息
ListenerCacheKey cacheKey = new ListenerCacheKey(eventType, sourceType);
// Map<ListenerCacheKey, ListenerRetriever> retrieverCache将匹配过的事件与监听器对应关系保存在内种中作为缓存
ListenerRetriever retriever = this.retrieverCache.get(cacheKey);// 这里是从内存的缓存中查找
if (retriever != null) {
return retriever.getApplicationListeners();
}
else {
// 第一次没有找到,就自己new一个ListenerRetriever来保存返回数据
retriever = new ListenerRetriever(true);
LinkedList<ApplicationListener> allListeners = new LinkedList<ApplicationListener>();
Set<ApplicationListener> listeners;
Set<String> listenerBeans;
/**
* defaultRetriever默认监听器
* 在applicationContext容器初始化的时候就已经保存了
* 所有实现ApplicationListener或SmartApplicationListener接口listeners
* /
synchronized (this.defaultRetriever) {
listeners = new LinkedHashSet<ApplicationListener>(this.defaultRetriever.applicationListeners);
listenerBeans = new LinkedHashSet<String>(this.defaultRetriever.applicationListenerBeans);
}
//遍历所有实现了ApplicationListener或SmartApplicationListener接口listeners
for (ApplicationListener listener : listeners) {
//supportsEvent(根据eventType和source,从listeners中筛选出符合条件的listener)
if (supportsEvent(listener, eventType, sourceType)) {
retriever.applicationListeners.add(listener);
allListeners.add(listener);
}
}
if (!listenerBeans.isEmpty()) {
BeanFactory beanFactory = getBeanFactory();
for (String listenerBeanName : listenerBeans) {
ApplicationListener listener = beanFactory.getBean(listenerBeanName, ApplicationListener.class);
if (!allListeners.contains(listener) && supportsEvent(listener, eventType, sourceType)) {
retriever.applicationListenerBeans.add(listenerBeanName);
allListeners.add(listener);
}
}
}
OrderComparator.sort(allListeners);
this.retrieverCache.put(cacheKey, retriever);
return allListeners;
}
}
在上面代码中有一个狠重要的方法supportsEvent,这个方法我说过是SmartApplicationListener接口定义的。这里如果用户自定义listener是直接实现该接口,那么这里就会调用用户自己的现实类;否则就会调用spring默认的,具体我们看抽象类AbstractApplicationEventMulticaster中supportsEvent方法的源代码说话。
/**
* Determine whether the given listener supports the given event.
* <p>The default implementation detects the {@link SmartApplicationListener}
* interface. In case of a standard {@link ApplicationListener}, a
* {@link GenericApplicationListenerAdapter} will be used to introspect
* the generically declared type of the target listener.
* @param listener the target listener to check
* @param eventType the event type to check against
* @param sourceType the source type to check against
* @return whether the given listener should be included in the
* candidates for the given event type
*/
protected boolean supportsEvent(
ApplicationListener listener, Class<? extends ApplicationEvent> eventType, Class sourceType) {
/**
* 从这行代码可以看出来,如果传进来的listener实现SmartApplicationListener的类,
* 那么就会调用其实现类的supportsEventType和supportsSourceType方法;
* 否则就会调用GenericApplicationListenerAdapter的supportsEventType和supportsSourceType方法
* /
SmartApplicationListener smartListener = (listener instanceof SmartApplicationListener ?
(SmartApplicationListener) listener : new GenericApplicationListenerAdapter(listener));
return (smartListener.supportsEventType(eventType) && smartListener.supportsSourceType(sourceType));
}
好,我们接着跟进查看Spring自己实现SmartApplicationListener接口的类GenericApplicationListenerAdapter,它的源代码。
package org.springframework.context.event;
import org.springframework.aop.support.AopUtils;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.core.GenericTypeResolver;
import org.springframework.core.Ordered;
import org.springframework.util.Assert;
public class GenericApplicationListenerAdapter implements SmartApplicationListener {
private final ApplicationListener delegate;
public GenericApplicationListenerAdapter(ApplicationListener delegate) {
Assert.notNull(delegate, "Delegate listener must not be null");
this.delegate = delegate;
}
@SuppressWarnings("unchecked")
public void onApplicationEvent(ApplicationEvent event) {
this.delegate.onApplicationEvent(event);
}
// 这里是仅支持事件调用方法的实现
public boolean supportsEventType(Class<? extends ApplicationEvent> eventType) {
//这里是获取listener中泛型定义的ApplicationEvent中指定delegate的字节码信息
Class<?> typeArg = GenericTypeResolver.resolveTypeArgument(this.delegate.getClass(), ApplicationListener.class);
// 判断是否是ApplicationEvent类
if (typeArg == null || typeArg.equals(ApplicationEvent.class)) {
// 获取指定类继承的父类
Class<?> targetClass = AopUtils.getTargetClass(this.delegate);
if (targetClass != this.delegate.getClass()) {
// 这里是获取listener中泛型定义的ApplicationEvent中指定targetClass的字节码信息
typeArg = GenericTypeResolver.resolveTypeArgument(targetClass, ApplicationListener.class);
}
}
/** * isAssignableFrom用来判断一个类Class1和另一个类Class2是否相同 * 或者一个类class1是另一个类class2的超类或接口 * 注意调用顺序是class1.isAssignableFrom(class2) */
// null 表示没有泛型为任意类型
return (typeArg == null || typeArg.isAssignableFrom(eventType));
}
// 这里是仅支持事件源信息调用方法的实现
public boolean supportsSourceType(Class<?> sourceType) {
return true;
}
public int getOrder() {
return (this.delegate instanceof Ordered ? ((Ordered) this.delegate).getOrder() : Ordered.LOWEST_PRECEDENCE);
}
}
好了,到了这里大家基本也都知道这份分发器原理了,这里说的主要是通过supportsEventType和supportsSourceType这两个方法,来判断什么样的ApplicationEvent用什么样的ApplicationListener来处理了。
1.首先,我自定义一个我们自己的事件父类IEvent
import org.springframework.context.ApplicationEvent;
/** * @Description: 自定义事件父类,根据事件名称区别 * @author Yang Gao * @date 2016-3-25 下午4:36:20 * */
public class IEvent extends ApplicationEvent {
private static final long serialVersionUID = -1130255953722074726L;
private String eventName;
public IEvent(String eventName) {
super(eventName);
this.eventName = eventName;
}
public String getEventName() {
return eventName;
}
}
2.然后在再定义两个不同的事件类,ZhangsanEvent和WangwuEvent
package com.gy.event;
/** * @author Yang Gao * @date 2016-3-25 下午4:44:57 * */
public class ZhangsanEvent extends IEvent {
private static final long serialVersionUID = 4328148476272415442L;
public ZhangsanEvent(String source) {
super(source);
}
}
package com.gy.event;
/** * @author Yang Gao * @date 2016-3-25 下午4:44:57 * */
public class WangwuEvent extends IEvent {
private static final long serialVersionUID = 4328148476272415442L;
public WangwuEvent(String source) {
super(source);
}
}
好了,我们来看一下具体的继承关系。
3.然后我们在定义自己的Listenter,这里我使用Spring的两种实现方式
package com.gy.listener;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.event.SmartApplicationListener;
import org.springframework.stereotype.Component;
import com.gy.event.ZhangsanEvent;
/** * @Description: 使用实现间接实现ApplicationListener的子接口SmartApplicationListener方式 * @author Yang Gao * @date 2016-3-25 下午4:42:26 * */
public class ZhangsanListener implements SmartApplicationListener {
@Override
public void onApplicationEvent(ApplicationEvent event) {
ZhangsanEvent _event = (ZhangsanEvent)event;
System.out.println("ZhangsanListener Handle Event Name is " + _event.getEventName());
}
@Override
public int getOrder() {
return 0;
}
/* * 决定监听器处理支持的事件类型 */
@Override
public boolean supportsEventType(Class<? extends ApplicationEvent> eventType) {
return ZhangsanEvent.class.isAssignableFrom(eventType);
}
/* * 决定监听器处理支持的事件源类型 */
@Override
public boolean supportsSourceType(Class<?> sourceType) {
return Object.class.isAssignableFrom(sourceType);
}
}
package com.gy.listener;
import org.springframework.context.ApplicationListener;
import org.springframework.stereotype.Component;
import com.gy.event.WangwuEvent;
/** * @Description: 使用直接实现ApplicationListener方式,泛型指定监听的具体事件类型 * @author Yang Gao * @date 2016-3-25 下午4:43:56 * */
public class WangwuListener implements ApplicationListener<WangwuEvent> {
@Override
public void onApplicationEvent(WangwuEvent event) {
System.out.println("WangwuListener Handle Event Name is " + event.getEventName());
}
}
4.然后咱在弄一个测试类SpringEventListenerTest
package com.gy.test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.stereotype.Component;
import com.gy.event.WangwuEvent;
import com.gy.event.ZhangsanEvent;
/** * @Description: 测试类 * @author Yang Gao * @date 2016-3-25 下午4:35:30 * */
public class SpringEventListenerTest {
public static void main(String[] args) {
ApplicationContext springContext = new ClassPathXmlApplicationContext("applicationContext.xml");
ZhangsanEvent zsEvent = new ZhangsanEvent("张三");
WangwuEvent wwEvent = new WangwuEvent("王五");
springContext.publishEvent(zsEvent);
springContext.publishEvent(wwEvent);
}
}
5.最后简单的applicationContext.xml配置文件,当然至于spring3.2.6的jar包,大家都自己动手去网上下载啦,我就不粘了。
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:util="http://www.springframework.org/schema/util">
<bean id="zhangsanListener" class="com.gy.listener.ZhangsanListener"/>
<bean id="wangwuListener" class="com.gy.listener.WangwuListener"/>
</beans>
总之,这次学习,由于时间比较充足,所以也特意花时间来写博客记录下来供以后复习用。当然,收获也是挺多的,包括在写博客回顾一遍也有收获。另外,这在提醒自己,以后有时间了要去看看Spring加载ApplicaitonContext的全过程,这样也会加深自己对Ioc和Aop的理解,也能更进一步的学习JDK的反射(Reflect)机制和事件驱动模型。