??xml version="1.0" encoding="utf-8" standalone="yes"?>久久久国产精品一区二区三区,亚洲精品视频免费观看,亚洲精品在线a http://www.aygfsteel.com/xixidabao/category/15380.htmlGROW WITH JAVA zh-cn Sat, 21 Apr 2007 02:48:12 GMT Sat, 21 Apr 2007 02:48:12 GMT 60 ?Spring 更好地处?Struts 动作三种整合 Struts 应用E序?Spring 的方?/title> http://www.aygfsteel.com/xixidabao/archive/2007/04/21/112404.htmlJAVA之\ JAVA之\ Sat, 21 Apr 2007 02:43:00 GMT http://www.aygfsteel.com/xixidabao/archive/2007/04/21/112404.html Z?Spring q么了不P
Spring 的创立?Rod Johnson 以一U批判的眼光看待 Java™ 企业软g开发,q且提议很多企业N都能够通过战略C?IOC 模式Q也UC依赖注入Q来解决。当 Rod 和一个具有奉献精的开放源码开发者团队将q个理论应用于实跉|Q结果就产生?Spring 框架。简a之,Spring 是一个轻型的容器Q利用它可以使用一个外?XML 配置文g方便地将对象q接在一赗每个对象都可以通过昄一?JavaBean 属性收C个到依赖对象的引用,留给您的单Q务就只是在一?XML 配置文g中把它们q接好?/p>
IOC ?Spring
IOC 是一U应用E序逻辑外在化的设计模式Q所以它是被注入而不是被写入客户Z码中。将 IOC 与接口编E应用结合,像 Spring 框架那样Q生了一U架构,q种架构能够减少客户机对特定实现逻辑的依赖。请参阅 参考资?/u> 了解更多关于 IOC ?Spring 的信息?/p>
依赖注入是一个强大的Ҏ,但是 Spring 框架能够提供更多Ҏ。Spring 支持可插拔的事务理器,可以l您的事务处理提供更q泛的选择范围。它集成了领先的持久性框Ӟq且提供一个一致的异常层次l构。Spring q提供了一U用面向方面代码代替正常的面向对象代码的简单机制?/p>
Spring AOP 允许您?em>拦截?/em> 在一个或多个执行点上拦截应用E序逻辑。加强应用程序在拦截器中的日志记录逻辑会生一个更可读的、实用的代码基础Q所以拦截器q泛用于日志记录。您很快׃看到Qؓ了处理横切关注点QSpring AOP 发布了它自己的拦截器Q您也可以编写您自己的拦截器?/p>
整合 Struts ?Spring
?Struts 怼QSpring 可以作ؓ一?MVC 实现。这两种框架都具有自q优点和缺点,管大部分h同意 Struts ?MVC 斚w仍然是最好的。很多开发团队已l学会在旉紧迫的时候利?Struts 作ؓ构造高品质软g的基。Struts h如此大的推动力,以至于开发团队宁愿整?Spring 框架的特性,而不愿意转换?Spring MVC。没必要q行转换Ҏ来说是一个好消息。Spring 架构允许您将 Struts 作ؓ Web 框架q接到基?Spring 的业务和持久层。最后的l果是现在一切条仉具备了?/p>
在接下来的小H门中,您将会了解到三种?Struts MVC 整合?Spring 框架的方法。我揭C每U方法的~陷q且Ҏ它们的优炏V?一旦您了解到所有三U方法的作用Q我会向您展示一个o人兴奋的应用E序Q这个程序用的是这三种Ҏ中我最喜欢的一U?/p>
三个窍?/font>
接下来的每种整合技术(或者窍门)都有自己的优点和特点。我偏爱其中的一U,但是我知道这三种都能够加深您?Struts ?Spring 的理解。在处理各种不同情况的时候,q将l您提供一个广阔的选择范围。方法如下:
使用 Spring ?ActionSupport
cL?Structs
使用 Spring ?DelegatingRequestProcessor
覆盖 Struts ?RequestProcessor
?Struts Action
理委托l?Spring 框架
装蝲应用E序环境
无论您用哪U技术,都需要?Spring ?ContextLoaderPlugin
?Struts ?ActionServlet
装蝲 Spring 应用E序环境。就像添加Q何其他插件一P单地向您?struts-config.xml 文gd该插Ӟ如下所C:
<plug-in className=
"org.springframework.web.struts.ContextLoaderPlugIn">
<set-property property=
"contextConfigLocation" value="/WEB-INF/beans.xml"/>
</plug-in>
前面已经提到q,?下蝲 部分Q您能够扑ֈq三个完全可使用的例子的完整源代码。每个例子都Z个书c搜索应用程序提供一U不同的 Struts ?Spring 的整合方法。您可以在这里看C子的要点Q但是您也可以下载应用程序以查看所有的l节?/p>
H门 1. 使用 Spring ?ActionSupport
手动创徏一?Spring 环境是一U整?Struts ?Spring 的最直观的方式。ؓ了它变得更单,Spring 提供了一些帮助。ؓ了方便地获得 Spring 环境Q?code>org.springframework.web.struts.ActionSupport cL供了一?getWebApplicationContext()
Ҏ。您所做的只是?Spring ?ActionSupport
而不?Struts Action
cL展您的动作,如清?1 所C:
清单 1. 使用 ActionSupport 整合 Struts
package ca.nexcel.books.actions;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.struts.action.ActionError;
import org.apache.struts.action.ActionErrors;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;
import org.apache.struts.action.DynaActionForm;
import org.springframework.context.ApplicationContext;
import org.springframework.web.struts.ActionSupport;
import ca.nexcel.books.beans.Book;
import ca.nexcel.books.business.BookService;
public class SearchSubmit extends ActionSupport { |(1)
public ActionForward execute(
ActionMapping mapping,
ActionForm form,
HttpServletRequest request,
HttpServletResponse response)
throws IOException, ServletException {
DynaActionForm searchForm = (DynaActionForm) form;
String isbn = (String) searchForm.get("isbn");
//the old fashion way
//BookService bookService = new BookServiceImpl();
ApplicationContext ctx =
getWebApplicationContext(); |(2)
BookService bookService =
(BookService) ctx.getBean("bookService"); |(3)
Book book = bookService.read(isbn.trim());
if (null == book) {
ActionErrors errors = new ActionErrors();
errors.add(ActionErrors.GLOBAL_ERROR,new ActionError
("message.notfound"));
saveErrors(request, errors);
return mapping.findForward("failure") ;
}
request.setAttribute("book", book);
return mapping.findForward("success");
}
}
让我们快速思考一下这里到底发生了什么。在 (1) 处,我通过?Spring ?ActionSupport
c而不?Struts ?Action
c进行扩展,创徏了一个新?Action
。在 (2) 处,我?getWebApplicationContext()
Ҏ获得一?ApplicationContext
。ؓ了获得业务服务,我用在 (2) 处获得的环境?(3) 处查找一?Spring bean?/p>
q种技术很单ƈ且易于理解。不q的是,它将 Struts 动作?Spring 框架耦合在一赗如果您x换掉 SpringQ那么您必须重写代码。ƈ且,׃ Struts 动作不在 Spring 的控制之下,所以它不能获得 Spring AOP 的优ѝ当使用多重独立?Spring 环境Ӟq种技术可能有用,但是在大多数情况下,q种Ҏ不如另外两种Ҏ合适?/p>
H门 2. 覆盖 RequestProcessor
?Spring ?Struts 动作中分L一个更巧妙的设计选择。分ȝ一U方法是使用 org.springframework.web.struts.DelegatingRequestProcessor
cL覆盖 Struts ?RequestProcessor
处理E序Q如清单 2 所C:
清单 2. 通过 Spring ?DelegatingRequestProcessor q行整合
<?xml version="1.0" encoding="ISO-8859-1" ?>
<!DOCTYPE struts-config PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 1.1//EN"
"http://jakarta.apache.org/struts/dtds/struts-config_1_1.dtd">
<struts-config>
<form-beans>
<form-bean name="searchForm"
type="org.apache.struts.validator.DynaValidatorForm">
<form-property name="isbn" type="java.lang.String"/>
</form-bean>
</form-beans>
<global-forwards type="org.apache.struts.action.ActionForward">
<forward name="welcome" path="/welcome.do"/>
<forward name="searchEntry" path="/searchEntry.do"/>
<forward name="searchSubmit" path="/searchSubmit.do"/>
</global-forwards>
<action-mappings>
<action path="/welcome" forward="/WEB-INF/pages/welcome.htm"/>
<action path="/searchEntry" forward="/WEB-INF/pages/search.jsp"/>
<action path="/searchSubmit"
type="ca.nexcel.books.actions.SearchSubmit"
input="/searchEntry.do"
validate="true"
name="searchForm">
<forward name="success" path="/WEB-INF/pages/detail.jsp"/>
<forward name="failure" path="/WEB-INF/pages/search.jsp"/>
</action>
</action-mappings>
<message-resources parameter="ApplicationResources"/>
<controller processorClass="org.springframework.web.struts.
DelegatingRequestProcessor"/> |(1)
<plug-in className="org.apache.struts.validator.ValidatorPlugIn">
<set-property property="pathnames"
value="/WEB-INF/validator-rules.xml,/WEB-INF/validation.xml"/>
</plug-in>
<plug-in className="org.springframework.web.struts.ContextLoaderPlugIn">
<set-property property="csntextConfigLocation" value="/WEB-INF/beans.xml"/>
</plug-in>
</struts-config>
我利用了 <controller>
标记来用 DelegatingRequestProcessor
覆盖默认?Struts RequestProcessor
。下一步是在我?Spring 配置文g中注册该动作Q如清单 3 所C:
清单 3. ?Spring 配置文g中注册一个动?/strong>
<?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="bookService" class="ca.nexcel.books.business.BookServiceImpl"/>
<bean name="/searchSubmit"
class="ca.nexcel.books.actions.SearchSubmit"> |(1)
<property name="bookService">
<ref bean="bookService"/>
</property>
</bean>
</beans>
注意Q在 (1) 处,我用名U属性注册了一?beanQ以匚w struts-config 动作映射名称?code>SearchSubmit 动作揭示了一?JavaBean 属性,允许 Spring 在运行时填充属性,如清?4 所C:
清单 4. h JavaBean 属性的 Struts 动作
package ca.nexcel.books.actions;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.struts.action.Action;
import org.apache.struts.action.ActionError;
import org.apache.struts.action.ActionErrors;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;
import org.apache.struts.action.DynaActionForm;
import ca.nexcel.books.beans.Book;
import ca.nexcel.books.business.BookService;
public class SearchSubmit extends Action {
private BookService bookService;
public BookService getBookService() {
return bookService;
}
public void setBookService(BookService bookService) { | (1)
this.bookService = bookService;
}
public ActionForward execute(
ActionMapping mapping,
ActionForm form,
HttpServletRequest request,
HttpServletResponse response)
throws IOException, ServletException {
DynaActionForm searchForm = (DynaActionForm) form;
String isbn = (String) searchForm.get("isbn");
Book book = getBookService().read(isbn.trim()); |(2)
if (null == book) {
ActionErrors errors = new ActionErrors();
errors.add(ActionErrors.GLOBAL_ERROR,new ActionError("message.notfound"));
saveErrors(request, errors);
return mapping.findForward("failure") ;
}
request.setAttribute("book", book);
return mapping.findForward("success");
}
}
在清?4 中,您可以了解到如何创徏 Struts 动作。在 (1) 处,我创Z一?JavaBean 属性?code>DelegatingRequestProcessor自动地配|这U属性。这U设计 Struts 动作q不知道它正?Spring 理Qƈ且您能够利?Sping 的动作管理框架的所有优炏V由于您?Struts 动作注意不到 Spring 的存在,所以您不需要重写您?Struts 代码可以用其他控制反转容器来替换?Spring?/p>
DelegatingRequestProcessor
Ҏ的确比第一U方法好Q但是仍然存在一些问题。如果您使用一个不同的 RequestProcessor
Q则需要手动整?Spring ?DelegatingRequestProcessor
。添加的代码会造成l护的麻烦ƈ且将来会降低您的应用E序的灵zL。此外,q有q一些用一pd命o来代?Struts RequestProcessor
的传闅R?q种改变会对这U解x法的使用寿命造成负面的媄响?/p>
H门 3. 动作管理委托给 Spring
一个更好的解决Ҏ是将 Strut 动作理委托l?Spring。您可以通过?struts-config
动作映射中注册一个代理来实现。代理负责在 Spring 环境中查?Struts 动作。由于动作在 Spring 的控制之下,所以它可以填充动作?JavaBean 属性,qؓ应用诸如 Spring ?AOP 拦截器之cȝҎ带来了可能?
清单 5 中的 Action
cM清单 4 中的相同。但?struts-config 有一些不同:
清单 5. Spring 整合的委托方?/strong>
<?xml version="1.0" encoding="ISO-8859-1" ?>
<!DOCTYPE struts-config PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 1.1//EN"
"http://jakarta.apache.org/struts/dtds/struts-config_1_1.dtd">
<struts-config>
<form-beans>
<form-bean name="searchForm"
type="org.apache.struts.validator.DynaValidatorForm">
<form-property name="isbn" type="java.lang.String"/>
</form-bean>
</form-beans>
<global-forwards type="org.apache.struts.action.ActionForward">
<forward name="welcome" path="/welcome.do"/>
<forward name="searchEntry" path="/searchEntry.do"/>
<forward name="searchSubmit" path="/searchSubmit.do"/>
</global-forwards>
<action-mappings>
<action path="/welcome" forward="/WEB-INF/pages/welcome.htm"/>
<action path="/searchEntry" forward="/WEB-INF/pages/search.jsp"/>
<action path="/searchSubmit"
type="org.springframework.web.struts.DelegatingActionProxy" |(1)
input="/searchEntry.do"
validate="true"
name="searchForm">
<forward name="success" path="/WEB-INF/pages/detail.jsp"/>
<forward name="failure" path="/WEB-INF/pages/search.jsp"/>
</action>
</action-mappings>
<message-resources parameter="ApplicationResources"/>
<plug-in className="org.apache.struts.validator.ValidatorPlugIn">
<set-property
property="pathnames"
value="/WEB-INF/validator-rules.xml,/WEB-INF/validation.xml"/>
</plug-in>
<plug-in
className="org.springframework.web.struts.ContextLoaderPlugIn">
<set-property property="contextConfigLocation" value="/WEB-INF/beans.xml"/>
</plug-in>
</struts-config>
清单 5 是一个典型的 struts-config.xml 文gQ只有一个小的差别。它注册 Spring 代理cȝ名称Q而不是声明动作的cdQ如Q?Q处所C。DelegatingActionProxy cM用动作映名U查?Spring 环境中的动作。这是我们使用 ContextLoaderPlugIn
声明的环境?/p>
一?Struts 动作注册Z?Spring bean 是非常直观的Q如清单 6 所C。我利用动作映射使用 <bean>
标记的名U属性(在这个例子中?"/searchSubmit
"Q简单地创徏了一?bean。这个动作的 JavaBean 属性像M Spring bean 一栯填充Q?
清单 6. ?Spring 环境中注册一?Struts 动作
<?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="bookService" class="ca.nexcel.books.business.BookServiceImpl"/>
<bean name="/searchSubmit"
class="ca.nexcel.books.actions.SearchSubmit">
<property name="bookService">
<ref bean="bookService"/>
</property>
</bean>
</beans>
动作委托的优?/font>
动作委托解决Ҏ是这三种Ҏ中最好的。Struts 动作不了?SpringQ不对代码作M改变可用于?Spring 应用E序中?code>RequestProcessor 的改变不会媄响它Qƈ且它可以利用 Spring AOP Ҏ的优点?
动作委托的优点不止如此。一旦让 Spring 控制您的 Struts 动作Q您可以?Spring l动作补充更强的zd。例如,没有 Spring 的话Q所有的 Struts 动作都必LU程安全的。如果您讄 <bean>
标记?singleton 属性ؓ“false”Q那么不用何种ҎQ您的应用程序都在每一个请求上有一个新生成的动作对象。您可能不需要这U特性,但是把它攑֜您的工具׃也很好。您也可以利?Spring 的生命周期方法。例如,当实例化 Struts 动作Ӟ<bean>
标记?init-method 属性被用于q行一个方法。类似地Q在从容器中删除 bean 之前Qdestroy-method 属性执行一个方法。这些方法是理昂贵对象的好办法Q它们以一U与 Servlet 生命周期相同的方式进行管理?/p>
拦截 Struts
前面提到q,通过?Struts 动作委托l?Spring 框架而整?Struts ?Spring 的一个主要的优点是:您可以将 Spring ?AOP 拦截器应用于您的 Struts 动作。通过?Spring 拦截器应用于 Struts 动作Q您可以用最的代h处理横切x炏V?/p>
虽然 Spring 提供很多内置拦截器,但是我将向您展示如何创徏自己的拦截器q把它应用于一?Struts 动作。ؓ了用拦截器Q您需要做三g事:
创徏拦截器?
注册拦截器?
声明在何处拦截代码?
q看h非常单的几句话却非常强大。例如,在清?7 中,我ؓ Struts 动作创徏了一个日志记录拦截器?q个拦截器在每个Ҏ调用之前打印一句话Q?/p>
清单 7. 一个简单的日志记录拦截?/strong>
package ca.nexcel.books.interceptors;
import org.springframework.aop.MethodBeforeAdvice;
import java.lang.reflect.Method;
public class LoggingInterceptor implements MethodBeforeAdvice {
public void before(Method method, Object[] objects, Object o) throws Throwable {
System.out.println("logging before!");
}
}
q个拦截器非常简单?code>before() Ҏ在拦截点中每个方法之前运行。在本例中,它打印出一句话Q其实它可以做您惛_的Q何事。下一步就是在 Spring 配置文g中注册这个拦截器Q如清单 8 所C:
清单 8. ?Spring 配置文g中注册拦截器
<?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="bookService" class="ca.nexcel.books.business.BookServiceImpl"/>
<bean name="/searchSubmit"
class="ca.nexcel.books.actions.SearchSubmit">
<property name="bookService">
<ref bean="bookService"/>
</property>
</bean>
<!-- Interceptors -->
<bean name="logger"
class="ca.nexcel.books.interceptors.LoggingInterceptor"/> |(1)
<!-- AutoProxies -->
<bean name="loggingAutoProxy"
class="org.springframework.aop.framework.autoproxy.
BeanNameAutoProxyCreator"> |(2)
<property name="beanNames">
<value>/searchSubmit</valuesgt; |(3)
</property>
<property name="interceptorNames">
<list>
<value>logger</value> |(4)
</list>
</property>
</bean>
</beans>
您可能已l注意到了,清单 8 扩展?清单 6 中所C的应用E序以包含一个拦截器。具体细节如下:
?(1) 处,我注册了q个拦截器?
?(2) 处,我创Z一?bean 名称自动代理Q它描述如何应用拦截器。还有其他的Ҏ定义拦截点,但是q种Ҏ常见而简ѝ?
?(3) 处,我将 Struts 动作注册为将被拦截的 bean。如果您惌拦截其他?Struts 动作Q则只需要在 "beanNames" 下面创徏附加?<value>
标记?
?(4) 处,当拦截发生时Q我执行了在 (1) 处创建的拦截?bean 的名U。这里列出的所有拦截器都应用于“beanNames”?
是q样。就像这个例子所展示的,您?Struts 动作|于 Spring 框架的控制之下,为处理您?Struts 应用E序提供了一pd全新的选择。在本例中,使用动作委托可以L地利?Spring 拦截器提?Struts 应用E序中的日志记录能力?/p>
]]>Hibernate 的原理与配置快速入?/title> http://www.aygfsteel.com/xixidabao/archive/2006/05/17/46596.htmlJAVA之\ JAVA之\ Wed, 17 May 2006 03:46:00 GMT http://www.aygfsteel.com/xixidabao/archive/2006/05/17/46596.html 看完本文后,我相信你对什么是ORMQ对?关系映射Q以及它的优点会有一个深ȝ认识Q我们先通过一个简单的例子开始来展现它的威力?br /> 正如一些传l的l典计算机文章大都会通过一个“hello,world”的例子开始讲解一P我们也不例外Q我们也从一个相对简单的例子来阐qHibernate的开发方法,但如果要真正阐述Hibernate的一些重要思想Q仅仅靠在屏q上打印一些字W是q远不够的,在我们的CZE序中,我们创Z些对象,q将其保存在数据库中Q然后对它们q行更新和查询?br />阅读D
“Hello World?/font> “Hello world”示例程序让您对Hibernate有一个简单的认识?/strong> 理解Hibernate的架?/font> 介绍Hibernate接口的主要功能?/td> 核心接口 Hibernate?个核心接口,通过q几个接口开发h员可以存储和获得持久对象Qƈ且能够进行事务控?/td> 一个重要的术语QType Type是Hibernate发明者发明的一个术语,它在整个构架中是一个非常基、有着强大功能的元素,一个Type对象能将一个Javacd映射到数据库中一个表的字D中厅R?/td> {略接口 Hibernate与某些其它开源Y件不同的q有一点――高度的可扩展性,q通过它的内置{略机制来实现?/td> 基础配置 Hibernate可以配置成可在Q何Java环境中运行,一般说来,它通常被用?Q?层的C/S模式的项目中Qƈ被部|在服务端?/td> 创徏一个SessionFactory对象 要创Z个SessionFactory对象Q必dHibernate初始化时创徏一个Configurationcȝ实例Qƈ已写好的映文件交由它处理?/td> “Hello World?/strong> Hibernate应用E序定义了一些持久类Qƈ且定义了q些cM数据库表格的映射关系。在我们q个“Hello world”示例程序中包含了一个类和一个映文件。让我们看看q个单的持久cd含有一些什么?映射文g是怎样定义的?另外Q我们该怎样用Hibernate来操作这个持久类?br /> 我们q个单示例程序的目的是将一些持久类存储在数据库中,然后从数据库取出来,q将其信息正文显C给用户。其中Message正是一个简单的持久c:Q它包含我们要显C的信息Q其源代码如下: 列表1 Message.Java 一个简单的持久c?br />
package hello; public class Message { private Long id; private String text; private Message nextMessage; private Message() {} public Message(String text) { this.text = text; } public Long getId() { return id; } private void setId(Long id) { this.id = id; } public String getText() { return text; } public void setText(String text) { this.text = text; } public Message getNextMessage() { return nextMessage; } public void setNextMessage(Message nextMessage) { this.nextMessage = nextMessage; } }
MessagecL三个属性:Message的id 、消息正文、以及一个指向下一条消息的指针。其中id属性让我们的应用程序能够唯一的识别这条消息,通常它等同于数据库中的主键,如果多个Messagecȝ实例对象拥有相同的idQ那它们代表数据库某个表的同一个记录。在q里我们选择了长整型作ؓ我们的id|但这不是必需的。Hibernate允许我们使用L的类型来作ؓ对象的id|在后面我们会Ҏ作详l描q?br /> 你可能注意到Messagecȝ代码cM于JavaBean的代码风|q且它有一个没有参数的构造函敎ͼ在我们以后的代码中我l用这U风格来~写持久cȝ代码?br /> Hibernate会自动管理Messagecȝ实例Qƈ通过内部机制使其持久化,但实际上Message对象q没有实CQ何关于Hibernate的类或接口,因此我们也可以将它作Z个普通的JavacL使用Q?br />Message message = new Message("Hello World"); System.out.println( message.getText() );
以上q段代码正是我们所期望的结果:它打印“hello world”到屏幕上。但qƈ不是我们的最l目标;实际上Hibernate与诸如EJB容器q样的环境在持久层实现的方式上有很大的不同。我们的持久c?Messagec?可以用在与容器无关的环境中,不像EJB必须要有EJB容器才能执行。ؓ了能更清楚地表现q点Q以下代码将我们的一个新消息保存到数据库中去Q?br />Session session = getSessionFactory().openSession(); Transaction tx = session.beginTransaction(); Message message = new Message("Hello World"); session.save(message); tx.commit(); session.close();
以上q段代码调用了Hibernate的Session和Transaction接口Q关于getSessionFactory()Ҏ我们会马上提到Q。它相当于我们执行了以下SQL语句Q?br />insert into MESSAGES (MESSAGE_ID, MESSAGE_TEXT, NEXT_MESSAGE_ID) values (1, 'Hello World', null)
在以上的SQL语句中,MESSAGE_ID字段到底被初始化成了什么值呢Q由于我们ƈ没有在先前的代码中ؓmessage对象的id属性赋与初始|那它是否为null呢?实际上Hibernate对id属性作了特D处理:׃它是一个对象的唯一标识Q因此当我们q行save()调用ӞHibernate会ؓ它自动赋予一个唯一的|我们在后面内容中讲q它是如何生成这个值的Q?br /> 我们假设你已l在数据库中创徏了一个名为MESSAGE的表Q那么既然前面这D代码让我们Message对象存入了数据库中,那么现在我们p它们一一取出来。下面这D代码将按照字母序Q将数据库中的所有Message对象取出来,q将它们的消息正文打印到屏幕上:Session newSession = getSessionFactory().openSession(); Transaction newTransaction = newSession.beginTransaction(); List messages =newSession.find("from Message as m order by m.text asc"); System.out.println( messages.size() + " message(s) found:" ); for ( Iterator iter = messages.iterator(); iter.hasNext(); ) { Message message = (Message) iter.next(); System.out.println( message.getText() ); } newTransaction.commit(); newSession.close();
在以上这D代码中Q你可能被find()Ҏ的这个参数困扰着Q?from Message as m order by m.text asc"Q其实它是Hibernate自己定义的查询语aQ全U叫Hibernate Query Language(HQL)。通俗地讲HQL与SQL的关pd不多是方言与普通话之间的关p,咋一看,你会觉得它有点类gSQL语句。其实在find()调用ӞHibernate会将q段HQL语言译成如下的SQL语句Q?br />select m.MESSAGE_ID, m.MESSAGE_TEXT, m.NEXT_MESSAGE_ID from MESSAGES m order by m.MESSAGE_TEXT asc
以下是q行l果Q?1 message(s) found: Hello World
如果你以前没有ORMQ对象-关系映射Q的开发经验,那你可能惛_代码的某个地方去Lq段SQL语句Q但在Hibernate中你可能会失望:它根本不存在Q所有就SQL语句都是Hibernate动态生成的? 也许你会觉得q缺点什么,对!仅凭以上代码Hibernate是无法将我们的MessagecL久化的。我们还需要一些更多的信息Q这是映射定义表!q个表在Hibernate中是以XML格式来体现的Q它定义了Messagecȝ属性是怎样与数据库中的MESSAGES表的字段q行一一对应的,列表2是这个示例程序的映射配置文g清单Q?br /> 列表2Q示例程序的对象Q关pL表 Q?xml version="1.0"?Q?br />Q?DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD//EN" "http://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd"Q?br />Qhibernate-mappingQ?br />Qclass name="hello.Message" table="MESSAGES"Q?br /> Qid name="id" column="MESSAGE_ID"Q?br /> Qgenerator class="increment"/Q?br /> Q?idQ?br /> Qproperty name="text" column="MESSAGE_TEXT"/Q?br /> Qmany-to-one name="nextMessage" cascade="all" column="NEXT_MESSAGE_ID"/Q?br />Q?classQ?br />Q?hibernate-mappingQ?
以上q个文档告诉Hibernate怎样MessagecL到MESSAGES表中Q其中Messagecȝid属性与表的MESSAGE_ID字段对应Qtext属性与表的MESSAGE_TEXT字段对应QnextMessage属性是一个多对一的关p,它与表中的NEXT_MESSAGE_ID相对应? 相对于有些开源项目来_Hibernate的配|文件其实是很容易理解的。你可以LC改与l护它。只要你定义好了持久cM数据库中表字D늚对应关系p了,Hibernate会自动帮你生成SQL语句来对Message对象q行插入、更新、删除、查扑ַ作,你可以不写一句SQL语句Q甚至不需要懂得SQL语言Q?br /> 现在让我们做一个新的试验,我们先取出第一个Message对象Q然后修改它的消息正文,最后我们再生成一个新的Message对象Qƈ它作ؓW一个Message对象的下一条消息,其代码如下: 列表3 更新一条消?br />Session session = getSessionFactory().openSession(); Transaction tx = session.beginTransaction(); // 1 is the generated id of the first message Message message =(Message) session.load( Message.class, new Long(1) ); message.setText("Greetings Earthling"); Message nextMessage = new Message("Take me to your leader (please)"); message.setNextMessage( nextMessage ); tx.commit(); session.close();
以上q段代码在调用时QHibernate内部自动生成如下的SQL语句Q?br />select m.MESSAGE_ID, m.MESSAGE_TEXT, m.NEXT_MESSAGE_ID from MESSAGES m where m.MESSAGE_ID = 1 insert into MESSAGES (MESSAGE_ID, MESSAGE_TEXT, NEXT_MESSAGE_ID) values (2, 'Take me to your leader (please)', null) update MESSAGES set MESSAGE_TEXT = 'Greetings Earthling', NEXT_MESSAGE_ID = 2 where MESSAGE_ID = 1
当第一个Message对象的text属性和nextMessage被程序修ҎQ请注意Hibernate是如何检到q种变化Qƈ如何在数据库中自动对它更新的。这实际上是Hibernate的一个很有h值的特色Q我们把它称为“自动脏数据”,Hibernate的这个特色得当我们修改一个持久对象的属性后Q不必显式地通知Hibernated它在数据库中q行更新。同LQ当W一个Message对象调用setNextMessage()Ҏ第二个Message对象作ؓ它的下一条消息的引用ӞW二条消息会无需调用save()ҎQ便可以自动C存在数据库中。这U特色被UCؓ“联保存”,它也免去了我们显式地对第二个Message对象调用save()Ҏ之苦?br /> 如果我们再运行先前的那段数据库中所有的Message对象都打印出来的代码Q那它的q行l果如下Q?br />2 message(s) found: Greetings Earthling Take me to your leader (please)
“Hello world”示例程序现在介l完毕。我们ȝ对Hibernate有了一个简单的认识Q下面我们将回过头来Q对Hibernate的主要API调用作一下简要的介绍Q?br />理解Hibernate的架?/strong> 当你想用Hibernate开发自qZ持久层的应用ӞW一件事情应当是熟悉它的~程接口。Hibernate的API接口设计得尽量简z明了,以方便开发h员。然而实际上׃ORM的复杂性,它的API一般都不可能设计得很简单。但是别担心Q你没有必要一下子了解所有的Hibernate的API接口。下面这张图描述了Hibernate在应用层和持久层中的一些重要的接口c: 在上图中Q我们将应用层放在了持久层的上部Q实际上在传l的目中,应用层充当着持久层的一个客L角色。但对于一些简单的目来说Q应用层和持久层q没有区分得那么清楚Q这也没什么,在这U情况下你可以将应用层和持久层合q成了一层?br /> 在上图中QHibernate的接口大致可以分Z下几U类型: · 一些被用户的应用程序调用的Q用来完成基本的创徏、读取、更新、删除操作以及查询操作的接口。这些接口是Hibernate实现用户E序的商业逻辑的主要接口,它们包括Session、Transaction和Query?br /> · Hibernate用来d诸如映射表这c配|文件的接口Q典型的代表有ConfigurationcR?br /> · 回调(Callback)接口。它允许应用E序能对一些事件的发生作出相应的操作,例如Interceptor、Lifecycle和Validatable都是q一cL口?br /> · 一些可以用来扩展Hibernate的映机制的接口Q例如UserType、CompositeUserType和IdentifierGenerator。这些接口可qL序来实现Q如果有必要Q?br /> Hibernate使用了J2EE架构中的如下技术:JDBC、JTA、JNDI。其中JDBC是一个支持关pL据库操作的一个基层;它与JNDI和JTA一L合,使得Hibernate可以方便地集成到J2EE应用服务器中厅R?br /> 在这里,我们不会详细地去讨论Hibernate API接口中的所有方法,我们只简要讲一下每个主要接口的功能Q如果你想了解得更多的话Q你可以在Hibernate的源码包中的net.sf.hibernate子包中去查看q些接口的源代码。下面我们依ơ讲一下所有的主要接口Q?br /> 核心接口 以下5个核心接口几乎在M实际开发中都会用到。通过q些接口Q你不仅可以存储和获得持久对象,q且能够q行事务控制?br /> Session接口 Session接口对于Hibernate 开发h员来说是一个最重要的接口。然而在Hibernate中,实例化的Session是一个轻量的类Q创建和销毁它都不会占用很多资源。这在实际项目中实很重要,因ؓ在客L序中Q可能会不断地创Z及销毁Session对象Q如果Session的开销太大Q会l系l带来不良媄响。但值得注意的是Session对象是非U程安全的,因此在你的设计中Q最好是一个线E只创徏一个Session对象?br /> 在Hibernate的设计者的头脑中,他们session看作介于数据q接与事务管理一U中间接口。我们可以将session惌成一个持久对象的~冲区,Hibernate能检到q些持久对象的改变,q及时刷新数据库。我们有时也USession是一个持久层理器,因ؓ它包含这一些持久层相关的操作,诸如存储持久对象x据库Q以及从数据库从获得它们。请注意QHibernate 的session不同于JSP应用中的HttpSession。当我们使用sessionq个术语Ӟ我们指的是Hibernate中的sessionQ而我们以后会HttpSesion对象UCؓ用户session?br /> SessionFactory 接口 q里用到了一个设计模式――工厂模式,用户E序从工厂类SessionFactory中取得Session的实例?br /> 令你感到奇怪的是SessionFactoryq不是轻量的!实际上它的设计者的意图是让它能在整个应用中׃n。典型地来说Q一个项目通常只需要一个SessionFactory够了,但是当你的项目要操作多个数据库时Q那你必Mؓ每个数据库指定一个SessionFactory?br />SessionFactory在Hibernate中实际vC一个缓冲区的作用,它缓冲了Hibernate自动生成的SQL语句和一些其它的映射数据Q还~冲了一些将来有可能重复利用的数据?br /> Configuration 接口 Configuration接口的作用是对Hibernateq行配置Q以及对它进行启动。在Hibernate的启动过E中QConfigurationcȝ实例首先定位映射文档的位|,dq些配置Q然后创Z个SessionFactory对象?br /> 虽然Configuration接口在整个Hibernate目中只扮演着一个很的角色Q但它是启动hibernate时你所遇到的每一个对象?br /> Transaction 接口 Transaction接口是一个可选的APIQ你可以选择不用这个接口,取而代之的是Hibernate的设计者自己写的底层事务处理代码?Transaction接口是对实际事务实现的一个抽象,q些实现包括JDBC的事务、JTA中的UserTransaction、甚臛_以是CORBA事务。之所以这栯计是能让开发者能够用一个统一事务的操作界面,使得自己的项目可以在不同的环境和容器之间方便地移倹{?br /> Query和Criteria接口 Query接口让你方便地对数据库及持久对象q行查询Q它可以有两U表达方式:HQL语言或本地数据库的SQL语句。Queryl常被用来绑定查询参数、限制查询记录数量,q最l执行查询操作?br /> Criteria接口与Query接口非常cMQ它允许你创建ƈ执行面向对象的标准化查询?br /> 值得注意的是Query接口也是轻量U的Q它不能在Session之外使用?br /> Callback 接口 当一些有用的事g发生时――例如持久对象的载入、存储、删除时QCallback接口会通知HibernateL收一个通知消息。一般而言QCallback接口在用L序中q不是必ȝQ但你要在你的项目中创徏审计日志Ӟ你可能会用到它?br /> 一个重要的术语QType Hibernate的设计者们发明了一个术语:TypeQ它在整个构架中是一个非常基、有着强大功能的元素。一个Type对象能将一个Javacd映射到数据库中一个表的字D中去(实际上,它可以映到表的多个字段中去Q。持久类的所有属性都对应一个type。这U设计思想使用Hibernate有着高度的灵zL和扩展性?br /> Hibernate内置很多typecdQ几乎包括所有的Java基本cdQ例如Java.util.Currency、Java.util.calendar、byte[]和Java.io.Serializable?br /> 不仅如此QHibernateq支持用戯定义的typeQ通过实现接口UserType和接口CompositeUserTypeQ你可以加入自己的type。你可以利用q种特色让你的项目中使用自定义的诸如Address、Nameq样的typeQ这样你可以获得更大的便利Q让你的代码更优雅。自定义type在Hibernate中是一Ҏ心特Ԍ它的设计者鼓׃多多使用它来创徏一个灵zR优雅的目Q?br /> {略接口 Hibernate与某些其它开源Y件不同的q有一点――高度的可扩展性,q通过它的内置{略机制来实现。当你感觉到Hibernate的某些功能不I或者有某些~陷Ӟ你可以开发一个自q{略来替换它Q而你所要做的仅仅只是承它的某个策略接口,然后实现你的新策略就可以了,以下是它的策略接口: · 主键的生?(IdentifierGenerator 接口) · 本地SQL语言支持 (Dialect 抽象c? · ~冲机制 (Cache 和CacheProvider 接口) · JDBC q接理 (ConnectionProvider接口) · 事务理 (TransactionFactory, Transaction, ?TransactionManagerLookup 接口) · ORM {略 (ClassPersister 接口) · 属性访问策?(PropertyAccessor 接口) · 代理对象的创?(ProxyFactory接口) HibernateZ上所列的机制分别创徏了一个缺省的实现Q因此如果你只是要增强它的某个策略的功能的话Q只需单地l承q个cd可以了,没有必要从头开始写代码?br /> 以上是Hibernate的一些核心接口,但当我们真正开始用它进行开发时Q你的脑里可能M有一个疑问:我是通过什么方式,q从哪里取得Session的呢Q以下我们就解答q个问题?br /> 基础配置 现在回顾一下我们先前的内容Q我们写Z一个示例程序,q简要地讲解了Hibernate的一些核心类。但要真正你的目q行hQ还有一件事必须要做Q配|。Hibernate可以配置成可在Q何Java环境中运行,一般说来,它通常被用?Q?层的C/S模式的项目中Qƈ被部|在服务端。在q种目中,Web览器、或Java GUIE序充当者客L。尽我们的焦点主要是集中在多层web应用Q但实际上在一些基于命令行的应用中也可以用Hibernate。ƈ且,对Hibernate的配|在不同的环境下都会不同QHibernateq行在两U环境下Q可理环境和不可管理环?br /> · 可管理环境――这U环境可理如下资源Q池资源理Q诸如数据库q接池和Q还有事务管理、安全定义。一些典型的J2EE服务器(JBoss、Weblogic、WebSphereQ已l实Cq些?br /> · 不可理环境――只是提供了一些基本的功能Q诸如像Jetty或Tomcatq样的servlet容器环境。一个普通的Java桌面应用或命令行E序也可以认为是处于q种环境下。这U环境不能提供自动事务处理、资源管理或安全理Q这些都必须由应用程序自己来定义?br /> Hibernate的设计者们这两种环境设计了一个统一的抽象界面,因此对于开发者来说只有一U环境:可管理环境。如果实际项目是建立在诸如Tomcatq类不可理的环境中Ӟ那Hibernate会使用它自q事务处理代码和JDBCq接池,使其变ؓ一个可理环境?br />对于可管理的环境而言QHibernate会将自己集成在这U环境中。对于开发者而言Q你所要做的工作非常简单:只需从一个ConfigurationcM创徏一个SessionFactorycd可以了?br />创徏一个SessionFactory对象 Z能创Z个SessionFactory对象Q你必须在Hibernate初始化时创徏一个Configurationcȝ实例Qƈ已写好的映文件交由它处理。这PConfiguration对象可以创Z个SessionFactory对象Q当SessionFactory对象创徏成功后,Configuration对象没有用了,你可以简单地抛弃它。如下是CZ代码Q?br />Configuration cfg = new Configuration(); cfg.addResource("hello/Message.hbm.xml"); cfg.setProperties( System.getProperties() ); SessionFactory sessions = cfg.buildSessionFactory();
在以上代码中QMessage.hb.xmlq个映射文g的位|比较特D,它与当前的classpath相关。例如classpath包含当前目录Q那在上qC码中的Message.hbm.xml映射文g可以保存在当前目录下的hello目录中?br /> 作ؓ一U约定,Hibernate的映文仉认以.htm.xml作ؓ其扩展名。另一个约定是坚持为每一个持久类写一个配|文Ӟ想一惛_果你所有持久类的映写入一个单独的配置文g中的话,那这个配|文件肯定非常庞大,不易l护。但q里又出C一个新问题Q如果ؓ每个cd一个配|文件的话,q么多的配置文g应该存放在哪里呢Q?br /> Hibernate推荐你将每个映射文g保存在与持久cȝ同的目录下,q且与持久类同名。例如我们第一个示例程序中的Message持久cL在hello目录下,那你必须在这个目录下存放名ؓMessage.hbm.xml的映文件。这样一个持久类都有自己的一个映文Ӟ避免了出现像struts目中的“struts-config.xml地狱”的情况。如果你不遵循这U规定,那你必须手动地用addResource()Ҏ一个个的映文件蝲入;但你如果遵@q种规定Q那你可以方便地用addClass()Ҏ同时持久类和它的映文件蝲入,以下是体现这U便利性的CZ代码Q?br />SessionFactory sessions = new Configuration() .addClass(org.hibernate.auction.model.Item.class) .addClass(org.hibernate.auction.model.Category.class) .addClass(org.hibernate.auction.model.Bid.class) .setProperties( System.getProperties() ) .buildSessionFactory();
当然QHibernate的映文件还有很多其它的配置选项Q比如数据库q接的设定,或是能够改变Hibernateq行时行为的一些设定。所有的讄可能是非常庞杂的Q以让你喘不过气来Q但是不必担心,因ؓHibernate为绝大多数值都讑֮了一个合理缺省|你只需要修改这些配|文件中的极一部分倹{?br /> 你可以通过以下几种方式来修改Hibernate的系l配|参敎ͼ · 一个Java.util.Properties实例作ؓ参数传给ConfigurationcȝsetProperties()Ҏ?br /> · 在Hibernate启动时用Java –Dproperty=value的方式设|倹{?br /> · 在classpath可以扑ֈ的\径下创徏一个名为hibernate.properties的配|文件? · 在classpath可以扑ֈ的\径下创徏一个名为hibernate.cfg.xml的文Ӟq在ӞpropertyQ标{中定义属性倹{?br /> 以上是对Hibernate的一个大致介l,如果你想知道得更多,那本文还是远q不够的Q我陆l推出更多关于Hibernate的资料。但有一Ҏ毫无疑问的:它的是一个非怼U的持久层解决ҎQ?br /> ]]>
վ֩ģ壺
Ǽ |
|
|
ɽ |
|
|
Ѱ |
|
ݶ |
|
̩ |
|
|
|
|
찲 |
|
Ͻ |
|
Ӳ |
|
|
ͷ |
|
|
|
|
|
|
̫ԭ |
|
Ƽ |
ƽ |
|
|
üɽ |
ƺ |
|
|
|
|