Spring3.2.6中事件驱动模型实现原理深入源码分析
2016-03-28 19:56
1131 查看
Spring3.2.6中事件驱动模型实现原理深入源码分析
本次学习,是在新入公司熟悉项目时候开始的。因为是做页游的项目,所以涉及到gameServer做会将游戏中的业务操作日志交给logServer处理。在本次项目中是采用spring自带的事件驱动模型(Event-Listener)来完成的,所以就花时间深入spring和jdk源码好好分析了其实现原理,收获颇多,故在此记录,留做以后复习查看。什么叫事件驱动模型?
要了解什么是事件驱动模型,首先要知道下面这样几个概念,我以JDK中GUI的按钮点击做说明。
事件(Event): 用户点击按钮(Button),就会产生事件(Event)。这里就是点击事件(ClickEvent)。
事件源(EventSource):发生事件的根源(场所)就是事件源。这里按钮组件就是事件源。
事件监听器(EventListener):监听特定的事件并处理的程序。这里监听器就是点击事件的处理者。
事件分发者(EventDispatcher):将发生的事件通知相对应的事件处理者的程序。这里就是通知监听器处理事件的程序。
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源码来找到答案。
Spring是如何实现?
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来处理了。
Spring两种事件监听方式的实现示例?
1.首先,我自定义一个我们自己的事件父类IEventimport 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>
6.好了,run一下,就结束了,让我们来看下结果。
补充
总之,这次学习,由于时间比较充足,所以也特意花时间来写博客记录下来供以后复习用。当然,收获也是挺多的,包括在写博客回顾一遍也有收获。另外,这在提醒自己,以后有时间了要去看看Spring加载ApplicaitonContext的全过程,这样也会加深自己对Ioc和Aop的理解,也能更进一步的学习JDK的反射(Reflect)机制和事件驱动模型。相关文章推荐
- java 保留小数点后两位
- Spring AOP原理——Java中的动态代理机制
- RxJava学习一:初识
- JAVA学习笔记(三)
- 深入理解Java虚拟机之内存区域与内存溢出
- JAVA第三次作业
- Java 设计模式-适配器模式
- Java产生唯一的随机数
- Java Integer比较
- 简析散列和散列码
- java第三周随笔
- java源码分析之ArrayList
- JavaWeb学习笔记——XML简介
- SPRING的事务传播特性
- spring websocket源码分析
- Eclipse导入工程中文乱码问题
- java第三次作业 io流
- Java千百问_03基本语法(004)_java中的运算符都有哪些
- javac编译成功,用java运行class文件出现“找不到或无法加载主类” 的问题
- spring mvc 的@ResponseBody与@JsonIgnore实现json传值