MyFramework之实训篇
原创: 牛超 TOKYO
前面吹得那么海,在架构高人们面前小弄了一下腰板儿斧。接下来就是MyFramework的使用了,作者本人开发软件向来喜欢自上而下搭建系统,实例代码先于框架已经写好了,为了模拟系统开发的真实性,这里采用经常使用的N层架构应用的模式。自顶向下分别是BO-》DAO-》Framework。
<!--[if !vml]--><!--[endif]-->
BEANS中存放业务数据结构内容,这里假设为用烂了的EMPLOYEE,定义如下:
package app.beans;
import java.text.SimpleDateFormat;
import java.util.Date;
public class EmployeeBean
{
//member variables
private Integer empid;
private String empcode;
private String empname;
private Date birthday;
private String resume;
//setter / getter
public Integer getEmpId()
{
return empid;
}
public void setEmpId(Integer id)
{
empid=id ;
}
public String getEmpCode()
{
return empcode;
}
public void setEmpCode(String code)
{
empcode=code;
}
public String getEmpName()
{
return empname;
}
public void setEmpName(String name)
{
empname=name;
}
public Date getBirthday()
{
return birthday;}
public void setBirthday(Date day)
{
birthday=day;
}
public String getResume()
{
return resume;
}
public void setResume(String me)
{
resume=me;
}
public String toString()
{
return "Employee # ("
+ "empid :" + new Integer(empid).toString()
+ ", empcode :" + empcode
+ ", empname :" + empname
+ ", birthday :" + new SimpleDateFormat("yyyy-MM-dd").format(birthday)
+ ", resume :" + resume
+ ")";
}
};
DAO层完成数据的访问以便为上层提供接口,这里数据源假设直接来自XML,完成对EmployeeBean列表的获取,这个集合内容存放在文档中。设计亦采用桥接模式,其中IEmployeeDao与EmployeeDaoImpl是一对接口定义与实现,如下所示:
<!--[if !vml]--><!--[endif]-->
对于BO层,就是组合了多个DAO的商业对象,这里只有一个人力资源业务,其实现也相对简单只依赖于一个IEmployeeDao对象。结构定义如图所示:
<!--[if !vml]--><!--[endif]-->
下面是目标测试代码,即主类的实现:
package app ;
import myFramework.BeansFactory;
import myFramework.IBeansFactory;
import app.beans.EmployeeBean;
import app.bo.IHrBO;
public class Main {
public Main()
{
IBeansFactory bf = BeansFactory.getInstance() ;
//test ioc
((IHrBO)bf.getObject("empbo")).getBOInfo() ;
//test aop
((IHrBO)bf.getObject("proxyempbo")).printHrEmployeeInfo() ;
EmployeeBean a = (EmployeeBean)bf.getObject("anemployee") ;
EmployeeBean b = (EmployeeBean)bf.getObject("anemployee") ;
//test beans be cloned from not singletone dict.
final int num = 5 ;
EmployeeBean[] ebs = new EmployeeBean[num] ;
for (int i = 0 ; i < num ; i ++)
{
System.out.println(
(ebs[i] = (EmployeeBean)bf.getObject("anemployee") )
);
}
System.out.println ("anemployee isSingleton ?" + (ebs[0] == ebs[2])) ;
//test interface handler
((IHrBO)bf.getObject("empbohandler")).getBOInfo() ;
}
/**
* @param args
*/
public static void main(String[] args) {
// TODO 自動生成されたメソッド・スタブ
new Main();
}
}
上述代码很简单分别测试了IoC容器、单件、分层AOP装备调用、普通/代理对象克隆、接口拦截器机能。因为容器生成的对象类型为Object,传入的参数为对象名即XML文档中定义的名称,XML定义还包括各种属性、集合对象以及对象间的依赖关系以便引导反转容器实现DI即依赖注入:
<?xml version="1.0" encoding="UTF-8"?>
<entities>
<!-- basic objects -->
<object name = "xmlcommon" class = "myFramework.XMLCommon" singleton = "true">
</object>
<object name = "empbo" class = "app.bo.HrBOImpl" singleton = "true">
<constructor>
<arg object = "employeedao" >
</arg>
</constructor>
</object>
<!-- object with properties -->
<object name = "anemployee" class = "app.beans.EmployeeBean" singleton = "false">
<EmpId>5</EmpId>
<EmpCode>0005</EmpCode>
<EmpName>ttt</EmpName>
<Birthday>2007-11-04</Birthday>
<Resume>no resume</Resume>
</object>
<!-- object list -->
<object name = "employeelist" class = "java.util.ArrayList" defpackage = "app.beans" iscollection = "true">
<element class = "EmployeeBean">
<EmpId>1</EmpId>
<EmpCode>0001</EmpCode>
<EmpName>aaa</EmpName>
<Birthday>2007-12-04</Birthday>
<Resume>0</Resume>
</element>
<element class = "EmployeeBean">
<EmpId>2</EmpId>
<EmpCode>0002</EmpCode>
<EmpName>bbb</EmpName>
<Birthday>2007-12-04</Birthday>
<Resume>0</Resume>
</element>
<element class = "app.beans.EmployeeBean">
<EmpId>3</EmpId>
<EmpCode>0003</EmpCode>
<EmpName>ccc</EmpName>
<Birthday>2007-12-04</Birthday>
<Resume>0</Resume>
</element>
<element class = "app.beans.EmployeeBean">
<EmpId>4</EmpId>
<EmpCode>0004</EmpCode>
<EmpName>ccc</EmpName>
<Birthday>2007-12-04</Birthday>
<Resume>0</Resume>
</element>
</object>
<!-- advices for aop -->
<object name = "testbeforeadvice" class = "app.advices.TestBeforeAdvice" singleton = "true">
</object>
<object name = "testaroundadvice" class = "app.advices.TestAroundAdvice" singleton = "true">
</object>
<object name = "testafteradvice" class = "app.advices.TestAfterAdvice" singleton = "true">
</object>
<object name = "testthrowsadvice" class = "app.advices.TestThrowsAdvice" singleton = "true">
</object>
<object name = "employeedao" class = "ProxyObjectHandler">
<!-- <proxy class = "app.bo.HrBOImpl"/> -->
<constructor>
<arg class = "app.dao.EmployeeDaoImpl"/>
</constructor>
<advices>
<element object = "testbeforeadvice" />
<element object = "testaroundadvice" />
<element object = "testafteradvice" />
<element object = "testthrowsadvice" />
</advices>
</object>
<!-- handler of proxy object according to interfaces -->
<object name = "proxyempbo" class = "ProxyObjectHandler">
<!-- <proxy class = "app.bo.HrBOImpl"/> -->
<constructor>
<arg object = "empbo"/>
</constructor>
<advices>
<element object = "testbeforeadvice" />
<element object = "testaroundadvice" />
<!-- <element object = "testafteradvice" /> -->
<element class = "app.advices.TestAfterAdvice" />
<element object = "testthrowsadvice" />
</advices>
</object>
<!-- invacation handler test -->
<object name = "testhandler" class = "app.advices.TestHandler" singleton = "true">
</object>
<object name = "empbohandler" class = "app.bo.HrBOImpl" singleton = "true">
<constructor>
<arg object = "employeedao" >
</arg>
</constructor>
<interruptor object = "testhandler">
</interruptor>
</object>
</entities>
由于反转容器取出对象均为Object类型,所以代码中得向下转换后再进行处理,测试得到的输出结果如下:
HrBOImpl: Human resource bussiness object
TestBeforeAdvice::before , Method:public abstract void app.bo.IHrBO.printHrEmployeeInfo()
testaroundadvice::before , Method:public abstract void app.bo.IHrBO.printHrEmployeeInfo()
TestBeforeAdvice::before , Method:public abstract java.util.List app.dao.IEmployeeDao.getEmployeeList()
testaroundadvice::before , Method:public abstract java.util.List app.dao.IEmployeeDao.getEmployeeList()
testaroundadvice::afterreturn , Method:public abstract java.util.List app.dao.IEmployeeDao.getEmployeeList()app.dao.EmployeeDaoImpl@12498b5
TestAfterAdvice::afterreturn , Method:app.dao.EmployeeDaoImpl@12498b5
Employee # (empid :1, empcode :0001, empname :aaa, birthday :2007-12-04, resume :0)
Employee # (empid :2, empcode :0002, empname :bbb, birthday :2007-12-04, resume :0)
Employee # (empid :3, empcode :0003, empname :ccc, birthday :2007-12-04, resume :0)
Employee # (empid :4, empcode :0004, empname :ccc, birthday :2007-12-04, resume :0)
testthrowadvice::afterThrowing , Method:java.lang.ArithmeticException: / by zero
testaroundadvice::afterreturn , Method:public abstract void app.bo.IHrBO.printHrEmployeeInfo()app.bo.HrBOImpl@1a5ab41
TestAfterAdvice::afterreturn , Method:app.bo.HrBOImpl@1a5ab41
Employee # (empid :5, empcode :0005, empname :ttt, birthday :2007-11-04, resume :no resume)
Employee # (empid :5, empcode :0005, empname :ttt, birthday :2007-11-04, resume :no resume)
Employee # (empid :5, empcode :0005, empname :ttt, birthday :2007-11-04, resume :no resume)
Employee # (empid :5, empcode :0005, empname :ttt, birthday :2007-11-04, resume :no resume)
Employee # (empid :5, empcode :0005, empname :ttt, birthday :2007-11-04, resume :no resume)
anemployee isSingleton ?false
TestHandler before invoke
HrBOImpl: Human resource bussiness object
TestHandler after invoke
由结果可以看出用于挂载在BO上的装备同样被重用在DAO上,所以装备是可重用的,并且其加载也是自由的,被代理封装实体对象在完成自己的操作同时也会兼顾其挂载的各个装备的操作。呵呵,结果证明已经利用MyFramework模仿完成了Spring这样强大框架的基础功能。本文中已经贴出大部分代码以供参考,如有需要完整代码的或是有指正意见的,请EMAIL我,也是为了结识更多志同道合的朋友。