问题
随着轻量级持久化框架的流行(如:Hibernate,JDO,JPA),领域对象取代了传统的DTO直接作为值对象,而在这种架构应用的开发过程中,开发人员常会遇见这样的异常LazyInitializationException。上述问题是由于Hibernate对于领域对象的关系域对象采取了懒加载策略所导致的(即在关系域被访问时才真正加载创建这些相关对象,Hibernate提供的懒加载策略在很多时候都可以让我的程序获得更高的效率);由于领域对象在脱管的状态下被作为值对象传回显示层,而显示层如果访问了采用懒加载策略加载的关系域,便会导致LazyInitializationException异常。
为了避免这个问题,我们常常会在Façade层的业务方法中加入与特定显示要求相绑定的返回对象初始化过程(即装载那些被懒加载了的关系域对象)。Façade通常是我们用于控制事务边界和完成返回的领域对象脱钩的地方。
1 表现层是易变的这样就会导致连锁反应,大量的代码需要维护,完全违背了面向对象设计的原则,增加了程序的维护成本。
2 并且Façade可能用于支持多种不同的表现层,很难让一个方法满足不同的要求。
OSIV(Open Session in View)结构是一种解决上述问题的方法,这种结构之所以能解决上述问题关键就在于OSIV在表现层中控制Session的打开和关闭,控制事务边界。OSIV虽然简化了应用程序的结构,也避免了LazyInitializationException问题,但是也有很多不足:1.增加了表示层的负责度,2.在响应返回表示层前必须提交事务。3.由于减少了封装层次,表现层直接操作领域对象使得包括性能方面的各种优化更为困难。
解决方案
思考既然表示层知道要显示的信息,即领域对象应该加载哪些相关联的对象。那么我们何不把这个任务交给Façade的调用者(表现层)来完成呢?
不同的表示层可能会有不同的显示策略,利用策略模式(GoF)我们让表示层来注入所需的关系域加载策略实现。
下面便是这个想法的实现:
示例中的领域模型:
图表
1 示例中领域对象模型
示例中相关的组件
图表
2 示例相关组件
LazyObjectLoader:懒对象加载者接口,其定义如下
来对象加载策略接口
package
org.ccsoft;
public
interface
LazyObjectLoader {
public
void
loadLazyObjects(Object obj);
}
该接口定义了不同懒对象加载策略实现者要实现的方法,在
loadLazyObjects
方法中实现对领域对象
obj
相关的关系域对象进行加载的策略。
OrderItemLoader
一种加载策略的实现
,
用于加载
Order
对象的关系域对象
OrderItem
对象
package
org.ccsoft;
import
java.io.Serializable;
public
class
OrderItem
implements
Serializable {
private
String
detail
;
public
String getDetail() {
return
detail
;
}
public
void
setDetail(String detail) {
this
.
detail
= detail;
}
}
OrderMgrFacadeImp: Façade的实现,可以使POJO也可以使Session Bean
package
org.ccsoft;
public
class
OrderMgrFacadeImp
implements
OrderMgrFacade {
private
OrderDAO
orderDAO
;
public
OrderDAO getOrderDAO() {
return
orderDAO
;
}
public
void
setOrderDAO(OrderDAO orderDAO) {
this
.
orderDAO
= orderDAO;
}
public
Order getOrder(
int
orderId, LazyObjectLoader loader) {
Order order=
orderDAO
.getOrder(orderId);
loader.loadLazyObjects(order);
return
order;
}
}
在getOrder方法中我们要求调用者提供了懒对象装载策略的实例用于装载那些调用者要用到的关系域对象。注意该示例是通过spring实现的,利用spring AOP完成事务管理,事务的边界在Façade中方法上,当方法执行结束,事务业务将结束,并且Hibernate会自动关闭session,我们看到getOrder方法中在事务结束前调用了懒对象装载策略,从而按照调用者的要求装载了调用者所需的关系域对象。
该模式的优点
1 将领域对象的处理逻辑与显示层的显示逻辑完全分离,提高了代码的可维护性和可扩展性
该模式的不足
1 要求显示层的开发者,了解懒加载的情况
2 增加了代码的复杂性
————————————————————————————————————
蔡 超
SCEA , SCBCD , MCSD
IBM Certified Specialist RUP
IBM Certified Solution Designer OOA&D UML v2
北京天融信软件架构师
SUN,Microsoft培训中心特邀高端教师
常年提供架构咨询服务
chaocai2001@yahoo.com.cn , 010-82776427