下面是HibernateSessionFactory
和 HibernateTransactionManager
:的配置:
<bean id="mySessionFactory"
class="org.springframework.orm.hibernate.
LocalSessionFactoryBean">
<property name="mappingResources">
<list>
<value>
com/meagle/bo/Order.hbm.xml
</value>
<value>
com/meagle/bo/OrderLineItem.hbm.xml
</value>
</list>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">
net.sf.hibernate.dialect.MySQLDialect
</prop>
<prop key="hibernate.show_sql">
false
</prop>
<prop key="hibernate.proxool.xml">
C:/MyWebApps/.../WEB-INF/proxool.xml
</prop>
<prop key="hibernate.proxool.pool_alias">
spring
</prop>
</props>
</property>
</bean>
<!-- Transaction manager for a single Hibernate
SessionFactory (alternative to JTA) -->
<bean id="myTransactionManager"
class="org.
springframework.
orm.
hibernate.
HibernateTransactionManager">
<property name="sessionFactory">
<ref local="mySessionFactory"/>
</property>
</bean>
可以看出:每個對象都可以在Spring 配置信息中用<bean>標簽引用。在這里,mySessionFactory
引用了
HibernateSessionFactory
,而
myTransactionManager
引用了
HibernateTransactionManage
。
注意代碼中
myTransactionManger Bean
有個
sessionFactory
屬性。
HibernateTransactionManager
有個sessionFactory
setter 和 getter方法,這是用來在Spring啟動的時候實現“依賴注入” (dependency injection)的。 在sessionFactory
屬性里 引用mySessionFactory
。這兩個對象在Spring容器初始化后就被組裝了起來了。 這樣的搭配讓你從 單例(singleton objects)和工廠(factories)中解放了出來,降低了代碼的維護代價。 mySessionFactory
.的兩個屬性,分別是用來注入mappingResources
和 hibernatePropertes
的。通常,如果你在
Spring
之外使用
Hibernate,
這樣的設置應該放在
hibernate.cfg.xml中的。 不管怎樣,Spring提供了一個便捷的方式-----在Spring內部配置中并入了Hibernate的配置。 如果要得到更多的信息,可以查閱Spring API。
既然我們已經組裝配置好了Service Beans,就需要把Business Service Object和 DAO也組裝起來,并把這些對象配到一個事務管理器(transaction manager)里。
在Spring中的配置信息:
<!-- ORDER SERVICE -->
<bean id="orderService"
class="org.
springframework.
transaction.
interceptor.
TransactionProxyFactoryBean">
<property name="transactionManager">
<ref local="myTransactionManager"/>
</property>
<property name="target">
<ref local="orderTarget"/>
</property>
<property name="transactionAttributes">
<props>
<prop key="find*">
PROPAGATION_REQUIRED,readOnly,-OrderException
</prop>
<prop key="save*">
PROPAGATION_REQUIRED,-OrderException
</prop>
</props>
</property>
</bean>
<!-- ORDER TARGET PRIMARY BUSINESS OBJECT:
Hibernate implementation -->
<bean id="orderTarget"
class="com.
meagle.
service.
spring.
OrderServiceSpringImpl">
<property name="orderDAO">
<ref local="orderDAO"/>
</property>
</bean>
<!-- ORDER DAO OBJECT -->
<bean id="orderDAO"
class="com.
meagle.
service.
dao.
hibernate.
OrderHibernateDAO">
<property name="sessionFactory">
<ref local="mySessionFactory"/>
</property>
</bean>
圖4 是我們對象搭建的一個提綱。 從中可以看出,每個對象都聯系著Spring,并且能通過Spring注入到其他對象。把它與Spring的配置文件比較,觀察他們之間的關系

圖 4. Spring就是這樣基于配置文件,將各個Bean搭建在一起。
這個例子使用一個TransactionProxyFactoryBean
,它定義了一個
setTransactionManager()
。
這對象很有用,他能很方便的處理你申明的事物還有
Service Object
。
你可以通過
transactionAttributes
屬性來定義怎樣處理。
想知道更多還是參考
TransactionAttributeEditor
吧。
TransactionProxyFactoryBean
還有個setter. 這會被我們 Business service object(orderTarget
)引用, orderTarget
定義了
業務服務層,并且它還有個屬性,由
setOrderDAO()
引用。這個屬性
Spring 和Bean 的還有一點要注意的: bean可以以用兩種方式創造。 這些都在單例模式(Sington)和原型模式(propotype)中定義了。 默認的方式是singleton,這意味著共享的實例將被束縛。 而原形模式是在Spring用到bean的時候允許新建實例的。當每個用戶需要得到他們自己Bean的Copy時,你應該僅使用prototype模式。(更多的請參考設計模式中的單例模式和原形模式)
提供一個服務定位器(Providing a Service Locator)
既然我們已經將我們的Serices和DAO搭配起來了。我們需要把我們的Service顯示到其他層。 這個通常是在Struts或者Swing這層里編碼。一個簡單方法就是用 服務定位器返回給Spring context 。當然,可以通過直接調用Spring中的Bean來做。
下面是一個Struts Actin 中的服務定位器的一個例子。
public abstract class BaseAction extends Action {
private IOrderService orderService;
public void setServlet(ActionServlet
actionServlet) {
super.setServlet(actionServlet);
ServletContext servletContext =
actionServlet.getServletContext();
WebApplicationContext wac =
WebApplicationContextUtils.
getRequiredWebApplicationContext(
servletContext);
this.orderService = (IOrderService)
wac.getBean("orderService");
}
protected IOrderService getOrderService() {
return orderService;
}
}
UI 層配置 (UI Layer Configuration)
這個例子里UI層 使用了Struts framework. 這里我們要講述一下在給程序分層的時候, 哪些是和Struts部分的。我們就從一個Struts-config.xml文件中的Action的配置信息開始吧。
struts-config.xml
file.
<action path="/SaveNewOrder"
type="com.meagle.action.SaveOrderAction"
name="OrderForm"
scope="request"
validate="true"
input="/NewOrder.jsp">
<display-name>Save New Order</display-name>
<exception key="error.order.save"
path="/NewOrder.jsp"
scope="request"
type="com.meagle.exception.OrderException"/>
<exception key="error.order.not.enough.money"
path="/NewOrder.jsp"
scope="request"
type="com.
meagle.
exception.
OrderMinimumAmountException"/>
<forward name="success" path="/ViewOrder.jsp"/>
<forward name="failure" path="/NewOrder.jsp"/>
</action>
SaveNewOrder 這個Action是用來持久化UI層里的表單提交過來Order的。這是Struts中一個很典型的Action; 注意觀察這個Action中exception配置,這些Exceptions也在Spring 配置文件(applicationContext-hibernate.xml)中配置了(就在 business service object 的transactionAttributes
屬性里)。 當異常在業務層被被拋出時,我們可以控制他們,并適當的顯示給UI層。
第一個異常,OrderException,在持久層保存order對象失敗的時候被觸發。這將導致事物回滾并且通過BO把異常回傳到Struts這一層。
第二個異常,OrderMinimumAmountException
也同第一個一樣。
搭配整和的最后一步 通過是讓你顯示層和業務層相結合。這個已經被服務定位器(service locator)實現了(前面討論過了), 這里服務層作為一個接口提供給我們的業務邏輯和持久層。
SaveNewOrder Action
在Struts中用一個服務定位器(service locator)來調用執行業務方法的。 方法代碼如下:
public ActionForward execute(
ActionMapping mapping,
ActionForm form,
javax.servlet.http.HttpServletRequest request,
javax.servlet.http.HttpServletResponse response)
throws java.lang.Exception {
OrderForm oForm = (OrderForm) form;
// Use the form to build an Order object that
// can be saved in the persistence layer.
// See the full source code in the sample app.
// Obtain the wired business service object
// from the service locator configuration
// in BaseAction.
// Delegate the save to the service layer and
// further upstream to save the Order object.
getOrderService().saveNewOrder(order);
oForm.setOrder(order);
ActionMessages messages = new ActionMessages();
messages.add(
ActionMessages.GLOBAL_MESSAGE,
new ActionMessage(
"message.order.saved.successfully"));
saveMessages(request, messages);
return mapping.findForward("success");
}
總結
這篇文章在技術和構架方面掩蓋了很多低層的基礎信息, 文章的主要的意圖在于讓你意識到如何給你應用程序分層。 分層可以“解耦”你的代碼——允許新的組件被添加進來,而且讓你的代碼易于維護。 這里用到的技術只是專注于把“解偶”做好。 不管怎樣,使用這樣的構架可以讓你用其他技術代替現在的層。 例如,你可能不使用Hibernate實現持久化。既然你在DAO中面向接口的編程的,所以你完全可以用iBATIS來代替。或者,你也可能想用Struts外的其他的技術或者框架替換現在的UI層(轉換久層,實現層并不應該直接影響到你的業務邏輯和業務服務層)。 用適當的框架搭建你的Web應用,其實也不是一件煩瑣的工作,更主要的是它“解耦”了你程序中的各個層。
后記:
看完這篇文章后,只是覺得很喜歡,于是就翻譯了,當然同時也準備著挨大家扔來的雞蛋:)。
這篇文章里并沒有太多的技術細節,和詳細的步驟。如果你從未使用過這些框架而在運行實例程序遇上困難的話,可以到CSDN論壇Java Open Source版發貼,我一定會詳細解答的(啊哦,這不算做廣告吧?),
文章是從一個構架的角度講述了如何搭配現有的開源框架進行分層, 有太多的術語我都不知道怎么表達,而且可能有很多語句存在錯誤。如果影響了你的閱讀,請你直接點原文地址,我同時也象你說聲抱歉。
作者簡介:Mark Eagle 高級軟件工程師,亞特蘭大。