基于J2EE輕量級架構(gòu)的多層應(yīng)用的研究 (轉(zhuǎn)載自http://www.aygfsteel.com/caoqingsong/archive/2006/06/16/53158.html)
?
1? ? J2EE 多層應(yīng)用分析
1.1? ???????
J2EE
層次結(jié)構(gòu)
J2EE
的三層結(jié)構(gòu)在業(yè)界是指表示層
(Presentation)
,業(yè)務(wù)邏輯層
(Business logic)
以及基礎(chǔ)架構(gòu)層
(Infrastructure)
。這樣的劃分當(dāng)然是經(jīng)典的,但是在實際項目中,往往會對三層體系結(jié)構(gòu)做一些擴(kuò)展來滿足項目的需要。一個最常用的擴(kuò)展就是將三層體系擴(kuò)展為五層體系,即表示層
(Presentation)
、控制
/
中介層
(Controller/Mediator)
、領(lǐng)域?qū)?/span>
(Domain)
、 數(shù)據(jù)持久層
(Data Persistence)
和數(shù)據(jù)源層
(Data Source)
。它其實是在三層架構(gòu)中增加了兩個中間層??刂?/span>
/
中介層位于表示層和領(lǐng)域?qū)又g,數(shù)據(jù)持久層位于領(lǐng)域?qū)雍突A(chǔ)架構(gòu)層之間。而輕量級架構(gòu)
Struts + Spring + Ibatis
可以實現(xiàn)J2EE多層結(jié)構(gòu),Struts 用于表示層、控制層,Spring 用于業(yè)務(wù)處理層,而Ibatis 用于數(shù)據(jù)持久層。
1.2? ???????
Struts
框架
Struts
是一個基于Sun J2EE平臺的MVC框架,主要是采用Servlet和JSP技術(shù)來實現(xiàn)的。是開發(fā)Web應(yīng)用程序的開放源碼的Framework。Struts把Servlet、JSP、自定義標(biāo)簽和信息資源(message resources)整合到一個統(tǒng)一的框架中,開發(fā)人員利用其進(jìn)行開發(fā)時不用再自己編碼實現(xiàn)全套MVC模式,極大的節(jié)省了時間,Struts包括如下的主要功能:
☆
?
包含一個controller servlet,能將用戶的請求發(fā)送到相應(yīng)的Action對象。
☆
?
JSP
自由tag庫,并且在controller servlet中提供關(guān)聯(lián)支持,幫助開發(fā)員創(chuàng)建交互式表單應(yīng)用。
☆
?
提供了一系列實用對象:XML處理、通過Java reflection APIs自動處理JavaBeans屬性、國際化的提示和消息
。
1.3? ???????
Spring
框架
Spring
是一個目前非常活躍的開源項目;它是一個基于IoC(Inversion of Control)和AOP(Aspect-Oriented Programming)的,輕量級的,多層j2ee系統(tǒng)的框架,但它不強迫你必須在每一層中必須使用Spring,它模塊化的很好,允許你根據(jù)自己的需要選擇使用它的某一個模塊;它實現(xiàn)了很優(yōu)雅的MVC
,對不同的數(shù)據(jù)訪問技術(shù)提供了統(tǒng)一的接口,采用IoC使得可以很容易的實現(xiàn)bean的裝配,提供了簡潔的AOP并據(jù)此實現(xiàn)Transcation Managment,等等
[ 1 ]
。
Spring
雖然提供了MVC Web框架的解決方案,但是也能與其他的web框架相結(jié)合使用,如struts、Webwork、JFS等。Spring也可以與其他持久層結(jié)構(gòu)相結(jié)合,如:jdbc、Hibernate、Ibatis等,能夠使用AOP的技術(shù)提供事務(wù)處理等功能
。?
1.4? ???????
數(shù)據(jù)關(guān)系映射
Ibatis
Ibatis
提供了ORM機制,對業(yè)務(wù)邏輯實現(xiàn)人員而言,面對的是純粹的Java對象, 這一層與通過Hibernate 實現(xiàn)ORM 而言基本一致,而對于具體的數(shù)據(jù)操作,Hibernate 會自動生成SQL 語句,而Ibatis 則要求開發(fā)者編寫具體的SQL 語句。相對Hibernate等 “全自動”O(jiān)RM機制而言,Ibatis 以SQL開發(fā)的工作量和數(shù)據(jù)庫移植性上的讓步,為系統(tǒng)設(shè)計提供了更大的自由空間。作為“全自動”O(jiān)RM 實現(xiàn)的一種有益補充,Ibatis 的出現(xiàn)顯得別具意義
[ 2 ]
。
2? ? J2EE 輕量級架構(gòu)
2.1? ??????? 架構(gòu)
?
?????????????????????????????????????????????????????????????????????????????????????????????
???????????????????????????????????????????????????????????????????????????????????????????????? 圖1? 框架示意圖
2.2? ???????
View
層
在視圖層主要使用Struts結(jié)構(gòu)的技術(shù)。
☆
TagLib
在jsp的前端頁面中使用Struts提供的標(biāo)簽完成頁面數(shù)據(jù)邏輯的組織與顯示。如(html,bean,logic等)
☆
國際化的消息處理功能
在jsp頁面中不出現(xiàn)特定語言的字符串描述,將這些統(tǒng)一的字符串信息統(tǒng)一的提取到文件中,通過Struts的Bean標(biāo)簽提取。便于整個系統(tǒng)的語言變更與組織。
☆
界面組合功能Tiles
頁面中將使用Struts的技術(shù),統(tǒng)一組織頁面的結(jié)構(gòu),便于系統(tǒng)改版、維護(hù)。
2.3? ???????
Control
層
控制層中依然使用Struts結(jié)構(gòu)。此層將接受、處理View發(fā)送的請求,在對信息初步的驗證、處理后,將把此請求委派給后端的業(yè)務(wù)處理層去處理。等待業(yè)務(wù)處理完成之后,將把處理結(jié)果傳遞給View層進(jìn)行表現(xiàn)。
2.4? ???????
業(yè)務(wù)處理層
在該層中使用Service模式,提供給Control層必要的處理方法。
在接收到Control層的業(yè)務(wù)處理請求后,按照業(yè)務(wù)規(guī)范、算法對數(shù)據(jù)進(jìn)行處理。將處理結(jié)果返回給Control層。
2.5? ???????
數(shù)據(jù)訪問層
本層屬于低級的數(shù)據(jù)處理層,將完成具體的數(shù)據(jù)處理工作,如數(shù)據(jù)的增加,更新,查詢,刪除等。
本層使用DAO(Data Access Object)的設(shè)計模式
[ 3 ]
,屏蔽多數(shù)據(jù)庫對上層應(yīng)用的影響,并使用Ibatis的ORMapping技術(shù),降低數(shù)據(jù)操作的復(fù)雜程度。
3? ? 數(shù)據(jù)持久層解決方案
3.1? ??????????
數(shù)據(jù)持久層
將數(shù)據(jù)持久單獨作為
J2EE
體系一個層提出來,表面上是因為數(shù)據(jù)持久性是企業(yè)實際開發(fā)中比較棘手的一個方面,數(shù)據(jù)持久層設(shè)計的成功與否往往對項目起著至關(guān)重要的影響,單獨將其提出來以便在開發(fā)中能夠避免它的設(shè)計草率。究其最深刻的內(nèi)因,則是在對象范例和關(guān)系范例這兩大領(lǐng)域之間“阻抗不匹配”。對象范例基于軟件工程的一些原理,例如耦合、聚合和封裝,而關(guān)系范例則基于數(shù)學(xué)原理,特別是集合論的原理。兩種不同的理論基礎(chǔ)導(dǎo)致各自有不同的優(yōu)缺點。而且,對象范例側(cè)重于從包含數(shù)據(jù)和行為的對象中構(gòu)建應(yīng)用程序,而關(guān)系范例則主要針對數(shù)據(jù)的存儲。當(dāng)為訪問而尋找一種合適的方法時,“阻抗不匹配”就成了主要矛盾:使用對象范例,通過它們的關(guān)系來訪問對象,而使用關(guān)系范例,則通過復(fù)制數(shù)據(jù)來連接表中的行。這種基本的差異導(dǎo)致兩種范例的結(jié)合并不理想,于是有人提出對象數(shù)據(jù)庫以希望解決這個問題。但是,關(guān)系數(shù)據(jù)庫技術(shù)已經(jīng)發(fā)展得相當(dāng)成熟,占據(jù)了數(shù)據(jù)庫市場
90
%以上的份額,對象數(shù)據(jù)庫的普及尚需時日。數(shù)據(jù)持久層就是要在對象-關(guān)系數(shù)據(jù)庫之間提供一個成功的企業(yè)級別的映射解決方案,盡最大可能彌補這兩種范例之間的差異。
3.2? ??????????
J2EE
體系解決方案
3.2.1?
???
EJB
CMP (
容器管理持久
)
實體
Bean
,提供健壯的數(shù)據(jù)持久性。
Bean
容器處理大部分的數(shù)據(jù)完整性、資源管理和并發(fā)性功能,從而使開發(fā)人員關(guān)注業(yè)務(wù)邏輯和數(shù)據(jù)處理,而不是這些低級細(xì)節(jié)。使用
Bean
管理的持久性
(Bean Managed Persistence
,
BMP)
實體
Bean
時,開發(fā)人員編寫持久性代碼而容器確定何時執(zhí)行該代碼。使用容器管理的持久性??
( Container Managed Persistence
,
CMP)
實體
Bean
時,容器生成持久性代碼并管理持久性邏輯
[ 4 ]
。
3.2.2?
???
JDO
Java
數(shù)據(jù)對象
(JDO)
是一個存儲
Java
對象的規(guī)范
[ 5 ]
。它已經(jīng)被
JCP
組織定義成
JSR12
規(guī)范。規(guī)范的兩個主要目的是提供數(shù)據(jù)處理和訪問機制的
API
以及允許規(guī)范的實現(xiàn)作為應(yīng)用服務(wù)器的一部分。
Java
數(shù)據(jù)對象是最新的持久性規(guī)范。
JDO
提供了面向?qū)ο蟮某志脭?shù)據(jù)存儲。開發(fā)人員使用
POJO(
無格式普通
Java
對象,
Plain Ordinary Java Object)
來裝入和存儲持久數(shù)據(jù)。
3.2.3?
???
ORM
ORM
具有自我存儲到關(guān)系數(shù)據(jù)庫的能力,對對象的改變能夠直接得以存儲,而不考慮數(shù)據(jù)庫存取代碼。這樣,把全部精力集中到對對象和類進(jìn)行編程,解決業(yè)務(wù)問題。在整個系統(tǒng)中除了這一個層次,沒有一句數(shù)據(jù)庫存取代碼。其中,
Hibernate
、Ibatis等
作為
ORM
中最好的開源工具,受到數(shù)量眾多的程序員的擁護(hù)。
4? ? 基于輕量級架構(gòu)的應(yīng)用案例分析
某大型水利信息系統(tǒng)需要使用
J2EE
平臺以滿足分布式處理、事務(wù)管理和安全的要求,
使整個軟件呈現(xiàn)分層的體系結(jié)構(gòu),支持多種數(shù)據(jù)庫的擴(kuò)展,支持多語言界面的調(diào)整,支持頁面整體布局的可擴(kuò)展性調(diào)整。封裝業(yè)務(wù)邏輯,使得在外部條件變化時,將影響盡可能的降低,即采用了基于J2EE的輕量級架構(gòu)。圖2是信息系統(tǒng)的體系結(jié)構(gòu),圖3是系統(tǒng)包結(jié)構(gòu)
??????????????????????????????????
圖2? 體系結(jié)構(gòu)圖
圖3? 系統(tǒng)包結(jié)構(gòu)
圖3中箭頭表示軟件包之間的依賴關(guān)系。獨立的包會被Spring、struts、Ibatis框架結(jié)構(gòu)間接的與其他軟件包關(guān)聯(lián)。
4.1? ??????????
系統(tǒng)剖析
4.1.1?
???
包結(jié)構(gòu)描述
☆
com.water.query.dao
:該包內(nèi)的類將引入Ibatis的重要組件,使系統(tǒng)能夠感知功能操作的接口與接口實現(xiàn)類的關(guān)系,這些信息是Ibatis自動映射的前提條件之一。
☆
com.water.query.dao.sqlmapdao
:該包是數(shù)據(jù)訪問的核心,使用Spring結(jié)構(gòu)的數(shù)據(jù)層功能引進(jìn)對Ibatis的支持
☆
com.water.query.dao.iface
:該包規(guī)定了所有業(yè)務(wù)的訪問接口,只有在此包的接口中定義的方法才會被用戶使用。是本系同中所有原子數(shù)據(jù)操作的定義點。
☆
Ibatis
:該包是由Ibatis數(shù)據(jù)存儲層結(jié)構(gòu)定義。由支持機構(gòu)提供支持。
☆
com.water.query.dao.sqlmapdao.sql
:該包定義了所有操作的SQL(Sequence Query Language)語句,以及SQL語句與具體值對象的映射關(guān)系。
☆
com.water.query.form
:該包定義了本系統(tǒng)中用于數(shù)據(jù)傳輸?shù)念?。這些類實例是Web界面層與業(yè)務(wù)邏輯實現(xiàn)層之間的橋梁,起著傳輸數(shù)據(jù)的功能。
☆
com.water.query.service
: 該包是本系統(tǒng)引入Spring結(jié)構(gòu)的入口點。通過該入口,系統(tǒng)中其他成員可以通過IoC(依賴倒轉(zhuǎn))功能訪問具體業(yè)務(wù)的Service對象。
☆
com.water.query.condition
:該包內(nèi)定義了一系列簡單JavaBean,這些JavaBean將攜帶SQL需要的參數(shù)穿行于軟件的Control層與Model層之間。
☆
com.water.log
:該包中定義了本系統(tǒng)使用的log組件。
☆
com.water.query.domain.baseinfo
:該包定義了所有基本信息查詢模塊將要使用的數(shù)據(jù)傳輸類。
4.1.2?
???
控制層
在視圖層和控制層中采用了Struts框架,在傳統(tǒng)的Struts用法中,我們一般都有幾個Action Bean和相應(yīng)的form bean ,但在此設(shè)計中并不拘泥于Struts的傳統(tǒng)固定用法,這里只用了一個自定義Action類,并且在form bean類的定義上也是創(chuàng)新的。
非傳統(tǒng)的Struts開發(fā)模式,關(guān)鍵就在Struts Action類和form bean類上。Struts Action類只有一個:BeanAction,這與傳統(tǒng)的struts編程方式很不同。BeanAction類是一個通用類,利用反射原理
[ 6 ]
,根據(jù)URL來決定調(diào)用form bean的哪個方法。BeanAction大大簡化了struts的編程模式,降低了對struts的依賴。利用這種模式,我們會很容易的把它移植到新的框架如JSF,Spring。
這樣重心就轉(zhuǎn)移到form bean上了,它已經(jīng)不是普通意義上的form bean了。它不僅僅有數(shù)據(jù)和校驗/重置方法,而且已經(jīng)具有了行為,從這個意義上來說,它更像一個BO(Business Object),Struts-config.xml的配置里有3種映射方式,來告訴BeanAction把控制轉(zhuǎn)到哪個form bean對象的哪個方法來處理。form bean的這些方法的簽名很簡單,例如:
public String myActionMethod(){
?
???????????????????
?//..work
???????????????????
??return "success";
?}
方法的返回值直接就是字符串,對應(yīng)的是forward的名稱,而不再是ActionForward對象,創(chuàng)建ActionForward對象的任務(wù)已經(jīng)由BeanAction類代勞了。
4.1.3?
???
業(yè)務(wù)層
利用Spring Framework 的BeanFactory機制,采用自定義的工具類(bean工廠類)來加載spring的配置文件,從中可以看出Spring有多靈活,它提供了各種不同的方式來使用其不同的部分/層次,您只需要用你想用的,不需要的部分可以不用。
具體的來說,創(chuàng)建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類用于表現(xiàn)層的form bean對象獲得service類的對象。
4.1.4?
???
數(shù)據(jù)持久層的配置
4.1.4.1?
????
Spring
配置文件
Spring
在設(shè)計時就充分考慮到了與Struts的協(xié)同工作,并且對Ibatis 有很好的支持,在此輕量級架構(gòu)中,不需要對Ibatis單獨進(jìn)行配置,只需對 Spring 進(jìn)行配置就以足夠。以下就是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
節(jié)點
sqlMapClient
節(jié)點實際上配置了一個
sqlMapClient
的創(chuàng)建工廠類。
configLocation
屬性配置了
ibatis
映射文件的名稱。
2
.
transactionManager
節(jié)點
transactionManager
采用了
Spring
中的
DataSourceTransactionManager
。
3
.
userDAO
節(jié)點
對應(yīng)的,
UserDAO
需要配置兩個屬性,
sqlMapClient
和
DataSource
,
sqlMapClient
將從指定的
DataSource
中獲取數(shù)據(jù)庫連接。
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
的輔助類,它負(fù)責(zé)調(diào)度
DataSource
、
SqlMapClientTemplate
完成
ibatis
操作,而
DAO
則通過對此類進(jìn)行擴(kuò)展獲得上述功能。上面配置文件中針對
UserDAO
的屬性設(shè)置部分,其中的屬性也是繼承自于這個基類。
SqlMapClientTemplate
對傳統(tǒng)
SqlMapClient
調(diào)用模式進(jìn)行了封裝,簡化了上層訪問代碼。
5? ? 總結(jié)
從軟件層次結(jié)構(gòu)的角度來說,軟件的框架要具有較高的伸縮性和可擴(kuò)展性,本文所討論的J2EE輕量級架構(gòu),由于它采用了Struts框架,因而它的模塊化設(shè)計得到了很好的應(yīng)用,層次非常清晰,具有很好的可復(fù)用度,但是,同時,此架構(gòu)存在可伸縮性問題,
架構(gòu)
中明顯存在可伸縮性問題的設(shè)計是
Action
。控制器
ActionServlet
對每個
Action
類只創(chuàng)建一個實例
,
所有對該
Action
類的請求都用這個實例進(jìn)行處理
,
因此
,
它是無狀態(tài)的、多線程共享的。這意味著
Action
實例的數(shù)量是一個常數(shù)
,
不能隨工作量增加而增加。此外,
反射的利用是對架構(gòu)擴(kuò)展的一個有益嘗試,雖然提供了非常好的應(yīng)用開發(fā)模式,但是它還非常新,一直在發(fā)展中。數(shù)據(jù)持久層中,Ibatis的應(yīng)用給人一種耳目一新的感覺,但它也存在著一些不足之處,例如相對于Hibernate ,Ibatis不能直接生成sql語句,需要人工編寫。
輕量級架構(gòu)結(jié)合Struts、Spring、Ibatis ,充分發(fā)揮了三者的優(yōu)點, 基于輕量級框架的
J2EE
架構(gòu)開發(fā)簡潔、結(jié)構(gòu)清晰,有很好的可擴(kuò)展性和可維護(hù)性,非常適于面向?qū)ο蟮脑O(shè)計與開發(fā)。
posted on 2006-06-16 11:20 nbt 閱讀(851) 評論(1) 編輯 收藏 所屬分類: Java2EE