1
J2EE
多层应用分析
1.1
J2EE
层次结构
J2EE
的三层结构在业界是指表示层
(Presentation)
,业务逻辑层
(Business logic)
以及基础架构层
(Infrastructure)
。这样的划分当然是经典的,但是在实际项目中,往往会对三层体系结构做一些扩展来满足项目的需要。一个最常用的扩展就是将三层体系扩展为五层体系,即表示层
(Presentation)
、控制
/
中介层
(Controller/Mediator)
、领域层
(Domain)
、 数据持久层
(Data Persistence)
和数据源层
(Data Source)
。它其实是在三层架构中增加了两个中间层。控制
/
中介层位于表示层和领域层之间,数据持久层位于领域层和基础架构层之间。而轻量级架构
Struts + Spring + Ibatis
可以实现J2EE多层结构,Struts 用于表示层、控制层,Spring 用于业务处理层,而Ibatis 用于数据持久层。
1.2
Struts
框架
Struts
是一个基于Sun J2EE平台的MVC框架,主要是采用Servlet和JSP技术来实现的。是开发Web应用程序的开放源码的Framework。Struts把Servlet、JSP、自定义标签和信息资源(message resources)整合到一个统一的框架中,开发人员利用其进行开发时不用再自己编码实现全套MVC模式,极大的节省了时间,Struts包括如下的主要功能:
☆
包含一个controller servlet,能将用户的请求发送到相应的Action对象。
☆
JSP
自由tag库,并且在controller servlet中提供关联支持,帮助开发员创建交互式表单应用。
☆
提供了一系列实用对象:XML处理、通过Java reflection APIs自动处理JavaBeans属性、国际化的提示和消息
。
1.3
Spring
框架
Spring
是一个目前非常活跃的开源项目;它是一个基于IoC(Inversion of Control)和AOP(Aspect-Oriented Programming)的,轻量级的,多层j2ee系统的框架,但它不强迫你必须在每一层中必须使用Spring,它模块化的很好,允许你根据自己的需要选择使用它的某一个模块;它实现了很优雅的MVC
,对不同的数据访问技术提供了统一的接口,采用IoC使得可以很容易的实现bean的装配,提供了简洁的AOP并据此实现Transcation Managment,等等
[ 1 ]
。
Spring
虽然提供了MVC Web框架的解决方案,但是也能与其他的web框架相结合使用,如struts、Webwork、JFS等。Spring也可以与其他持久层结构相结合,如:jdbc、Hibernate、Ibatis等,能够使用AOP的技术提供事务处理等功能
。
1.4
数据关系映射
Ibatis
Ibatis
提供了ORM机制,对业务逻辑实现人员而言,面对的是纯粹的Java对象, 这一层与通过Hibernate 实现ORM 而言基本一致,而对于具体的数据操作,Hibernate 会自动生成SQL 语句,而Ibatis 则要求开发者编写具体的SQL 语句。相对Hibernate等 “全自动”ORM机制而言,Ibatis 以SQL开发的工作量和数据库移植性上的让步,为系统设计提供了更大的自由空间。作为“全自动”ORM 实现的一种有益补充,Ibatis 的出现显得别具意义
[ 2 ]
。
2
J2EE
轻量级架构
2.1
架构
图1 框架示意图
2.2
View
层
在视图层主要使用Struts结构的技术。
☆
TagLib
在jsp的前端页面中使用Struts提供的标签完成页面数据逻辑的组织与显示。如(html,bean,logic等)
☆
国际化的消息处理功能
在jsp页面中不出现特定语言的字符串描述,将这些统一的字符串信息统一的提取到文件中,通过Struts的Bean标签提取。便于整个系统的语言变更与组织。
☆
界面组合功能Tiles
页面中将使用Struts的技术,统一组织页面的结构,便于系统改版、维护。
控制层中依然使用Struts结构。此层将接受、处理View发送的请求,在对信息初步的验证、处理后,将把此请求委派给后端的业务处理层去处理。等待业务处理完成之后,将把处理结果传递给View层进行表现。
在该层中使用Service模式,提供给Control层必要的处理方法。
在接收到Control层的业务处理请求后,按照业务规范、算法对数据进行处理。将处理结果返回给Control层。
本层属于低级的数据处理层,将完成具体的数据处理工作,如数据的增加,更新,查询,删除等。
本层使用DAO(Data Access Object)的设计模式
[ 3 ]
,屏蔽多数据库对上层应用的影响,并使用Ibatis的ORMapping技术,降低数据操作的复杂程度。
3
数据持久层解决方案
3.1
数据持久层
将数据持久单独作为
J2EE
体系一个层提出来,表面上是因为数据持久性是企业实际开发中比较棘手的一个方面,数据持久层设计的成功与否往往对项目起着至关重要的影响,单独将其提出来以便在开发中能够避免它的设计草率。究其最深刻的内因,则是在对象范例和关系范例这两大领域之间“阻抗不匹配”。对象范例基于软件工程的一些原理,例如耦合、聚合和封装,而关系范例则基于数学原理,特别是集合论的原理。两种不同的理论基础导致各自有不同的优缺点。而且,对象范例侧重于从包含数据和行为的对象中构建应用程序,而关系范例则主要针对数据的存储。当为访问而寻找一种合适的方法时,“阻抗不匹配”就成了主要矛盾:使用对象范例,通过它们的关系来访问对象,而使用关系范例,则通过复制数据来连接表中的行。这种基本的差异导致两种范例的结合并不理想,于是有人提出对象数据库以希望解决这个问题。但是,关系数据库技术已经发展得相当成熟,占据了数据库市场
90
%以上的份额,对象数据库的普及尚需时日。数据持久层就是要在对象-关系数据库之间提供一个成功的企业级别的映射解决方案,尽最大可能弥补这两种范例之间的差异。
3.2
J2EE
体系解决方案
3.2.1
EJB
CMP (
容器管理持久
)
实体
Bean
,提供健壮的数据持久性。
Bean
容器处理大部分的数据完整性、资源管理和并发性功能,从而使开发人员关注业务逻辑和数据处理,而不是这些低级细节。使用
Bean
管理的持久性
(Bean Managed Persistence
,
BMP)
实体
Bean
时,开发人员编写持久性代码而容器确定何时执行该代码。使用容器管理的持久性
( Container Managed Persistence
,
CMP)
实体
Bean
时,容器生成持久性代码并管理持久性逻辑
[ 4 ]
。
3.2.2
JDO
Java
数据对象
(JDO)
是一个存储
Java
对象的规范
[ 5 ]
。它已经被
JCP
组织定义成
JSR12
规范。规范的两个主要目的是提供数据处理和访问机制的
API
以及允许规范的实现作为应用服务器的一部分。
Java
数据对象是最新的持久性规范。
JDO
提供了面向对象的持久数据存储。开发人员使用
POJO(
无格式普通
Java
对象,
Plain Ordinary Java Object)
来装入和存储持久数据。
3.2.3
ORM
ORM
具有自我存储到关系数据库的能力,对对象的改变能够直接得以存储,而不考虑数据库存取代码。这样,把全部精力集中到对对象和类进行编程,解决业务问题。在整个系统中除了这一个层次,没有一句数据库存取代码。其中,
Hibernate
、Ibatis等
作为
ORM
中最好的开源工具,受到数量众多的程序员的拥护。
4
基于轻量级架构的应用案例分析
某大型水利信息系统需要使用
J2EE
平台以满足分布式处理、事务管理和安全的要求,
使整个软件呈现分层的体系结构,支持多种数据库的扩展,支持多语言界面的调整,支持页面整体布局的可扩展性调整。封装业务逻辑,使得在外部条件变化时,将影响尽可能的降低,即采用了基于J2EE的轻量级架构。图2是信息系统的体系结构,图3是系统包结构
图2 体系结构图
图3 系统包结构
图3中箭头表示软件包之间的依赖关系。独立的包会被Spring、struts、Ibatis框架结构间接的与其他软件包关联。
4.1
系统剖析
4.1.1
包结构描述
☆
com.water.query.dao
:该包内的类将引入Ibatis的重要组件,使系统能够感知功能操作的接口与接口实现类的关系,这些信息是Ibatis自动映射的前提条件之一。
☆
com.water.query.dao.sqlmapdao
:该包是数据访问的核心,使用Spring结构的数据层功能引进对Ibatis的支持
☆
com.water.query.dao.iface
:该包规定了所有业务的访问接口,只有在此包的接口中定义的方法才会被用户使用。是本系同中所有原子数据操作的定义点。
☆
Ibatis
:该包是由Ibatis数据存储层结构定义。由支持机构提供支持。
☆
com.water.query.dao.sqlmapdao.sql
:该包定义了所有操作的SQL(Sequence Query Language)语句,以及SQL语句与具体值对象的映射关系。
☆
com.water.query.form
:该包定义了本系统中用于数据传输的类。这些类实例是Web界面层与业务逻辑实现层之间的桥梁,起着传输数据的功能。
☆
com.water.query.service
: 该包是本系统引入Spring结构的入口点。通过该入口,系统中其他成员可以通过IoC(依赖倒转)功能访问具体业务的Service对象。
☆
com.water.query.condition
:该包内定义了一系列简单JavaBean,这些JavaBean将携带SQL需要的参数穿行于软件的Control层与Model层之间。
☆
com.water.log
:该包中定义了本系统使用的log组件。
☆
com.water.query.domain.baseinfo
:该包定义了所有基本信息查询模块将要使用的数据传输类。
4.1.2
控制层
在视图层和控制层中采用了Struts框架,在传统的Struts用法中,我们一般都有几个Action Bean和相应的form bean ,但在此设计中并不拘泥于Struts的传统固定用法,这里只用了一个自定义Action类,并且在form bean类的定义上也是创新的。
非传统的Struts开发模式,关键就在Struts Action类和form bean类上。Struts Action类只有一个:BeanAction,这与传统的struts编程方式很不同。BeanAction类是一个通用类,利用反射原理
[ 6 ]
,根据URL来决定调用form bean的哪个方法。BeanAction大大简化了struts的编程模式,降低了对struts的依赖。利用这种模式,我们会很容易的把它移植到新的框架如JSF,Spring。
这样重心就转移到form bean上了,它已经不是普通意义上的form bean了。它不仅仅有数据和校验/重置方法,而且已经具有了行为,从这个意义上来说,它更像一个BO(Business Object),Struts-config.xml的配置里有3种映射方式,来告诉BeanAction把控制转到哪个form bean对象的哪个方法来处理。form bean的这些方法的签名很简单,例如:
public String myActionMethod(){
//..work
return "success";
}
方法的返回值直接就是字符串,对应的是forward的名称,而不再是ActionForward对象,创建ActionForward对象的任务已经由BeanAction类代劳了。
4.1.3
业务层
利用Spring Framework 的BeanFactory机制,采用自定义的工具类(bean工厂类)来加载spring的配置文件,从中可以看出Spring有多灵活,它提供了各种不同的方式来使用其不同的部分/层次,您只需要用你想用的,不需要的部分可以不用。
具体的来说,创建CustomBeanFactory类,Spring的配置文件applicationContext.xml。以下就是该类的全部代码,很简单:
public final class CustomBeanFactory {
static XmlBeanFactory factory = null;
static {
Resource is = new
InputStreamResource( CustomBeanFactory.class.
getResourceAsStream("applicationContext.xml"));
factory = new XmlBeanFactory(is);
}
public static Object getBean(String beanName){
return factory.getBean(beanName);
}
}
实际上就是封装了Spring 的XMLBeanFactory而已,并且Spring的配置文件只需要加载一次,以后就可以直接用CustomBeanFactory.getBean("someBean")来获得需要的对象了(例如someBean),而不需要知道具体的类。CustomBeanFactory类用于{耦合1}的解耦。CustomBeanFactory类用于表现层的form bean对象获得service类的对象。
4.1.4
数据持久层的配置
4.1.4.1
Spring
配置文件
Spring
在设计时就充分考虑到了与Struts的协同工作,并且对Ibatis 有很好的支持,在此轻量级架构中,不需要对Ibatis单独进行配置,只需对 Spring 进行配置就以足够。以下就是Spring的配置文件
applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN"
"http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
<bean id="dataSource"
class="org.apache.commons.dbcp.BasicDataSource"destroy-method="close">
<property name="driverClassName"><value>net.sourceforge.jtds.jdbc.Driver</value>
</property>
<property name="url"><value>jdbc:jtds:sqlserver://127.0.0.1:1433/Sample</value>
</property>
<property name="username"><value>test</value></property>
<property name="password"><value>changeit</value></property>
</bean>
<bean id="sqlMapClient"class="org.springframework.orm.ibatis.SqlMapClientFactoryBean">
<property name="configLocation"><value>SqlMapConfig.xml</value></property>
</bean>
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource"><ref local="dataSource"/></property>
</bean>
<bean id="userDAO" class="net.xiaxin.dao.UserDAO">
<property name="dataSource"><ref local="dataSource" /></property>
<property name="sqlMapClient"><ref local="sqlMapClient" /></property>
</bean>
</beans>
可以看到:
1
.
sqlMapClient
节点
sqlMapClient
节点实际上配置了一个
sqlMapClient
的创建工厂类。
configLocation
属性配置了
ibatis
映射文件的名称。
2
.
transactionManager
节点
transactionManager
采用了
Spring
中的
DataSourceTransactionManager
。
3
.
userDAO
节点
对应的,
UserDAO
需要配置两个属性,
sqlMapClient
和
DataSource
,
sqlMapClient
将从指定的
DataSource
中获取数据库连接。
4.1.4.2
Ibatis
映射文件
sqlMapConfig.xml:
<sqlMapConfig>
<sqlMap resource="net/xiaxin/dao/entity/user.xml"/>
</sqlMapConfig>
user.xml
为:
<sqlMap namespace="User">
<typeAlias alias="user" type="net.xiaxin.dao.entity.User" />
<insert id="insertUser" parameterClass="user">
INSERT INTO users ( username, password) VALUES ( #username#,
#password# )
</insert>
</sqlMap>
UserDAO.java
:
public class
UserDAO extends SqlMapClientDaoSupport implements
IUserDAO {
public void
insertUser(User user) {
getSqlMapClientTemplate().update("insertUser", user);
}
}
SqlMapClientDaoSupport
是
Spring
中面向
ibatis
的辅助类,它负责调度
DataSource
、
SqlMapClientTemplate
完成
ibatis
操作,而
DAO
则通过对此类进行扩展获得上述功能。上面配置文件中针对
UserDAO
的属性设置部分,其中的属性也是继承自于这个基类。
SqlMapClientTemplate
对传统
SqlMapClient
调用模式进行了封装,简化了上层访问代码。
5
总结
从软件层次结构的角度来说,软件的框架要具有较高的伸缩性和可扩展性,本文所讨论的J2EE轻量级架构,由于它采用了Struts框架,因而它的模块化设计得到了很好的应用,层次非常清晰,具有很好的可复用度,但是,同时,此架构存在可伸缩性问题,
架构
中明显存在可伸缩性问题的设计是
Action
。控制器
ActionServlet
对每个
Action
类只创建一个实例
,
所有对该
Action
类的请求都用这个实例进行处理
,
因此
,
它是无状态的、多线程共享的。这意味着
Action
实例的数量是一个常数
,
不能随工作量增加而增加。此外,
反射的利用是对架构扩展的一个有益尝试,虽然提供了非常好的应用开发模式,但是它还非常新,一直在发展中。数据持久层中,Ibatis的应用给人一种耳目一新的感觉,但它也存在着一些不足之处,例如相对于Hibernate ,Ibatis不能直接生成sql语句,需要人工编写。
轻量级架构结合Struts、Spring、Ibatis ,充分发挥了三者的优点, 基于轻量级框架的
J2EE
架构开发简洁、结构清晰,有很好的可扩展性和可维护性,非常适于面向对象的设计与开发。