该框架的设计基于IOC思想。关于IOC,具体可见:http://www.csufox.com/spring-ioc.html

不过该框架实现的不是属性注入,而是将触发器-监听器-执行器的绑定由配置文件配置,框架底层实现,实现了控制反转。

该框架取名为XMLEventHandler,意为基于XML文件配置Java事件的处理器。

技术基础:

1. Java对XML文件的读取。XML是一种标记语言,用于各种配置文件和不同语言间交换信息,它只负责信息的存储,而不负责信息的表达(HTML语言是XML的衍化语言,负责网页信息的表达)。本框架采用jdk1.6自带的 org.w3c.dom 包来解析XML文档。具体可见:http:///Java_Docs/html/zh_CN/api/index.html

2. Java反射机制(reflection)。反射机制用于运行中动态地实例化任意类或者调用该类的任意方法。不管网上将反射机制说得多复杂,言简意赅的一句解释就是:Java加载类的路径(字符串),通过无参构造函数来实例化目标对象,或通过方法名调用目标方法(传入参数数组)。概括为四句代码:

 

Object targetClass = Class.forName(classPath).newInstance(); //通过类的路径名来实例化对象
Class<?> cla = targetClass.getClass();    //<>是泛型设计,这里可用通配符?表示
Method m = cla.getMethod(targetMethod,new Class[]{});  //传入方法名和参数类型数组
m.invoke(targetClass, new Object[]{});   //方法执行,传入目标类的实例和参数数组

配置文件命名为:event-config.xml,意为事件配置文件。

event-config.xml 文件初步设计如下:

<?xml version="1.0" encoding="UTF-8"?>
<beans>
    <bean id="frame" class="demo.FrameDemo2">
        <component name="calculate">
            <event type="ActionListener" class="event.OnClick" method="onClick"></event>
        </component>
    </bean>
</beans>

XML文件与属性文件不同,属性文件一般是一一映射关系,而XML文件则是一对多的映射关系,本质是树结构。

配置文件解释如下

  • 根节点为beans
  • bean节点的id属性用来唯一地标识一个bean容器(Frame),class属性用来唯一地确定bean所在类的路径。
  • component节点的name属性表示为容器内的组件名,“calculate”是一个button名。
  • event节点的type属性表示监听器的类型,class表示事件执行器的完整路径,method表示执行器的方法名。

结构如下:(只包含前三个包,demo包用于测试,event包用于定义远程事件执行方法)

  • 下面开始框架的详细代码实现:    
    XMLReader.java
    作用:用于对xml文件进行处理,以及实例化bean容器,比如Frame,Panel,Window。
package com.csufox.util;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;

import com.csufox.event.BeanFactory;
import com.sun.org.apache.xerces.internal.parsers.DOMParser;

public class XMLReader {
    private Element rootNode;
    public XMLReader(String fileName){
        DOMParser parse = new DOMParser();
        try {
            parse.parse(fileName);
        } catch (Exception e) {
            e.printStackTrace();
        }
        Document doc = parse.getDocument();   //预处理xml文件,转换为doc文档类
        rootNode = doc.getDocumentElement();
    }
    public Object getBean(String id){   //得到指定容器的实例
        Object obj = null;
        NodeList beanNodeList = rootNode.getElementsByTagName("bean");
        for(int i=0;i<beanNodeList.getLength();i++) {
            Element beanNode = (Element) beanNodeList.item(i);
            if(beanNode.getAttribute("id").equals(id)){
                obj = BeanFactory.create(beanNode);
            }
        }
        return obj;
    }
}


BeanFactory.java

作用:bean工厂,利用简单工厂模式,传入不同的参数来得到不同的bean容器,初始化的工作交由工厂处理。

package com.csufox.event;

import java.beans.Expression;

import org.w3c.dom.Element;
import org.w3c.dom.NodeList;

public class BeanFactory {
    public static Object create(Element beanNode){ //工厂静态方法
        Object bean = null;
        try {
            bean = Class.forName(beanNode.getAttribute("class")).newInstance();
            NodeList componentNodeList = beanNode.getElementsByTagName("component");
            for(int i=0;i<componentNodeList.getLength();i++){
                Element componentNode = (Element)componentNodeList.item(i);
                String componentName = componentNode.getAttribute("name");

                String firstChar = componentName.charAt(0) + "";
                String newFirstChar = firstChar.toUpperCase();
                String methodName = "get" + componentName.replaceFirst(firstChar, newFirstChar);               //得到get函数,进而得到容器内的组件,如Button

                Expression e=new Expression(bean,methodName,null);
                e.execute();
                Object component = e.getValue(); //Expression用于执行给定类中的指定方法,并得到返回值。这是Java反射机制的一种替代方案,执行效率更高。

                NodeList eventNodeList = componentNode.getElementsByTagName("event");
                for(int j=0;j<eventNodeList.getLength();j++){
                    Element eventNode = (Element)eventNodeList.item(j);
                    EventHandler.handle(bean,component,eventNode);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return bean;
    }
}

EventHandler.java

作用:事件处理器,用于将容器内的组件添加事件监听器。

package com.csufox.event;

import java.lang.reflect.Method;

import org.w3c.dom.Element;

import com.csufox.listener.SingletonActionListener;

public class EventHandler{
    private static SingletonActionListener listener = null;

    public static void handle(Object bean,Object component,Element eventNode){
        String listenerType = eventNode.getAttribute("type");
        if(listenerType.equals("ActionListener")){
            listener = SingletonActionListener.getInstance(bean,component,eventNode);
        }
        Class<?> componentClass = component.getClass();
        String addListener = "add" + listenerType;   //得到添加事件监听器的方法名
        try {
            Class<?> name = Class.forName("java.awt.event."+listenerType);
            Method method = componentClass.getMethod(addListener,name);
            method.invoke(component,listener);  //反射机制执行方法,可用Statement类替代
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}