姜林美, 李国刚, 杜勇前
(华侨大学 计算机科学与技术学院, 福建 厦门 361021)
结合AOP思想和依赖注入技术的轻量级MVC框架
姜林美, 李国刚, 杜勇前
(华侨大学 计算机科学与技术学院, 福建 厦门 361021)
摘要:为了解决目前Java主流模型-视图-控制器(MVC)框架日益庞大,从而导致性能低下的问题,提出了一个轻量级的MVC框架.该框架利用面向方面编程(AOP)技术实现了横向业务的剥离,采用控制反转设计模式实现了模块间的最低耦合,并通过Java反射技术实现了数据库记录与Java对象的自动转换.实验结果表明:该框架以仅仅70 KB左右的JAR包实现了比其庞大数百倍的类似框架的主要功能,同时支持网络应用和移动应用的开发,具有更高的执行效率.
关键词:Java反射; 依赖注入; 控制反转; 模型-视图-控制器框架; 面向方面编程; 移动应用开发
在面向对象设计领域,框架是由一组相互协作的可重用设计的类构成,对这些类进行特化(specialized),即可创建不同的客户应用程序[1].目前,框架设计已成为加速信息系统开发和软件重用的一项关键技术[2],尽可能地降低模块之间的耦合性.模型-视图-控制器(model view controller,MVC)框架的核心是能够实现三层甚至多层的松散耦合[3].面向方面编程(aspect oriented programming,AOP)的核心思想是对软件系统中各个互相独立的横切关系(如日志记录、权限检查、缓存和持久化等)加以模块化,使之可以有效地集中被管理,而不会让其分散到程序代码的各个地方[4].AOP把一个系统看作一批关注点,强调调用者与被调用者之间的解耦,并能够自动将横切关注点织入到面向对象的软件系统中[5],将业务关注点和横切关注点分离[6-7].依赖注入是Martin Fowler对IoC(inversion of control)模式的一种扩展解释,即高层不应依赖于底层,两者都应依赖于抽象;抽象不应依赖于细节,细节应依赖于抽象[8].在Java中,依赖注入一般通过反射机制来实现.Java反射机制允许在运行时加载、探知和使用编译期完全不知道的类[9].目前,SSH(struts2 spring hibernate)框架在Java Web轻量级应用开发领域得到了广泛的应用.SSH是由Struts2,Spring和Hibernate三个独立组件组合而成,它们各有自己的不同的版本,这些版本相互组合存在兼容性问题和执行效率低下的问题.另外,Hibernate因采用对象关系映射(ORM)技术导致效率比精心编写的JDBC(java data base connectivity)差[10].最后,SSH的各个组件的尺寸越来越大,所带来的问题是应用系统的可维护性差,运行效率的降低.为此,本文提出应用AOP和Java依赖注入技术的思想的轻量级MVC框架.
1框架的设计
文中提出的框架运行于Web容器之上,其总体结构如图1所示.
图1 框架结构Fig.1 Structure of the framework
派遣过滤器是框架与Web容器交互的界面.派遣过滤器实现了javax.servlet.Filter接口.Filter接口的配置管理器由派遣过滤器创建并调用,负责读取并解析系统配置文件.frame.xml.init()方法中,通过配置管理器读取框架的配置文件frame.xml,并进行解析.Filter接口的doFilter()方法中,利用Action调度器对Web容器发来的HttpServletRequest请求进行处理,并将处理结果通过HttpServletResponse反馈给Web容器.
配置管理器由派遣过滤器创建并调用,它负责读取并解析系统配置文件frame.xml.根据配置文件中的配置项生成各类映射表,包括Action映射表、拦截器映射表、终结器映射表、DAO(data access object)映射表、结果视图映射表和常量映射表.前4种映射表是Action调度器进行依赖注入的依据.另外,配置管理器还通过反射机制创建数据库连接池.该连接池在DAO对象调用数据库操作工具包进行数据库访问时被自动引用,并在派遣过滤器销毁时自动销毁.
当客户端的HTTP请求经Web服务器送达Web容器后,Web容器生成相应HttpServletRequest请求,派遣过滤器则会在其doFilter() 方法中截获该请求,并通过Action调度器对该请求进行处理,并反馈处理结果.因此,Action调度器是整个框架的核心.
1.3.1依赖注入依赖注入是Action调度器对一次HttpServletRequest请求所做的第一个操作,需要调用反射工具包中的反射处理函数配合完成.首先,Action调度器会根据请求的URL(universal resource locator)信息,在配置管理器的Action映射表中查找相应的Action类名.如果找到,则通过依赖注入创建相应的Action实例;否则,立即终止请求,并输出错误提示.Action实例成功创建之后,调度器继续在配置管理器的映射表中查找与该Action相关的拦截器和终结器,查找成功,即通过依赖注入创建相应的实例.此外,调度器还将在配置管理器的DAO映射表中查找与该Action相关联的DAO,如果查找成功,则创建DAO实例,并将创建的DAO实例注入该Action对象.最后,调度器通过Java反射功能检查该Action中的成员变量中是否有表单类型的对象,如果有,则创建表单实例,并为表单对象的各成员变量注入值.所注入的值来自HttpServletRequest中与成员变量同名的请求参数,表单类型指的是直接或间接从Form类继承的类.
1.3.2拦截器调度器在完成依赖注入之后,在配置文件中,以拦截器配置的先后顺序依次调用拦截器对象的intercept()方法,该方法以接收请求相应的Action对象作为其参数.在拦截器中可以对请求做任何横切事务处理,并根据横切处理结果决定是否要继续执行Action对象中的目标方法.
1.3.3ActionAction是框架提供给上层应用的主要接口,应用程序应当是在Action中或Action的交互类中实现业务处理的核心代码.
如节1.3.1所述,Action中若有DAO类型的成员变量,并在frame.xml中进行了相应的配置,该成员变量的值会在依赖注入阶段进行注入.另外,Action中表单类型的成员变量的值也会在依赖注入阶段进行注入.因此,在Action中可以直接使用DAO进行数据库访问,也可以通过表单类型的成员变量直接获得客户端提交的数据.
在Action中,可通过“表单-POJO(plain ordinary java objects)转换器”将表单对象转换成POJO对象.转换的原则是同名成员变量做类型转换后,进行相应的赋值,转换后的POJO对象即可供业务处理使用.此后,若业务处理过程需要进行数据库操作,可使用DAO对象来完成.在DAO中只需编写SQL语句,然后调用数据库操作工具包中的相应方法执行该SQL语句,即可完成任何数据库操作.若执行的是有结果集(Resultset)的SQL语句,所取得所有记录行(结果集中的)会通过“记录行-POJO转换器”转换成POJO对象,然后整个结果集中的数据将被封装成一个List列表(POJO数据集)返回.
1.3.4结果视图结果视图对应MVC框架的视图部分,在Action中对业务逻辑进行处理之后,可根据处理结果选择在frame.xml中配置好的属于Action的任一结果视图.框架支持的结果类型包括FORWARD,REDIRECT,REDIRECT_TOP,CHAIN,PLAINTEXT,JSON和XML.前3种类型一般用于JSP页面,其中,FORWARD类型用于直接在服务端转发请求的JSP页面;RIDRECT类型则用于重新转发到一个新的URL页面;REDIRECT_TOP和RIDRECT一样,但在原始页面由多个frame(指html的〈frame〉或〈iframe〉)构成时,会在顶层显示转发后的结果页面.CHAIN类型用于直接调用另一个Action作后续处理的页面;使用PLAINTEXT类型会向客户端传送普通文本;使用JSON类型则会将Action中的处理结果格式化成JSON字符串,再传送给客户端.最后,XML类型意味着向客户端传送XML文档.
1.3.5终结器Action调度器处理的最后一步,在配置文件中,对终结器配置的先后顺序依次调用终结器对象的intercept()方法,该方法同样以接收请求相应的Action对象作为其参数,可对请求做任何横切事务处理.
2框架的实现
框架源码实现时含4个包,分别是工具包util、数据库包db、核心包core和活动包action.整个框架最终被打包成xxdw-platform.jar提供给上层应用程序来使用,框架的源码组织结构,如图2所示.
图2 源码组织结构Fig.2 Organization of the source codes
工具包util提供整个框架的一些工具类,工具类只有一些静态的方法,以便通过类名直接调用.其中:ReflectUtil类是实现依赖注入的基础,同时也为Form2PojoUtil类进行表单-POJO的转换,以及为Record2PojoUtil进行记录行-POJO的转换提供支持.ReflectUtil的核心操作是依赖注入和数据类型的转换.
ViewUtil定义了和视图操作相关的一些方法,如取上下文路径、视图重定向等.CommonUtil则定义了其他一些常用的公共方法,如设置调试模式、获取远端IP地址、特殊字符转义处理等.
数据库包db中的类均与数据库处理相关.其中:ConnectionPoolFactory是用于创建连接池的工厂类;ConnectionPool是数据库连接池.配置管理器在读入并解析frame.xml时,实例化连接池工厂,并创建连接池;Dao是一个抽象类,应用程序应当继承该类以实现自身的各种数据库访问操作;DbUtil类提供一系列静态方法以执行任何SQL查询操作,使用Record2PojoUtil工具可将数据库记录转换成Java对象.
核心包core实现整个框架的“控制”(即MVC中的Controller)部分,其中:FrameFilter是派遣过滤器,它被配置到Web容器的web.xml文件中,以截获客户端的ServletRequest请求;ConfigureManager即配置管理器,管理frame.xml中的各配置项;ActionItem,ResultItem和DaoItem分别用于其中的Action配置项、结果视图配置项和Dao配置项;ActionDispatcher对应框架中的Action调度器,对整个HttpServletRequest的请求处理过程进行调度处理.
活动包action中实现了一些应用程序所必须继承的基础类或应当实现的接口,应用程序主要通过这些类使用框架的各项功能.其中:Action类是业务活动基类,所有继承该类的类应当在frame.xml中进行配置,并会在框架的依赖注入阶段被实例化;Form是所有表单类应继承的基类,用于接收客户端提交的数据,表单类也会在依赖注入阶段被实例化,并被注入数据;Interceptor和Finalizer分别为拦截器和终结器接口;Pojo类则是应用程序中的简单对象类.
3实验结果与分析
为验证所提出的轻量级MVC框架的性能,建立了两个Web项目,分别采用struts 2框架和所提出的轻量级MVC框架对客户端的请求进行处理.客户端通过多线程来模拟并发连接,每个线程可连续向服务端发起多个请求.线程数称为并发数;每个线程连续发起的请求数称为每并发请求数,简称请求数.因此,总请求数=并发数×请求数,客户端向服务端提交请求的核心代码如下所示.
∥建立一个Socket
Socket socket=new Socket(InetAddress.getByName(“localhost”),8080);
∥提交的数据
String para=“username=alice&password=568998”;
StringBuffer command=new StringBuffer()
.append(“POST” +path+ “HTTP/1.1 ” )
.append(“Accept:*/* ”)
.append(“Content-Type: application/x-www-form-urlencoded ”)
.append(“HOST:localhost:8080 ”)
.append(“Connection:Close ”)
.append(“Content-Length: ”+para.length() + “ ”)
.append(“ ”+para);
∥发送命令
BufferedWriter writer=new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
writer.write(command.toString());
writer.flush();
∥接收返回的结果
BufferedReader reader=new BufferedReader(new InputStreamReader(socket.getInputStream()));
while (reader.readLine() != null);
两个Web项目所构建的服务端接收相同的请求数据(即username=alice&password=123456)并对其进行读取,然后向客户端返回相同的jsp响应页面.
实验一的客户端和服务器采用同一台主机,该主机的配置如下:CPU为Pentium (R) Dual Core CPU E5200@2.5 GHz,内存3.0 G,操作系统为Windows 7,32位旗舰版 Service Pack 1,Web服务器为Apache Tomcat 6.0.26.
实验二的服务端同实验一,客户端则为一台安卓华为C8813手机.华为C8813的主要参数:操作系统为Android OS 4.1,CPU为高通骁龙Snapdragon MSM8625Q双核1.2 GHz,内存512 M.
两个实验各自的总请求数均为2 500(基本接近Tomcat 6所能接受的并发连接数的上限),各自测试3种具有代表性的情形:并发数为1,每并发连接数为2 500;并发数为50,每并发连接数也为50;并发数为2 500,每并发连接数为1.第1,3种情形属于极端情况,中间一种情形代表了普通情况.3种情况下,采用struts 2的服务端和采用文中MVC框架的服务端的平均耗时(每种情形均进行1 000次测试),如表1所示.表1中:T为并发数;R为请求数.由表1可知:采用轻量级MVC框架的服务端所用时间远低于采用struts 2的服务端所用时间.
表1 处理2 500个连接的耗时
为更清晰地观察两个框架的性能区别,根据表1计算出的两个框架每秒所能处理的请求数,如表2所示.由表2可知:在客户端为PC机的情况下,相比于struts 2,采用文中轻量级MVC框架可提升处理请求的能力平均达57.11%;在客户端为手机的情况下,受限于移动终端的并行处理能力,相比于struts 2,采用文中轻量级MVC框架可提升处理请求的能力小一些,但平均仍达16.64%.
每秒所能处理的连接数对比,如图3所示.图3中:横轴标识中的T表示并发数;R表示每并发请求数.由图3可以直观地看出:文中轻量级MVC框架的性能优越性.
(a) PC客户端 (b) Android客户端图3 每秒所能处理的连接数对比Fig.3 Connection processing performance comparison
从实验结果可以看出:两个框架在并发数和每并发请求数均衡的普通情况下的处理能力均优于各自的极端情况,但是在任何情形下,文中所述框架在性能上均优于struts框架.
表2 每秒处理的请求数和性能比较
4结束语
鉴于AOP程序设计和MVC框架在Web应用程序开发中日益广泛的应用,而现存的采用Java平台的MVC框架(如SSH)日益庞大繁杂,提出了一个精简的轻量级的结合AOP和依赖注入的MVC框架.该框架的成品jar包库仅有72.1 KB,远小于SSH和Spring MVC等框架的jar包库.实验数据说明:该框架相比于struts 2具有更好的运行性能.另外,该框架已在多个Web和移动应用项目中得到应用.实践结果证明:该框架能极大地提升应用开发的效率.最后,增加Web服务支持可以更大地提高框架的通用性,这也是进一步的研究方向.
参考文献:
[1]LI Fangxing,BROADWATER R P.Software framework concepts for power distribution system analysis[J].IEEE Transactions on Power Systems,2004,19(2):948-956.
[2]CHEN Liyan,GAO Qing.Research on framework developing technology based on MVC[J].Advances in Information Sciences and Service Sciences,2011,3(3):25-31.
[3]张忻.基于MVC模式的Struts框架在物流管理信息系统中的应用[D].成都:西南交通大学,2005:7-8.
[4]徐倩颖,杨宗源.面向方面编程的一种新型设计模式[J].华东师范大学学报(自然科学版),2008,2008(1):68-74.
[5]史玉珍,李波.一种面向方面的UML建模方法研究[J].计算机测量与控制,2009,17(12):2497-2499.
[6]陈月娟,李慧,刘光远,等.基于AOP的信息管理系统的研究与实现[J].计算机应用与软件,2010,27(2):130-132,140.
[7]卞世晖,李龙澍,陈圣兵,等.基于AOP理念的Struts 2拦截器的研究与应用[J].电子设计工程,2010,18(1):8-9.
[8]ROBERT C M.敏捷软件开发:原则、 模式与实践[M].北京:清华大学出版社,2003:116-118.
[9]费廷伟,刘淑芬,屈志勇,等.Java反射驱动的规则引擎技术研究[J].计算机应用,2010,30(5):1324-1326,1330.
[10]柏银.基于Struts+Spring+Hibernate多架构的性能分析系统[D].成都:四川大学,2006:26-30.
(责任编辑: 陈志贤英文审校: 吴逢铁)
A Light-Weight MVC Framework Combining
AOP and Dependency Injection
JIANG Linmei, LI Guogang, DU Yongqian
(College of Computer Science and Technology, Huaqiao University, Xiamen 361021, China)
Abstract:To solve the problem of low performance caused by gradually increased size of the most popular Java MVC(Model-View-Control) frameworks, a novel light-weight MVC framework is presented. In the proposed framework, AOP(Aspect Oriented Programming) technology is used to deal with the cross-cutting business logic, and Inversion-of-Control pattern is adopted to achieve the lowest coupling among modules. Meanwhile, Java reflection technology is used to transfer a database record to a Java object automatically. The experimental results show that although the JAR package of the proposed framework takes only around 70 KB, it not only realizes all the primary functions of the similar frameworks whose size are hundreds of times more massive, but also supports the development of both web application and mobile application with higher execution efficiency.
Keywords:Java reflection; dependency injection; inversion of control; model view controller; aspect oriented programming; mobile application development
基金项目:福建省厦门市重大科技计划项目(3502Z20131019)
通信作者:姜林美(1976-),男,讲师,博士研究生,主要从事网络安全与网络应用软件的研究.E-mail:clough@hqu.edu.cn.
收稿日期:2014-07-30
中图分类号:TP 393.01
文献标志码:A
doi:10.11830/ISSN.1000-5013.2016.01.0092
文章编号:1000-5013(2016)01-0092-06