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