您的位置:首页 > 编程语言

自行打造实现控制反转容器(IOC)与面向方面编程(AOP)的轻量级Framework(2)

2008-09-01 19:34 597 查看
MyFrameworkIoC部分

作者:牛超
Email/MSN:ncfire_msn@hotmail.com
QQ: 10867910

关键字(Keywords):面向对象(OOP)、框架(Framework)、反射(Reflection)、设计模式(Design Pattern)、扩展标识语言(XML)、依赖注入(Dependency Injection)、控制反转容器(IoC)、横切点(Pointcut)、面向方面编程(AOP)

使用桥接模式定义对象工厂,它只有一个行为,获取一个指定对象,即依照参数传递的名字从XML定义中组装一个与之匹配的规格对象。此构建方法的实现为整个框架的核心。
package myFramework;
public interface IBeansFactory {
public Object getObject(String aObjName);
4000

}
接下来是代理对象工厂,即装备加载工厂,使用代理模式构造对象。目标要实现两个行为,即分别通过设置装备和安装拦截器创建代理对象以供前面的对象工厂所使用。
package myFramework;
public interface IProxyBeansFactory
{
public Object createProxyObject(Object proxy, IAdvice[] advices);
public Object createProxyObject(Object proxy, IProxyInterfaceHandler pohandle);
}
对XML文件操作采用JAVA DOM库,XML文档对象的获取功能也比较单一,直接使用单件模式封装在类XMLCommon中,如下代码:
package myFramework ;

import java.io.File;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;

import org.w3c.dom.Document;
public class XMLCommon
{
private static XMLCommon xmlCmnObj ;
private static String resourceFileName;
private Document document;
private XMLCommon()
{
try
{
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder=factory.newDocumentBuilder();
document=builder.parse(new File(getResourceFileName()));
document.normalize();
}
catch(Exception ex)
{
ex.printStackTrace() ;
}
}
//get the singleton instance 获取单件对象
public static XMLCommon getInstance()
{
if (xmlCmnObj == null)
{
xmlCmnObj = new XMLCommon() ;
}
return xmlCmnObj ;
}
//get the filename of xml resource 获取资源文件名
public static String getResourceFileName()
{
if (resourceFileName == null)
resourceFileName = "./entities.xml" ;
return resourceFileName ;
}
//set the filename of xml resource 设置资源文件名
public static void setResourceFileName(String fname)
{
resourceFileName = fname ;
}
//获取XML文档类,用于读取XML文件中的内容
public Document getDocument()
{
return document ;
}
}
本Framework的实现所依赖的基础理论是OOP重要特性——反射机制,因此如何利用反射和自省来创建、克隆对象并动态调用相关方法就显得尤为重要,所以封装一个反射工具包,整个Framework也就完成了一半,这里亦用单件模式来定义反射工具对象。
package myFramework ;
import java.lang.reflect.*;
import java.util.*;
public class Reflection
{
//singleton instance 单件实例对象
private static Reflection reflect = new Reflection() ;
public static Reflection getInstance()
{
return reflect ;
}

/**
* get the public property of one object 获取一个对象的公共属性值
*
* @param owner, fieldName
* @return object
* @throws Exception
*
*/
public Object getProperty(Object owner, String fieldName) throws Exception {
Class ownerClass = owner.getClass();

Field field = ownerClass.getField(fieldName);

Object property = field.get(owner);

return property;
}

/**
* get the static property in public 获取公共静态属性
*
* @param className
* @param fieldName
* @return object
* @throws Exception
*/
public Object getStaticProperty(String className, String fieldName)
throws Exception {
Class ownerClass = Class.forName(className);

Field field = ownerClass.getField(fieldName);

Object property = field.get(ownerClass);

return property;
}

/**
* whether the two parameter list is matched 判断参数列表2是否与列表1兼容
*
* @param para. of be defined
* @param para. of be invoked
* @return result
*/
private boolean matchParameter(Class[] paradef , Class[] paraIvk)
{
boolean ret = false;
if (paradef.length != paraIvk.length)
return false ;

for (int j = 0 ; j < paraIvk.length && !ret ; j ++)
{
if (paradef[j] == null)
continue ;

if (! paradef[j].isAssignableFrom(paraIvk[j]))
{
ret = false ;
break ;
}
else
{
ret = true ;
}
}
return ret ;
}
/**
* invoke a method 调用一个方法
*
* @param owner
* @param methodName
* @param args
* @return the return object of the method
* @throws Exception
*/
public Object invokeMethod(Object owner, String methodName, Object[] args)
throws Exception
{
Method method = null;
Class ownerClass = owner.getClass();
Class[] argsClass = new Class[args.length];
boolean bmatchok = false ;

//fetch the class from parameters of the method being invoked. 读取当前调用方法的参数CLASS
for (int i = 0; i < args.length; i++)
{
if (args[i] != null)
{
argsClass[i] = args[i].getClass();
}
}
try
{
//get the method object according to parameters 根据参数匹配获得正确的方法对象
method = ownerClass.getMethod(methodName, argsClass);
bmatchok = (method != null) ;
}
catch(Exception ex)
{
//to get the method list through introspection 通过自省以获取正确的方法调用实例
Method[] methods = ownerClass.getMethods() ;
Method mdcur ;
//match the method manually 手动匹配方法
for ( int i = 0 ; i < methods.length ; i ++)
{
mdcur = methods[i] ;
if (methods[i].getName().equals(methodName))
{
Class[] paraClass = mdcur.getParameterTypes() ;
if (matchParameter(paraClass , argsClass))
{
method = mdcur ;
break ;
}
}
}

}
//reflect to invoke the method
return method.invoke(owner, args);
}

/**
* get the type of argument in a setter method 获取一个设置子的类型
*
* @param owner
* @param methodName
* @return the class of argument
* @throws Exception
*/
public Class getArgTypeOfSetter(Object owner, String methodName)
throws Exception
{
Class ownerClass = owner.getClass();
Method[] methods = ownerClass.getMethods();
for (int i = 0 ; i < methods.length ; i++)
{
if (methods[i].getName().equals(methodName))
return methods[i].getParameterTypes()[0];
}
return null ;
}

/**
* invoke a static method 调用一个静态方法
*
* @param className
* @param methodName
* @param args
* @return the return object
* @throws Exception
*/
public Object invokeStaticMethod(String className, String methodName,
Object[] args) throws Exception
{
Class ownerClass = Class.forName(className);

Class[] argsClass = new Class[args.length];

for (int i = 0, j = args.length; i < j; i++) {
argsClass[i] = args[i].getClass();
}

Method method = ownerClass.getMethod(methodName, argsClass);

return method.invoke(null, args);
}

/**
* to create a instance dynamicly 动态创建一个对象
*
* @param className
* @param args
* @return the instance be created
* @throws Exception
*/
public Object newInstance(String className, Object[] args) throws Exception
{
Class newoneClass = Class.forName(className);

Class[] argsClass = new Class[args.length];

for (int i = 0 ;i < args.length; i++) {
argsClass[i] = args[i].getClass();
}
//get the constructor can be matched 匹配正确的构造子
Constructor con ;
try
{
con = newoneClass.getConstructor(argsClass);
}
catch (Exception ex)
{
con = null ;
}
if (con == null)
{
//to scan which can be matched manually from constructors 手动匹配构造子
Constructor[] cons= newoneClass.getConstructors() ;
for ( int j = 0 ; j < cons.length ; j++)
{
//get the parameter type list
Class[] cls = cons[j].getParameterTypes() ;
if (matchParameter(cls , argsClass))
{
con = cons[j] ;
break ;
}

}
if (con == null)
{
System.err.println("error: can't match the constructor") ;
return null ;
}
}
return con.newInstance(args);
}

/**
* to create a instance dynamicly without argument 创建一个对象调用其类的无参构造子
*
* @param className
* @return the instance be created
* @throws Exception
*/
public Object newInstance(String className) throws Exception
{
Class newoneClass = Class.forName(className);
Constructor cons = newoneClass.getConstructor();
return cons.newInstance();
}

/**
* to adjust whether the object is an proxy object 判断一个对象是否是代理对象
*
* @target object
*/
public boolean isProxyObject(Object obj)
{
return Proxy.isProxyClass(obj.getClass()) ;
}
/**
* to adjust whether the two types is matched 判断两个CLASS是否匹配
* @param obj
* @param cls
* @return the result
*/
public boolean isAssignable(Class cl, Class cr)
{
return cl.isAssignableFrom(cr) ;
}
/**
* to adjust whether the two types is matched 判断两个CLASS是否匹配

* @param obj
* @param cls
* @return the result
*/
public boolean isAssignable(String cl, Class cr)
{
boolean bret = false;
try
{
bret = Class.forName(cl).isAssignableFrom(cr) ;
}
catch(ClassNotFoundException ex)
{}
return bret ;
}
/**
* to adjust whether the two types is matched 判断两个CLASS是否匹配
* @param obj
* @param cls
* @return the result
*/
public boolean isAssignable(String cl, String cr)
{
boolean bret = false;
try
{
bret = Class.forName(cl).isAssignableFrom(Class.forName(cr) ) ;
}
catch(ClassNotFoundException ex)
{}
return bret ;
}
/**
* to adjust whether is a instance of class 判断对象是否属于指定CLASS
* @param obj
* @param cls
* @return the result
*/
public boolean isInstance(Object obj, Class cls) {
return cls.isInstance(obj);
}

/**
* to clone an object(deep clone) without fields with primitive type 克隆一个对象
* @param obj
* @return the result
*/
public Object cloneObjectFrom(Object obj)
{
Object objret = null;
Class cls = obj.getClass() ;
Field[] f = cls.getDeclaredFields() ;
Field fcur = null ;

//set accessible of field that having no permission 超越私有权限访问对象
Field.setAccessible(f , true) ;
try
{
//adjust whether is a proxy object
if (! isProxyObject(obj))
{
//just create an instance by the same class
objret = cls.newInstance() ;
}
else
{
//create a proxy instance through the source object 创建一个新的代理对象
objret = Proxy.newProxyInstance(
obj.getClass().getClassLoader(),
obj.getClass().getInterfaces(),
Proxy.getInvocationHandler(obj));
}
//objret = obj.clone() ;
for ( int i = 0 ; i < f.length ; i++)
{
fcur = f[i] ;

Class clstype = fcur.getType();
if ( clstype.isPrimitive() )
{
System.err.println(obj.getClass().toString()
+ "." +fcur.getName()
+ " is not allowed to be a primitive type") ;
return null ;
}

fcur.set(objret,fcur.get(obj)) ;
}
// deep copy for iterable object 深度复制
if (Class.forName("java.lang.Iterable").isAssignableFrom(obj.getClass()))
{
for (Object objIdx : (Iterable)obj)
{
objIdx = cloneObjectFrom(objIdx) ;
}
}
}
catch(Exception ex)
{
ex.printStackTrace() ;
}
return objret ;

}
}

到这里一切工具包准备就绪,接下来就是实现两个单件工厂对象的类,其中类BeansFactory依赖于代理对象接口IProxyBeansFactory,该接口被桥接的实现类ProxyBeansFactory用于创建加载了装备与拦截器的代理对象,其代码如下:
package myFramework;
import java.lang.reflect.Proxy;
public class ProxyBeansFactory implements IProxyBeansFactory
{
private static ProxyBeansFactory pbf = new ProxyBeansFactory();
private ProxyBeansFactory()
{
}
//get the singleton instance
public static ProxyBeansFactory getInstance()
{
return pbf;
}
//create a proxy object according the target and advices
public Object createProxyObject(Object proxy, IAdvice[] advices)
{
return Proxy.newProxyInstance(proxy.getClass().getClassLoader(), proxy.getClass().getInterfaces(), new ProxyObjectHandler(proxy , advices));
}
//create a proxy object by loading a handler to the target object
public Object createProxyObject(Object proxy, IProxyInterfaceHandler pohandle)
{
return Proxy.newProxyInstance(
proxy.getClass().getClassLoader(),
proxy.getClass().getInterfaces(),
pohandle);
}
}
其中上述代码中IAdvice与IProxyInterfaceHandler属于AOP(面向方面编程)的范畴,二者可以称为“装备”和“拦截器”,用于向目标对象的行为方法安装切入点。轻量级架构为了容忍开发人员在类的定义上的自由,都是采用这种代理拦截技术以便可轻松的加/卸载,从而完成所需的功能。对于AOP的实现后面篇幅中会有详解,暂且跳过。
下面就是IoC中核心类BeansFactory的实现代码,提供公共API为getInstance与getObject,前者用于获取工厂对象单件实例,后者则用于获取指定对象。代码如下:
package myFramework ;

import java.text.SimpleDateFormat;
import java.util.* ;

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

/**
* BeansFactory : Inversion of control container 控制反转容器
*
* @author Niu Chao
* @since 2008-8-19
* @version 0.1
*/
public class BeansFactory implements IBeansFactory
{
private static BeansFactory bf = new BeansFactory();
private IProxyBeansFactory pbf = ProxyBeansFactory.getInstance();
private static String[] keyTags = {"class","element","constructor","arg","proxy","advices","interruptor"} ;
private Reflection reflect ;
private XMLCommon xmlCommonObj ;
//dict. of singleton objects 单件对象池
private Dictionary<String,Object> dictSingleton;
//dict. for object pool 非单件对象池
private Dictionary<String,Object> dictObjsPool;
private Element root = null;
/*
* Constructor
* declared in private
*/
private BeansFactory()
{
reflect = Reflection.getInstance() ;
xmlCommonObj = XMLCommon.getInstance();
dictSingleton = new Hashtable<String,Object>();
dictObjsPool = new Hashtable<String,Object>();
}
/*
* create a new Instance
* className
* constructor arguments
*/
private Object newInstance(String className, Object[] args)
{
Object obj = null;

//create an instance by classname
try
{
obj = (args == null?reflect.newInstance(className):reflect.newInstance(className , args));
}
catch (Exception ex)
{
System.out.println(this.getClass().toString() + ":" + ex.toString()) ;
}
return obj;
}
/*
* convert from string to a type specified
* class destination
* data need to be converted
*
*/
private Object convertToType(Class cls,String arg)
{
String clsname = cls.getName() ;

if(clsname == "java.lang.Integer")
{
return new Integer(arg) ;
}
else if(clsname == "java.util.Date")
{
try
{
//parse a date type 转换成日期
return new SimpleDateFormat("yyyy-MM-dd").parse(arg) ;
}
catch(Exception ex)
{
ex.printStackTrace() ;
}
}
//else append here 其它转换,这里没有写过多
return arg ;
}

/*
* adjust whether the tag is a fixed key tag 判断标签是否是系统定义的
* tag to be adjusted
* bool result
*
*/
private boolean isKeyTag(String tag)
{
for (int i = 0 ; i < keyTags.length ; i++)
{
if (tag.equals(keyTags[i]))
{
return true ;
}
}
return false ;
}
/*
* set the property of one object from element defined in xml file
* 根据XML定义设置一个对象的属性
* object to be set
* element of xml
*
*/
private void setObjectFromElement(Object objelm , Element elm)
{
//get the child nodes of the current <element> tag 获取子节点
NodeList proplist = elm.getChildNodes();
for (int k = 0 ; k< proplist.getLength() ; k++)
{
//get the property name be signed in node 获取当前节点的名称
Node elmprop = (Node) proplist.item(k) ;
String propName = elmprop.getNodeName() ;

//cancel the node named start with '#' 过滤以“#”开头的节点
if (propName.startsWith("#") || isKeyTag(propName))
continue ;
//set the property through the setter method 通过设置子设置属性值
String objarg = elmprop.getFirstChild().getNodeValue();
invokeSetProperty(objelm , propName , objarg) ;
}
}
/*
* get an object from element's attribute 根据节点属性创建/获取一个对象
* element of xml
*
*/
private Object getObjectFromAttrib(Element elmcur)
{
Object obj = null ;
String stmp = elmcur.getAttribute("object") ;
if (stmp.length() > 0)
{
// get the object from ioc. 递归调用以获取依赖对象
obj = getObject(stmp) ;
}
else if ((stmp = elmcur.getAttribute("class")).length() > 0)
{
obj = constructAnObject(stmp , elmcur) ;
}
return obj ;
}
/*
* construct an object according to the class name and element's attributes
* 根据类名和XML节点定义构造一个对象并设置属性
* element of xml
*
*/
private Object constructAnObject(String clsname , Element elmobj)
{
Object obj = null;
//the constructor-arguments
Object[] objargs = null ;
Element elmcur = null;
ProxyTargetHandler itrhandler = null ;
String stmp ;

//whether is a collection 判断是否是集合类
stmp = elmobj.getAttribute("iscollection");
boolean isCollection = stmp.equals("true");

//set the default package of sub-element nodes 读取缺省类路径
String sDefPackage = elmobj.getAttribute("defpackage") ;
if ( !sDefPackage.equals("") && clsname.indexOf(".") < 0)
{
clsname = sDefPackage + "." + clsname ;
}

NodeList conslist = elmobj.getElementsByTagName("constructor");
Element elmcons =(Element) conslist.item(0) ;
if (elmcons != null )
{
//get the constructor-arguments 读取构造子参数列表
NodeList argslist = elmcons.getElementsByTagName("arg") ;
int icnt = argslist.getLength() ;

//allocate the area of object array 分配空间以容纳构造子
if (icnt > 0)
{
//constructor parameters
objargs = new Object[icnt] ;
}

//scan the list of arguments 遍历构造子参数列表
for (int j = 0 ; j < icnt ; j++)
{
elmcur = (Element) argslist.item(j) ;
objargs[j] = getObjectFromAttrib(elmcur) ;
}
}
//get the interrupt handler 获取拦截器
NodeList hdlnodes = elmobj.getElementsByTagName("interruptor");
Element elmhdl = (Element) hdlnodes.item(0) ;
if (elmhdl != null)
{
itrhandler = (ProxyTargetHandler)getObjectFromAttrib(elmhdl) ;
}
//if the object has advices 判断该对象是否需要加载装备
NodeList advsnodes = elmobj.getElementsByTagName("advices");
Element elmadvs =(Element) advsnodes.item(0) ;
if (elmadvs != null)
{
//get the advices collected by element 遍历装备
NodeList advslist = elmadvs.getElementsByTagName ("element") ;
IAdvice advobj ;
if (advslist.getLength() > 0)
{
IAdvice[] advs= new IAdvice[advslist.getLength()];
for (int j = 0 ; j < advslist.getLength() ; j ++)
{
Element elmadv = (Element) advslist.item(j) ;
advobj = (IAdvice) getObjectFromAttrib(elmadv) ;
advs[j] = advobj ;
}

//get the first parameter 构造子首参数为目标对象
if (objargs.length > 0 )
{
Object proxy = objargs[0] ;
obj = pbf.createProxyObject (proxy,advs) ;
return obj ;
}
}
}//generate a new instance 创建新对象
else if ( (obj = newInstance(clsname , objargs)) == null)
return null;

//set the property of the object instanced according to xml 设置对象属性
setObjectFromElement(obj , elmobj) ;

//if there is invacation handler defined, create a proxy object 判断是否定义拦截器
if (itrhandler != null)
{
itrhandler.setObjTarget(obj) ;
obj = pbf.createProxyObject(obj , itrhandler) ;
}
//whether is a collection 如果是集合对象
if (isCollection)
{
//get the elements of the collection 遍历每个元素从XML文档
NodeList elmlist = elmobj.getElementsByTagName("element");
Element elm ;
for (int j = 0 ; j< elmlist.getLength() ; j++)
{
elm = (Element) elmlist.item(j) ;

//create a instance of beanclass be specified 根据对象名创建实例
String beanclsname = elm.getAttribute("class");
if (beanclsname.indexOf(".") < 0)
{
beanclsname = sDefPackage + "." + beanclsname ;
}
Object objelm = newInstance(beanclsname , null);
if (objelm == null)
{
return null ;
}

//set the object according to child 设置对象属性
//nodes of the current <element> tag
setObjectFromElement(objelm , elm) ;

//process the collection of list 构建集合列表
if (reflect.isAssignable("java.util.Collection",clsname) )
{
Collection lst = (Collection)obj;
lst.add(objelm) ;
}

}
}
return obj ;
}
/*
* invoke a setter method 调用设置子方法
* property name 属性名
* data need to be setted 属性值
*
*/
private Object invokeSetProperty(Object owner, String propName, Object arg)
{
Object obj = null;

String methodName = "set"+propName ;
try
{
//get the class of argument belongs to the method 获取属性类型
Class cls = reflect.getArgTypeOfSetter(owner,methodName);

//according to the type , do converting 转换字串为目标类型
arg = convertToType(cls , (String)arg) ;
Object[] objArgs = {arg} ;
//invoke the method of setter 调用设置子方法
obj = reflect.invokeMethod(owner , methodName, objArgs);
}
catch(Exception ex)
{
ex.printStackTrace() ;
}
return obj;
}
/*
* get the singleton instance of BeansFactory 获取单件对象
*/
public static BeansFactory getInstance()
{
return bf;
}

/*
* get a object defined in xml file 获取对象
*/
public Object getObject(String aObjName)
{
String objname , clsname , stmp;
boolean isSingleton = false;
Document doc ;
Element elmobj;

//get the object from singleton dict. 搜索单件对象缓存中
Object obj = dictSingleton.get(aObjName) ;
if (obj != null)
{
return obj;
}

//set the root node if not be initallized 设置根结点
if (root == null)
{
doc = xmlCommonObj.getDocument() ;
root = doc.getDocumentElement();
}

//filter by the object tag 搜索指定元素节点
NodeList objlist = root.getElementsByTagName("object");
for (int i = 0 ; i < objlist.getLength(); i++)
{
elmobj = (Element) objlist.item(i);
objname = elmobj.getAttribute("name") ;

//find the object by it's name 匹配名称
if (!objname.equals(aObjName))
continue;

//get the class name 获取类名
clsname = elmobj.getAttribute("class") ;

//whether is a singleton
stmp = elmobj.getAttribute("singleton") ;
isSingleton = stmp.equals("true");

if (! isSingleton )
{
obj = dictObjsPool.get(objname) ;
if (obj!=null)
{
//clone the object 非单件对象缓存中存在则克隆复本返回
obj = reflect.cloneObjectFrom(obj) ;
}
}
if (obj == null)
{
//to construct an object according to classname and element defined
//根据类名与当前元素结点构造对象
obj = constructAnObject(clsname , elmobj) ;

}

//put the object into memory cache 将对象保存至缓存中
if (obj!=null)
{

if (isSingleton )
{
//put the instance into singleton dict./objects pool dict.
//放置对象至单件缓存中
dictSingleton.put(objname , obj) ;
}
else
{
//put it into objects pool if not a singleton
//缓存该对象
dictObjsPool.put(objname , obj) ;
}
}

}
return obj;
}
}
以上便为IOC部分的代码,当然如果不明白松散耦合,控制反转容器与依赖注入的概念,那上述代码一定会觉得不知所途,既知晓渔就能鱼,善于剖析机理,很多问题也便迎刃而解罗。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
相关文章推荐