﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>BlogJava-&lt;font color="red"&gt;中國男人&lt;/font&gt;&lt;font color="lightgreen"&gt;大鹏一曰同风起，扶摇直上九万里&lt;/font&gt;-随笔分类-EJB</title><link>http://www.blogjava.net/liaojiyong/category/12588.html</link><description /><language>zh-cn</language><lastBuildDate>Wed, 28 Feb 2007 19:04:41 GMT</lastBuildDate><pubDate>Wed, 28 Feb 2007 19:04:41 GMT</pubDate><ttl>60</ttl><item><title>为什么要使用EJB？(转)</title><link>http://www.blogjava.net/liaojiyong/archive/2006/08/02/61344.html</link><dc:creator>liaojiyong</dc:creator><author>liaojiyong</author><pubDate>Wed, 02 Aug 2006 07:56:00 GMT</pubDate><guid>http://www.blogjava.net/liaojiyong/archive/2006/08/02/61344.html</guid><wfw:comment>http://www.blogjava.net/liaojiyong/comments/61344.html</wfw:comment><comments>http://www.blogjava.net/liaojiyong/archive/2006/08/02/61344.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/liaojiyong/comments/commentRss/61344.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/liaojiyong/services/trackbacks/61344.html</trackback:ping><description><![CDATA[
		<h2 align="center">　</h2>
		<p align="center">
				<a href="http://www.jdon.com/aboutme.htm">板桥里人</a> http://www.jdon.com 2004/03/08</p>
		<p align="left">　　首先，我们必须明确，为什么要使用J2EE？J2EE优点是什么？使用J2EE的主要原因是多层结构，传统的两层C/S结构难于维护，稳定性极差，界面代码和数据库代码混淆在一起，牵一动百，多层结构使得界面和数据库完全分离，并且诞生了中间件这样的技术，如下图：</p>
		<p align="center">
				<img height="186" alt="" src="http://www.jdon.com/artichect/images/middle.png" width="400" />
		</p>
		<h3>Web+EJB能组成真正的多层结构</h3>
		<p>　　为什么使用EJB我原先认为这不是一个讨论的话题，因为EJB是J2EE重要的组成部分，可以说没有EJB的J2EE只是一种Web系统，这样的系统非常容易丧失了多层结构的大部分优点（仔细想想那些混合多种层次功能JavaBeans和传统两层结构有什么区别？）。</p>
		<p>　 　当然，可以人为地在Javabeans之间进行层次划分，例如Hibernate算数据持久层，某些JavaBeans是业务核心层，但是因为都是普通 JavaBeans，这种划分没有一种强制性和明显标志性，这样的系统更换了主创人员或设计师，可能就会被新的程序员修改得非常混乱。</p>
		<p>　　我们先看看一个包含EJB的J2EE系统是如何清晰地表达层次。如下图：</p>
		<p align="center">
				<img height="300" alt="" src="http://www.jdon.com/artichect/images/j2ee.png" width="482" />
		</p>
		<p>　　Web完全只是一个MVC模式的实现，关键业务核心是在EJB的服务层实现，这样做的优点是，Web只负责界面相关部分，因为，如果是一个智能客户端，如Swing或J2ME，在不需要修改任何业务核心的情况下能够方便地更换。同样，提供Web Services功能，也只是在 Web层修改，不会涉及EJB方面的修改，同样保证了系统的稳定性，保证了系统升级和未来的扩展性。</p>
		<p>　　如果不使用EJB，在EJB服务层实现的业务核心将由普通JavaBeans实现，使用何种架构或设计能够保证负责MVC的JavaBeans和负责业务核心的JavaBeans清晰地分开，又如何保证在新的程序员不会破坏和打乱你精心布局的JavaBeans架构？</p>
		<h3>EJB提供性能优化支持</h3>
		<p>　　最主要的是性能问题，由于以前国内中文Java网站有些人弯曲EJB，认为EJB性能低，其实这是一种非常肤浅错误的认识，我们首先看看在一般Java环境中是如何提高性能。</p>
		<p>　　假定一个JavaBeans为A，那么一般使用这个JavaBeans命令如下：</p>
		<p>　　A a = new A();</p>
		<p>　 　但是，在高访问量的环境中，new A()其实是很费时消耗系统性能的，因此，能不能在软件系统启动时候就预先建立一些对象，这样，系统运行时，从这些已经生成的对象池中借用一个，这样，就 无需在使用时进行New，节约了开销，提高了性能，因此，真正成熟性能解决方案都是需要对象池等支持。</p>
		<p>　 　在一个纯Web结构的系统（也就是只能运行在Tomat环境中），例如Struts + Hibernate等这样的系统，除非自己动手做，一般是没有对象池技术支持的，因此他们的性能只能算是Demo演示版本的性能，根本无法承受大容量并发 访问，也无法称为一个成熟的系统，所以，我们研究成熟的开源Web系统，如Jive、OFBize，LifeRay等，他们都在Web层拥有自己的对象池 和缓存池。</p>
		<p>　　对象池和缓存机制是J2EE必须的吗？当然，是所有成熟系统必须的，Windows系统如果去掉缓存将会变得怎样？</p>
		<p>　　自己动手开发对象池和缓存机制并不是一件简单的事情，需要对多线程以及同步锁等底层原理有深层次的把握，这其实也是一门非常深入的Java研究分支，所以，你可以抛开你的客户焦急的催促，精心研究开发自己的对象池和缓存池。</p>
		<p>　 　但是，EJB容器（如JBoss）已经提供了对象池和缓存机制，所以，没有事务机制的无状态Session Bean的性能肯定要强于普通JavaBeans。EJB容器不但在单机中提供了对象池和缓存，而且可以跨服务器实现动态负载平衡，这些都无需开发者自己 开发任何软件代码，结构如下：</p>
		<p align="center">
				<img height="227" alt="" src="http://www.jdon.com/artichect/images/ejb.png" width="304" />
		</p>
		<h3 align="left">EJB组件能提供真正的可重用框架</h3>
		<p align="left">　　每一个jar包代表一个EJB组件，一个系统可以由多个可重用的EJB组件构成，例如：树形结构EJB组件；自增序号EJB组件；用户资料EJB组件等，这样的EJB组件可以象积木一样搭配在大部分应用系统中，提高了系统的开发效率，保证了开发质量。</p>
		<p align="left">　　下图是某个新的具体系统时应用到的EJB组件图，在这个新的应用中，由于使用了以前大量可重用的EJB组件，新的开发工作基本集中在界面设计和流程安排上：</p>
		<p align="center">
				<img height="421" alt="" src="http://www.jdon.com/artichect/images/ejbcomps.png" width="297" />
		</p>
		<h3>EJB提供了事务机制</h3>
		<p>　　事务机制对于一些关键事务是很重要的，例如ATM机提款，提款有多个动作：修改数据库以及数钱等，如果这其中有任何一个环节出错，那么其它已经实现的操作必须还原，否则，就会出现，提款人没有拿到钱，但是卡上已经扣款等不可思议的事情发生。</p>
		<p>　 　EJB提供的事务机制非常周全，但事务机制带来的缺点是性能的降低，因此，有些人认为EJB很重，因为在实际应用中，有的用户系统可能不需要事务机制， 只是需要EJB提供的性能优化机制，这样，如果使用EJB，就象叫一个人来背东西，他除了背着我要的东西外，还背着我不要的东西。</p>
		<p>　　除非你是一个完美主义，在一般企业应用或数据库系统应用中，EJB不会对你构成很重的包袱。</p>
		<h3>CMP独特的优点</h3>
		<p>　　开源以及一些数据库持久层技术崇拜者，一直抨击CMP，认为CMP慢无用，实际最大的问题是他们的设计和使用问题。</p>
		<p>　 　由于EJB容器（如JBoss）对CMP实现有事务机制的缓存优化，因此，CMP特别适合多个用户同时更新同一个数据源的情况，CMP这种严格的事务完 整性保证多个用户同时操作一个数据记录时，能够保证性能优化和数据的完整性，如果这个数据记录是是软件系统的状态标志，它的状态会影响系统中很多的环节， 那么状态更改的重要性不言而喻。</p>
		<p>　　如果没有事务完整性支持，你的软件系统在用户访问量变大，就会变得发生各种不可能发生的逻辑错误，查看程序逻辑是正确的，那么问题出在哪里？出在数据完整性上。</p>
		<p>　 　由于每个CMP在内存中都有一个缓存，在实际应用中，如果使用CMP批量读数据库数据，几万条查询完毕，内存中充满了几万条CMP缓存，如果这时你的 EJB容器设置不当（如使用JBoss缺省配置），那么JVM的垃圾回收机制就会频繁启动，导致你的系统变慢甚至死机，这也是一些人抨击CMP慢的原因所 在，其实他们使用方法不当，或者没有正确配置EJB容器CMP缓存。</p>
		<p>　　对于这种情况，根据J2EE核心模式，推荐使用DAO+JDBC方式。</p>
		<h3>小结</h3>
		<p>　 　除非你对设计模式非常精深，能够将自己系统中的JavaBeans使用模式或某种框架进行固定分层，同时，你孜孜不倦研发出对象池，又熟练于JTA等事 务机制，你可以选择没有EJB的纯Web结构，就象Jive、OFBiz那样。当然还有一个前提，老板不懂或者非常有挑战性（做与IBM SUN 微软齐名的公司和技术）。</p>
		<p>　　不要再被TSS那些狂热的开源先生误导，他们有时间有保障可以做他们喜欢的事情，作为专业的J2EE程序员，按照J2EE标准去学习去行动，也不要认为，只要使用了J2EE其中某个技术如Jsp或JavaBeans就心安理得认为自己的系统是J2EE了。</p>
		<p>　　当然，我并不是说纯Web系统不能实现多层结构，但是至少在很多方面没有Web+EJB结构完善和清晰，所以，EJB不是J2EE可以忽视的部分，而是主要的重要的部分，重要业务功能核心都封装在EJB中，相反Web层是一种次要的、和界面相关的层次。</p>
		<p>　　补充：什么情况下不需要EJB，在SUN的SECA架构师试卷中回答：小型系统和不需要事务。另外过去那种认为“EJB有性能问题”根本是一种缪误，具体可参考下面有关问题。</p> <img src ="http://www.blogjava.net/liaojiyong/aggbug/61344.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/liaojiyong/" target="_blank">liaojiyong</a> 2006-08-02 15:56 <a href="http://www.blogjava.net/liaojiyong/archive/2006/08/02/61344.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>EJB 3.0 学习笔记——Entity Bean（转）</title><link>http://www.blogjava.net/liaojiyong/archive/2006/07/21/59317.html</link><dc:creator>liaojiyong</dc:creator><author>liaojiyong</author><pubDate>Thu, 20 Jul 2006 17:39:00 GMT</pubDate><guid>http://www.blogjava.net/liaojiyong/archive/2006/07/21/59317.html</guid><wfw:comment>http://www.blogjava.net/liaojiyong/comments/59317.html</wfw:comment><comments>http://www.blogjava.net/liaojiyong/archive/2006/07/21/59317.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/liaojiyong/comments/commentRss/59317.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/liaojiyong/services/trackbacks/59317.html</trackback:ping><description><![CDATA[
		<p>在EJB 3.0 学习笔记——准备工作中只是简单的搭好了EJB3.0开发的基本环境，之</p>
		<p>后就可以开发最简单的Session Bean了，我感兴趣的还是Entity Bean，所以接下来</p>
		<p>我想先试验一下Entity Bean。<br /> <br />一、在JBoss中配置好Data Source<br />我使用的是MySQL数据库，所以首先将MySQL的JDBC驱动复制到<br />jboss-4.0.3SP1\server\all\lib目录，然后将jboss-4.0.3SP1\docs\examples\jca</p>
		<p>下的mysql-ds.xml作出适当修改后复制到jboss-4.0.3SP1\server\all\deploy目录</p>
		<p>下，这是我修改后的mysql-ds.xml文件：</p>
		<p>&lt;?xml version="1.0" encoding="UTF-8"?&gt;</p>
		<p>&lt;!-- $Id: mysql-ds.xml,v 1.3.2.1 2004/12/01 11:46:00 schrouf Exp $ --&gt;<br />&lt;!--  Datasource config for MySQL using 3.0.9 available from:<br /><a href="http://www.mysql.com/downloads/api-jdbc-stable.html"><font color="#000080">http://www.mysql.com/downloads/api-jdbc-stable.html</font></a><br />--&gt;</p>
		<p>&lt;datasources&gt;<br />  &lt;local-tx-datasource&gt;<br />    &lt;jndi-name&gt;MySqlDS&lt;/jndi-name&gt;<br />    &lt;connection-url&gt;jdbc:mysql://localhost:3306/test&lt;/connection-url&gt;<br />    &lt;driver-class&gt;com.mysql.jdbc.Driver&lt;/driver-class&gt;<br />    &lt;user-name&gt;test&lt;/user-name&gt;<br />    &lt;password&gt;&lt;/password&gt;<br />    &lt;exception-sorter-class-</p>
		<p>name&gt;org.jboss.resource.adapter.jdbc.vendor.MySQLExceptionSorter&lt;/excepti</p>
		<p>on-sorter-class-name&gt;<br />    &lt;!-- sql to call when connection is created<br />    &lt;new-connection-sql&gt;some arbitrary sql&lt;/new-connection-sql&gt;<br />      --&gt;<br />    &lt;!-- sql to call on an existing pooled connection when it is obtained </p>
		<p>from pool <br />    &lt;check-valid-connection-sql&gt;some arbitrary sql&lt;/check-valid-</p>
		<p>connection-sql&gt;<br />      --&gt;</p>
		<p>    &lt;!-- corresponding type-mapping in the standardjbosscmp-jdbc.xml </p>
		<p>(optional) --&gt;<br />    &lt;metadata&gt;<br />       &lt;type-mapping&gt;mySQL&lt;/type-mapping&gt;<br />    &lt;/metadata&gt;<br />  &lt;/local-tx-datasource&gt;<br />&lt;/datasources&gt;<br />这样之后，JBoss下的MySQL Data Source配置完成。</p>
		<p>二、创建数据库并编写Entity Bean代码</p>
		<p>create table book(<br />id int not null auto_increment primary key,<br />title varchar(20) not null,<br />author varchar(40) not null<br />);<br />新建Java Project，导入User Library：EJB3_JBoss，以下是类代码。</p>
		<p>//Book.java<br />package ejb.bean.entity;</p>
		<p>import java.io.Serializable;</p>
		<p>import javax.persistence.Entity;<br />import javax.persistence.GeneratedValue;<br />import javax.persistence.GenerationType;<br />import javax.persistence.Id;<br />import javax.persistence.Table;</p>
		<p>@Entity<br />@Table(name="book")<br />public class Book implements Serializable {<br /> /**<br />  * <br />  */<br /> private static final long serialVersionUID = 1L;<br /> private Integer id; <br /> private String title; <br /> private String author;<br /> <br /> public Book() {  <br />  super(); <br /> } <br /> public Book(Integer id, String title, String author) { <br />  super();  <br />  this.id = id;  <br />  this.title = title;  <br />  this.author = author; <br />  }<br /> @Override<br /> public String toString() { <br />  <br />  return "Book: " + getId() + " Title " + getTitle() + " </p>
		<p>Author " + getAuthor(); <br /> }<br /> public String getAuthor() {<br />  return author;<br /> }<br /> <br /> @Id @GeneratedValue(strategy=GenerationType.AUTO)<br /> public Integer getId() {<br />  return id;<br /> }<br /> public String getTitle() {<br />  return title;<br /> }<br /> public void setAuthor(String author) {<br />  this.author = author;<br /> }<br /> public void setId(Integer id) {<br />  this.id = id;<br /> }<br /> public void setTitle(String title) {<br />  this.title = title;<br /> }</p>
		<p>}</p>
		<p>三、编写一个简单的Stateless Session Bean 并进行测试</p>
		<p>//BookTestLocal.java<br />package ejb.bean.entity;</p>
		<p>import javax.ejb.Local;</p>
		<p>@Local<br />public interface BookTestLocal {</p>
		<p> public void test();<br />}</p>
		<p>//BookTestRemote.java<br />package ejb.bean.entity;</p>
		<p>import javax.ejb.Remote;<br />@Remote<br />public interface BookTestRemote {<br /> <br /> public void test();</p>
		<p>}</p>
		<p>//BookTestBean.java<br />package ejb.bean.entity;</p>
		<p>import javax.ejb.Stateless;<br />import javax.persistence.EntityManager;<br />import javax.persistence.PersistenceContext;</p>
		<p>@Stateless<br />public class BookTestBean implements BookTestLocal, BookTestRemote {</p>
		<p> @PersistenceContext<br /> EntityManager em;<br /> public void test() {<br />  // TODO Auto-generated method stub<br />  Book book = new Book(null, "My first bean book", </p>
		<p>"Sebastian");<br />  em.persist(book);</p>
		<p> }</p>
		<p>}</p>
		<p>
				<br />//Client.java<br />package ejb.client.entity;</p>
		<p>import ejb.bean.entity.*;</p>
		<p>
				<br />import javax.naming.InitialContext;</p>
		<p>/**<br /> * Comment<br /> *<br /> * @author &lt;a href="<a href="mailto:bill@jboss.org&quot;&gt;Bill"><font color="#000080">mailto:bill@jboss.org"&gt;Bill</font></a> Burke&lt;/a&gt;<br /> * @version $Revision: 1.1.6.7 $<br /> */<br />public class Client<br />{<br />   public static void main(String[] args) throws Exception<br />   {<br />      InitialContext ctx = new InitialContext();<br />      BookTestRemote book = (BookTestRemote) ctx.lookup</p>
		<p>("BookTestBean/remote");</p>
		<p>     </p>
		<p>   <br />      book.test();<br />      <br />      System.out.println("test successful! ");</p>
		<p>   }<br />}</p>
		<p>三、其他文件<br />将jboss-EJB-3.0_RC5-PFD\docs\tutorial中的找到的jndi.properties、log4j.xml</p>
		<p>、builder.xml等复制到当前工程中，其中builder.xml需要修改。<br />//builder.xml<br />&lt;?xml version="1.0"?&gt;</p>
		<p>&lt;!-- </p>
		<p>======================================================================= </p>
		<p>--&gt;<br />&lt;!-- JBoss build file                                                     </p>
		<p>  --&gt;<br />&lt;!-- </p>
		<p>======================================================================= </p>
		<p>--&gt;</p>
		<p>&lt;project name="JBoss" default="ejbjar" basedir="."&gt;</p>
		<p>   &lt;property file="../local.properties" /&gt;<br />   &lt;property environment="env"/&gt;<br />   &lt;property name="src.dir" value="${basedir}/src"/&gt;<br />   &lt;property name="jboss.home" value="E:/Programming/Servers/jboss-</p>
		<p>4.0.3SP1/"/&gt;<br />   &lt;property name="jboss.server.config" value="all"/&gt;<br />   &lt;property name="build.dir" value="${basedir}/build"/&gt;<br />   &lt;property name="build.classes.dir" value="${build.dir}/classes"/&gt;</p>
		<p>   &lt;!-- Build classpath --&gt;<br />   &lt;path id="classpath"&gt;<br />      &lt;!-- So that we can get jndi.properties for InitialContext --&gt;<br />      &lt;pathelement location="${basedir}"/&gt;<br />      &lt;fileset dir="${jboss.home}/lib"&gt;<br />         &lt;include name="**/*.jar"/&gt;<br />      &lt;/fileset&gt;<br />      &lt;fileset dir="${jboss.home}/server/${jboss.server.config}/lib"&gt;<br />         &lt;include name="**/*.jar"/&gt;<br />      &lt;/fileset&gt;<br />      &lt;fileset dir="${jboss.home}/server/</p>
		<p>${jboss.server.config}/deploy/ejb3.deployer"&gt;<br />         &lt;include name="*.jar"/&gt;<br />      &lt;/fileset&gt;<br />      &lt;fileset dir="${jboss.home}/server/</p>
		<p>${jboss.server.config}/deploy/jboss-aop-jdk50.deployer"&gt;<br />         &lt;include name="*.jar"/&gt;<br />      &lt;/fileset&gt;<br />      &lt;pathelement location="${build.classes.dir}"/&gt;<br />   &lt;/path&gt;</p>
		<p>   &lt;property name="build.classpath" refid="classpath"/&gt;</p>
		<p>   &lt;!-- </p>
		<p>=================================================================== --&gt;<br />   &lt;!-- Prepares the build directory                                      </p>
		<p>  --&gt;<br />   &lt;!-- </p>
		<p>=================================================================== --&gt;<br />   &lt;target name="prepare"&gt;<br />      &lt;mkdir dir="${build.dir}"/&gt;<br />      &lt;mkdir dir="${build.classes.dir}"/&gt;<br />   &lt;/target&gt;</p>
		<p>   &lt;!-- </p>
		<p>=================================================================== --&gt;<br />   &lt;!-- Compiles the source code                                          </p>
		<p>  --&gt;<br />   &lt;!-- </p>
		<p>=================================================================== --&gt;<br />   &lt;target name="compile" depends="prepare"&gt;<br />      &lt;javac srcdir="${src.dir}"<br />         destdir="${build.classes.dir}"<br />         debug="on"<br />         deprecation="on"<br />         optimize="off"<br />         includes="**"&gt;<br />         &lt;classpath refid="classpath"/&gt;<br />      &lt;/javac&gt;<br />   &lt;/target&gt;</p>
		<p>   &lt;target name="ejbjar" depends="compile"&gt;<br />      &lt;jar jarfile="build/tutorial.jar"&gt;<br />         &lt;fileset dir="${build.classes.dir}"&gt;<br />            &lt;include name="**/*.class"/&gt;<br />         &lt;/fileset&gt;<br />        &lt;fileset dir="."&gt;<br />           &lt;include name="META-INF/persistence.xml"/&gt;<br />        &lt;/fileset&gt;<br />      &lt;/jar&gt;<br />      &lt;copy file="build/tutorial.jar" todir="${jboss.home}/server/</p>
		<p>${jboss.server.config}/deploy"/&gt;<br />   &lt;/target&gt;</p>
		<p>   &lt;target name="run.stateless" depends="ejbjar"&gt;<br />      &lt;java classname="ejb.client.stateless.Client" fork="yes" dir="."&gt;<br />         &lt;classpath refid="classpath"/&gt;<br />      &lt;/java&gt;<br />   &lt;/target&gt;<br /> <br /> &lt;target name="run.stateful" depends="ejbjar"&gt;<br />       &lt;java classname="ejb.client.stateful.Client" fork="yes" </p>
		<p>dir="."&gt;<br />          &lt;classpath refid="classpath"/&gt;<br />       &lt;/java&gt;<br /> &lt;/target&gt;<br /> <br /> &lt;target name="run.timer" depends="ejbjar"&gt;<br />       &lt;java classname="ejb.client.timer.Client" fork="yes" </p>
		<p>dir="."&gt;<br />          &lt;classpath refid="classpath"/&gt;<br />       &lt;/java&gt;<br /> &lt;/target&gt;<br /> <br /> &lt;target name="run.entity" depends="ejbjar"&gt;<br />        &lt;java classname="ejb.client.entity.Client" </p>
		<p>fork="yes" dir="."&gt;<br />           &lt;classpath refid="classpath"/&gt;<br />        &lt;/java&gt;<br />  &lt;/target&gt;<br /> </p>
		<p>   &lt;!-- </p>
		<p>=================================================================== --&gt;<br />   &lt;!-- Cleans up generated stuff                                         </p>
		<p>  --&gt;<br />   &lt;!-- </p>
		<p>=================================================================== --&gt;<br />   &lt;target name="clean.db"&gt;<br />      &lt;delete dir="${jboss.home}/server/</p>
		<p>${jboss.server.config}/data/hypersonic"/&gt;<br />   &lt;/target&gt;</p>
		<p>   &lt;target name="clean"&gt;<br />      &lt;delete dir="${build.dir}"/&gt;<br />      &lt;delete file="${jboss.home}/server/</p>
		<p>${jboss.server.config}/deploy/tutorial.jar"/&gt;<br />   &lt;/target&gt;</p>
		<p>
				<br />&lt;/project&gt;</p>
		<p>最后，在工程目录下新建目录META-INF，在目录META-INF新建persistence.xml文件</p>
		<p>，以下是文件内容：<br />&lt;?xml version="1.0" encoding="UTF-8"?&gt;<br />&lt;persistence&gt;<br />   &lt;persistence-unit name="test"&gt;<br />      &lt;jta-data-source&gt;java:/MySqlDS&lt;/jta-data-source&gt;<br />      &lt;properties&gt;<br />       &lt;property name="hibernate.dialect" </p>
		<p>value="org.hibernate.dialect.MySQLDialect"/&gt;       <br />        &lt;property name="hibernate.hbm2ddl.auto" value="update"/&gt;<br />      &lt;/properties&gt;<br />   &lt;/persistence-unit&gt;<br />&lt;/persistence&gt;</p>
		<p>四、运行测试<br />run as-&gt;ant build后，选择运行目标为run.entity-&gt;run。<br />运行结果：<br />Buildfile: D:\Programs\Java\EclipseWork\EJB3\build.xml<br />prepare:<br />compile:<br />ejbjar:<br />run.entity:<br />     [java] test successful!<br />BUILD SUCCESSFUL<br />Total time: 9 seconds</p>
		<p>
				<br />MySQL中select * from book;<br />id        title                     author<br />1        My first bean book         Sebastian<br />已经成功写入。</p>
		<p> </p>
<img src ="http://www.blogjava.net/liaojiyong/aggbug/59317.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/liaojiyong/" target="_blank">liaojiyong</a> 2006-07-21 01:39 <a href="http://www.blogjava.net/liaojiyong/archive/2006/07/21/59317.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>EJB 3.0开发指南之组合主键</title><link>http://www.blogjava.net/liaojiyong/archive/2006/07/04/56460.html</link><dc:creator>liaojiyong</dc:creator><author>liaojiyong</author><pubDate>Tue, 04 Jul 2006 01:28:00 GMT</pubDate><guid>http://www.blogjava.net/liaojiyong/archive/2006/07/04/56460.html</guid><wfw:comment>http://www.blogjava.net/liaojiyong/comments/56460.html</wfw:comment><comments>http://www.blogjava.net/liaojiyong/archive/2006/07/04/56460.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/liaojiyong/comments/commentRss/56460.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/liaojiyong/services/trackbacks/56460.html</trackback:ping><description><![CDATA[在前面的所有的实体Bean的例子中，我们所用的主键都是Id,而且都是由容器自动生成的。 <br /><br />　　如:<br /><br /><table bordercolor="#ffcc66" width="90%" align="center" bgcolor="#dadacf" border="1"><tbody><tr><td>@Id(generate = GeneratorType.AUTO)<br />public int getId()<br />{<br />　return id;<br />}</td></tr></tbody></table><br />　　事实上,主键可以是任意的java基本类型、或者是基本类型的包装类，如Integer、String类型、或者是带字段或属性的主键类。注意，如果这样使用主键,你需要将主键的注释中的生成规则改为NONE。就是由程序生成主键值。<br /><br />　　主键类必须实现hashCode和equals方法。<br /><br />　　这个例子前面举例过，就是一个存储学生信息的实体bean，在那个例子中，使用Name类作为属性，并且以Id作为主键，在这个例子中，我们将使用name作为主键，注意name的类型一个java类。和前面的例子一样，我们还是使用Client测试。<br /><br />　　Name.java：主键。<br /><br />　　Student.java：实体Bean类。<br /><br />　　StudentDAO.java：会话Bean的业务接口<br /><br />　　StudentDAOBean.java：会话Bean的实现类<br /><br />　　Client.java：测试EJB的客户端类。<br /><br />　　jndi.properties：jndi属性文件，提供访问jdni的基本配置属性。<br /><br />　　Build.xml：ant 配置文件，用以编译、发布、测试、清除EJB。<br /><br />　　下面针对每个文件的内容做一个介绍。<br /><br />　　Name.java<br /><br /><table bordercolor="#ffcc66" width="90%" align="center" bgcolor="#dadacf" border="1"><tbody><tr><td>package com.kuaff.ejb3.composite;<br /><br />import java.io.Serializable;<br />import javax.ejb.AccessType;<br />import javax.ejb.DependentObject;<br /><br />@DependentObject(access = AccessType.PROPERTY)<br /><br />public class Name implements java.io.Serializable<br />{<br />　private String first;<br />　private String last;<br /><br />　public Name()<br />　{<br />　}<br /><br />　public Name(String first, String last)<br />　{<br />　　this.first = first;<br />　　this.last = last;<br />　}<br /><br />　public String getFirst()<br />　{<br />　　return first;<br />　}<br /><br />　public void setFirst(String first)<br />　{<br />　　this.first = first;<br />　}<br /><br />　public String getLast()<br />　{<br />　　return last;<br />　}<br /><br />　public void setLast(String last)<br />　{<br />　　this.last = last;<br />　}<br /><br />　public int hashCode()<br />　{<br />　　return (first+last).hashCode();<br />　}<br /><br />　public boolean equals(Object object)<br />　{<br />　　if (this == object) return true;<br />　　if (object == null) return false;<br />　　if (! (object instanceof Name)) return false;<br />　　Name name = (Name)object;<br />　　if ((name.first.equals(first)) &amp;&amp; (name.last.equals(last)))<br />　　　return true;<br />　　else<br />　　　return false;<br />　}<br /><br />}</td></tr></tbody></table><br />　　Student.java<br /><br /><table bordercolor="#ffcc66" width="90%" align="center" bgcolor="#dadacf" border="1"><tbody><tr><td>package com.kuaff.ejb3.composite;<br /><br />import javax.ejb.Dependent;<br />import javax.ejb.DependentAttribute;<br />import javax.ejb.Column;<br />import javax.ejb.Entity;<br />import javax.ejb.GeneratorType;<br />import javax.ejb.Id;<br />import javax.ejb.Table;<br /><br />@Entity @Table(name = "STUDENT") public class Student implements java.io.Serializable<br />{<br />　private Name name;<br />　private String grade;<br />　private String email;<br /><br />　public void setName(Name name)<br />　{<br />　　this.name = name;<br />　}<br /><br />　@Id(generate = GeneratorType.NONE)<br />　@Dependent(<br />　　{ @DependentAttribute(name = "first", column ={ @Column(name = "FIRST") }), <br />　　　@DependentAttribute(name = "last", column ={ @Column(name = "LAST") }) }) <br />　　　public Name getName()<br />　　　{<br />　　　　return name;<br />　　　}<br /><br />　public void setGrade(String grade)<br />　{<br />　　this.grade = grade;<br />　}<br /><br />　@Column(name = "GRADE") <br />　public String getGrade()<br />　{<br />　　return grade;<br />　}<br /><br />　public void setEmail(String email)<br />　{<br />　　this.email = email;<br />　}<br /><br />　@Column(name = "EMAIL") <br /><br />　public String getEmail()<br />　{<br />　　return email;</td></tr></tbody></table><br />　　StudentDAO.java<br /><br /><table bordercolor="#ffcc66" width="90%" align="center" bgcolor="#dadacf" border="1"><tbody><tr><td>package com.kuaff.ejb3.composite;<br /><br />import javax.ejb.Remote;<br />import java.util.List;<br /><br />@Remote<br /><br />public interface StudentDAO<br /><br />{<br /><br />void create(String first, String last, String grade, String email);<br /><br /><br /><br />Student find(Name name);<br /><br />List findByFirstName(String name);<br /><br />List findByLastName(String name);<br /><br />List findByEmail(String email);<br /><br /><br /><br />void merge(Student s);<br /><br />}</td></tr></tbody></table><br />　　StudentDAOBean.java<br /><br /><table bordercolor="#ffcc66" width="90%" align="center" bgcolor="#dadacf" border="1"><tbody><tr><td>package com.kuaff.ejb3.composite;<br /><br />import java.util.List;<br />import javax.ejb.EntityManager;<br />import javax.ejb.Inject;<br />import javax.ejb.Stateless;<br /><br />@Stateless<br /><br />public class StudentDAOBean implements StudentDAO<br />{<br />　@Inject<br />　private EntityManager manager;<br /><br />　public void create(String first, String last, String grade, String email)<br />　{<br />　　Student student = new Student();<br />　　student.setName(new Name(first,last));<br />　　student.setGrade(grade);<br />　　student.setEmail(email);<br />　　manager.create(student);<br />　}<br /><br />　public Student find(Name name)<br />　{<br />　　return manager.find(Student.class, name);<br />　}<br /><br />　public List findByFirstName(String name)<br />　{<br />　　return manager.createQuery("from Student s where s.name.last = :name").setParameter("name", name).listResults();<br /><br />　}<br /><br />　public List findByLastName(String name)<br />　{<br />　　return manager.createQuery("from Student s where s.name.first = :name").setParameter("name", name).listResults();<br />　}<br /><br />　public List findByEmail(String email)<br />　{<br />　　return manager.createQuery("from Student s where s.email = :email").setParameter("email", email).listResults();<br />　}<br /><br />　public void merge(Student s)<br />　{<br />　　manager.merge(s);<br />　}<br /><br />}</td></tr></tbody></table><br />　　Client.java<br /><br /><table bordercolor="#ffcc66" width="90%" align="center" bgcolor="#dadacf" border="1"><tbody><tr><td>package com.kuaff.ejb3.composite;<br /><br />import javax.naming.InitialContext;<br />import javax.naming.NamingException;<br />import java.util.List;<br /><br />public class Client<br />{<br />　public static void main(String[] args) throws NamingException<br />　{<br />　　InitialContext ctx = new InitialContext();<br />　　StudentDAO dao = (StudentDAO) ctx.lookup(StudentDAO.class.getName());<br />　　dao.create("晁","岳攀","8","smallnest@kuaff.com");<br />　　dao.create("朱","立焕","6","zhuzhu@kuaff.com");<br />　　Name name = new Name("朱","立焕");<br /><br />　　//List list = dao.findByEmail("zhuzhu@kuaff.com");<br /><br />　　Student s = dao.find(name);<br />　　System.out.printf("%s %s的email:%s%n",s.getName().getFirst(),s.getName().getLast(),s.getEmail());<br />　　/*<br />　　　for(Object o:list)<br />　　　{<br />　　　　Student s = (Student)o;<br />　　　　System.out.printf("%s %s的email:%s%n",s.getName().getFirst(),s.getName().getLast(),s.getEmail());<br />　　　}<br />　　*/<br />　}<br />}</td></tr></tbody></table><br />　　这个客户端用来测试。<br /><br />　　请运行{$JBOSS_HOME}/bin目录下的run.bat: run –c all,启动JBOSS。<br /><br />http://localhost:8080/jmx-console/HtmlAdaptor?action=inspectMBean&amp;name=jboss%3Aservice%3DHypersonic%2Cdatabase%3DlocalDB，然后调用startDatabaseManager()方法，打开HSQL管理工具管理数据库。<br /><br />　　在Eclipse的Ant视图中执行ejbjar target。或者在命令行下，进入到此工程目录下，执行ant ejbjar,将编译打包发布此EJB。<br /><br />　　在Eclipse的Ant视图中执行run target。或者在命令行下，进入到此工程目录下，执行ant run,测试这个EJB。<br /><img src ="http://www.blogjava.net/liaojiyong/aggbug/56460.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/liaojiyong/" target="_blank">liaojiyong</a> 2006-07-04 09:28 <a href="http://www.blogjava.net/liaojiyong/archive/2006/07/04/56460.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>EJB3.0开发指南之多对多和一对一</title><link>http://www.blogjava.net/liaojiyong/archive/2006/07/04/56459.html</link><dc:creator>liaojiyong</dc:creator><author>liaojiyong</author><pubDate>Tue, 04 Jul 2006 01:27:00 GMT</pubDate><guid>http://www.blogjava.net/liaojiyong/archive/2006/07/04/56459.html</guid><wfw:comment>http://www.blogjava.net/liaojiyong/comments/56459.html</wfw:comment><comments>http://www.blogjava.net/liaojiyong/archive/2006/07/04/56459.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/liaojiyong/comments/commentRss/56459.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/liaojiyong/services/trackbacks/56459.html</trackback:ping><description><![CDATA[在前面的例子中，我们演示了一对多和多对一的例子，在本章将演示多对多和一对一的关系。 <br /><br />　　学生和老师就是多对多的关系。一个学生有多个老师，一个老师教多个学生。<br /><br />　　学生和档案就是一对一的关系（不知道国外的学生有没有档案？）。<br /><br />　　为了实现多对多的关系，数据库中需要关联表，用以在两个实体间建立关联。JBoss可以自动生成关联表，你也可以@AssociationTable来指定关联表的信息。<br /><br />　　如:<br /><br /><table bordercolor="#ffcc66" width="90%" align="center" bgcolor="#dadacf" border="1"><tbody><tr><td>@ManyToMany(cascade = {CascadeType.CREATE, CascadeType.MERGE}, fetch = FetchType.EAGER, isInverse = true)<br />@AssociationTable(table = @Table(name = "STUDENT_TEACHER"),<br /><br />joinColumns = {@JoinColumn(name = "TEACHER_ID")},inverseJoinColumns = {@JoinColumn(name = "STUDENT_ID")})<br /><br />@ AssociationTable的注释声明如下：<br />@Target({METHOD, FIELD})<br /><br />public @interface AssociationTable {<br />　Table table() default @Table(specified=false);<br />　JoinColumn[] joinColumns() default {};<br />　JoinColumn[] inverseJoinColumns() default {};<br />}</td></tr></tbody></table><br />　　关联表注释指定了关联表的名称、主表的列和从表的列。<br /><br />　　为了实现一对一的关系，需要用@OneToOne来注释。 <br /><br />　　如:<br /><br /><table bordercolor="#ffcc66" width="90%" align="center" bgcolor="#dadacf" border="1"><tbody><tr><td>@OneToOne(cascade = {CascadeType.ALL})<br />@JoinColumn(name = "DOSSIER_ID")<br /><br />public Dossier getDossier()<br />{<br />　return dossier;<br />}</td></tr></tbody></table><br />　　这定义了一个单向的一对一的关系。如果在Dossier也定义了相关的关联，那么它就是双向的。双向的意思就是通过一个Student实体就可以查找到一个Dossier，通过一个Dossier就可以查找到一个Student。<br /><br /><table bordercolor="#ffcc66" width="90%" align="center" bgcolor="#dadacf" border="1"><tbody><tr><td>@ OneToOne的注释声明如下：<br />@Target({METHOD, FIELD}) @Retention(RUNTIME)<br /><br />public @interface OneToOne {<br />　String targetEntity() default "";<br />　CascadeType[] cascade() default {};<br />　FetchType fetch() default EAGER;<br />　boolean optional() default true;<br />}</td></tr></tbody></table><br />　　这个例子主要有以下几个文件，这个例子主要实现了学生和老师、学生和档案之间的关系。Student、Teacher、Dossier都是实体Bean。Student和Dossier是一个双向的OneToOne之间的关系，Student和Teacher是ManyToMany的关系，也是双向的。和前面的例子一样，我们还是使用Client测试。<br /><br />　　Student.java：实体Bean。<br /><br />　　Dossier.java：实体Bean所依赖的类。<br /><br />　　Teacher.java：实体Bean所依赖的类。<br /><br />　　EntityTest.java：会话Bean的业务接口<br /><br />　　EntityTest Bean.java：会话Bean的实现类<br /><br />　　Client.java：测试EJB的客户端类。<br /><br />　　jndi.properties：jndi属性文件，提供访问jdni的基本配置属性。<br /><br />　　Build.xml：ant 配置文件，用以编译、发布、测试、清除EJB。<br /><br />　　下面针对每个文件的内容做一个介绍。<br /><br />　　Student.java<br /><br /><table bordercolor="#ffcc66" width="90%" align="center" bgcolor="#dadacf" border="1"><tbody><tr><td>package com.kuaff.ejb3.relationships;<br />import javax.ejb.CascadeType;<br />import javax.ejb.Entity;<br />import javax.ejb.FetchType;<br />import javax.ejb.GeneratorType;<br />import javax.ejb.Id;<br />import javax.ejb.JoinColumn;<br />import javax.ejb.OneToOne;<br />import javax.ejb.ManyToMany;<br />import javax.ejb.Table;<br />import javax.ejb.AssociationTable;<br />import java.util.ArrayList;<br />import java.util.Set;<br />import java.util.Collection;<br />import java.io.Serializable;<br /><br />@Entity<br /><br />@Table(name = "STUDENT")<br /><br />public class Student implements Serializable<br /><br />{<br />　private int id;<br />　private String first;<br />　private String last;<br />　private Dossier dossier;<br />　private Set&lt;Teacher&gt; teachers;<br /><br />　@Id(generate = GeneratorType.AUTO)<br /><br />　public int getId()<br />　{<br />　　return id;<br />　}<br /><br />　public void setId(int id)<br />　{<br />　　this.id = id;<br />　}<br /><br />　public void setFirst(String first)<br />　{<br />　　this.first = first;<br />　}<br /><br />　public String getFirst()<br />　{<br />　　return first;<br />　}<br /><br />　public void setLast(String last)<br />　{<br />　　this.last = last;<br />　}<br /><br />　public String getLast()<br />　{<br />　　return last;<br />　}<br /><br />　public void setDossier(Dossier dossier)<br />　{<br />　　this.dossier = dossier;<br />　}<br /><br />@OneToOne(cascade = {CascadeType.ALL})<br />@JoinColumn(name = "DOSSIER_ID")<br /><br />public Dossier getDossier()<br />{<br />　return dossier;<br />}<br /><br />public void setTeacher(Set&lt;Teacher&gt; teachers)<br />{<br />　this.teachers = teachers;<br />}<br /><br />@ManyToMany(cascade = {CascadeType.CREATE, CascadeType.MERGE}, fetch = FetchType.EAGER, isInverse = true)<br />@AssociationTable(table = @Table(name = "STUDENT_TEACHER"),<br /><br />joinColumns = {@JoinColumn(name = "TEACHER_ID")},inverseJoinColumns = {@JoinColumn(name = "STUDENT_ID")})<br /><br />public Set&lt;Teacher&gt; getTeacher()<br />{<br />　return teachers;<br />}<br />}<br /><br /><br />　　Dossier.java<br /><br />package com.kuaff.ejb3.relationships;<br /><br />import javax.ejb.Entity;<br />import javax.ejb.GeneratorType;<br />import javax.ejb.Id;<br /><br />@Entity<br /><br />public class Dossier implements java.io.Serializable<br />{<br />　private Long id;<br />　private String resume;<br /><br />　@Id(generate = GeneratorType.AUTO)<br />　public Long getId()<br />　{<br />　　return id;<br />　}<br /><br />　public void setId(Long id)<br />　{<br />　　this.id = id;<br />　}<br /><br />　public void setResume(String resume)<br />　{<br />　　this.resume = resume;<br />　}<br /><br />　public String getResume()<br />　{<br />　　return resume;<br />　}<br />}<br /><br /></td></tr></tbody></table><br /><table cellspacing="0" cellpadding="0" width="776" border="0"><tbody><tr><td valign="top" bgcolor="#f0f2fb" height="10"></td></tr><tr><td valign="top" bgcolor="#f0f2fb"><table cellspacing="0" cellpadding="0" width="590" align="center" border="0"><tbody><tr><td><span class="f14">　　Teacher.java<br /><br /><table bordercolor="#ffcc66" width="90%" align="center" bgcolor="#dadacf" border="1"><tbody><tr><td>package com.kuaff.ejb3.relationships;<br /><br />import javax.ejb.AssociationTable;<br />import javax.ejb.Basic;<br />import javax.ejb.CascadeType;<br />import javax.ejb.Column;<br />import javax.ejb.Entity;<br />import javax.ejb.FetchType;<br />import javax.ejb.Id;<br />import javax.ejb.JoinColumn;<br />import javax.ejb.ManyToMany;<br />import javax.ejb.Table;<br />import javax.ejb.Transient;<br />import javax.ejb.Version;<br />import java.util.Set;<br />import javax.ejb.GeneratorType;<br /><br />@Entity<br /><br />public class Teacher implements java.io.Serializable<br />{<br />　private Long id;<br />　private String resume;<br />　private String name;<br />　private String info;<br />　private Set&lt;Student&gt; students;<br /><br />　@Id(generate = GeneratorType.IDENTITY) <br /><br />　public Long getId()<br />　{<br />　　return id;<br />　}<br /><br />　public void setId(Long id)<br />　{<br />　　this.id = id;<br />　}<br /><br />　public void setName(String name)<br />　{<br />　　this.name = name;<br />　}<br /><br />　public String getName()<br />　{<br />　　return name;<br />　}<br /><br />　public void setInfo(String info)<br />　{<br />　　this.info = info;<br />　}<br /><br />　public String getInfo()<br />　{<br />　　return info;<br />　}<br /><br />　public void setStudents(Set&lt;Student&gt; students)<br />　{<br />　　this.students = students;<br />　}<br /><br />　@ManyToMany(cascade = {CascadeType.CREATE, CascadeType.MERGE}, fetch = FetchType.EAGER)<br />　@AssociationTable(table = @Table(name = "STUDENT_TEACHER"),<br /><br />　joinColumns = {@JoinColumn(name = "TEACHER_ID",referencedColumnName="ID")},<br />　inverseJoinColumns = {@JoinColumn(name = "STUDENT_ID",referencedColumnName="ID")})<br /><br />　public Set&lt;Student&gt; getStudents()<br />　{<br />　　return students;<br />　}<br />}<br /></td></tr></tbody></table><br />　　EntityTest.java<br /><br /><table bordercolor="#ffcc66" width="90%" align="center" bgcolor="#dadacf" border="1"><tbody><tr><td>package com.kuaff.ejb3.relationships;<br /><br />import javax.ejb.Remote;<br />import java.util.List;<br /><br />@Remote<br /><br />public interface EntityTest<br />{<br />　public void createData();<br />　public List findByName(String name);<br />}</td></tr></tbody></table><br />　　EntityTestBean.java<br />　<br /><table bordercolor="#ffcc66" width="90%" align="center" bgcolor="#dadacf" border="1"><tbody><tr><td>package com.kuaff.ejb3.relationships;<br /><br />import javax.ejb.EntityManager;<br />import javax.ejb.Inject;<br />import javax.ejb.Stateless;<br />import java.util.HashSet;<br />import java.util.Set;<br />import java.util.List;<br /><br />@Stateless<br /><br />public class EntityTestBean implements EntityTest<br />{<br />　private @Inject EntityManager manager;<br />　public void createData()<br />　{<br />　　Teacher teacher1 = new Teacher();<br />　　Teacher teacher2 = new Teacher();<br /><br />　　Set&lt;Student&gt; students1 = new HashSet&lt;Student&gt;();<br />　　Set&lt;Student&gt; students2 = new HashSet&lt;Student&gt;();<br />　　Student student1 = new Student();<br />　　Student student2 = new Student();<br />　　Student student3 = new Student();<br /><br />　　Dossier dossier1 = new Dossier();<br />　　Dossier dossier2 = new Dossier();<br />　　Dossier dossier3 = new Dossier();<br />　　teacher1.setId(new Long(1));<br />　　teacher1.setName("hushisheng");<br />　　teacher1.setInfo("胡时胜教授，博士生导师");<br />　　manager.create(teacher1);<br />　　teacher2.setId(new Long(2));<br />　　teacher2.setName("liyongchi");<br />　　teacher2.setInfo("李永池教授，博士生导师");<br />　　manager.create(teacher2);<br /><br />　　student1.setFirst("晁");<br />　　student1.setLast("岳攀");<br />　　dossier1.setResume("这是晁岳攀的档案");<br />　　student1.setDossier(dossier1);<br />　　students1.add(student1);<br /><br />　　student2.setFirst("赵");<br />　　student2.setLast("志伟");<br />　　dossier2.setResume("这是赵志伟的档案");<br />　　student2.setDossier(dossier2);<br />　　students1.add(student2);<br /><br />　　student3.setFirst("田");<br />　　student3.setLast("明");<br /><br />　　dossier3.setResume("这是田明的档案");<br />　　student3.setDossier(dossier3);<br />　　students2.add(student3);<br /><br />　　teacher1.setStudents(students1);<br />　　teacher2.setStudents(students2);<br /><br />　}<br /><br />　public List findByName(String name)<br />　{<br />　　return manager.createQuery("from Teacher t where t.name = :name").setParameter("name", name).listResults();<br />　}<br /><br />}</td></tr></tbody></table><br />　　在这个会话Bean中提供了创建各个实体Bean的方法，并提供了查找老师的方法。<br /><br />　　Client.java<br /><br /><table bordercolor="#ffcc66" width="90%" align="center" bgcolor="#dadacf" border="1"><tbody><tr><td>package com.kuaff.ejb3.secondary;<br /><br />import javax.naming.InitialContext;<br />import javax.naming.NamingException;<br />import java.util.List;<br /><br />public class Client<br />{<br />　public static void main(String[] args) throws NamingException<br />　{<br />　　InitialContext ctx = new InitialContext();<br />　　StudentDAO dao = (StudentDAO) ctx.lookup(StudentDAO.class.getName());<br />　　int id = dao.create("晁","岳攀","8","smallnest@kuaff.com","男");<br />　　dao.create("朱","立焕","6","zhuzhu@kuaff.com","女");<br />　　List list = dao.findAll();<br />　　for(Object o:list)<br />　　{<br />　　　Student s = (Student)o;<br />　　　System.out.printf("%s%s的性别:%s%n",s.getName().getFirst(),s.getName().getLast(),s.getGender());<br />　　　dao.evict(s);<br />　　}<br />　}<br />} </td></tr></tbody></table><br />　　这个客户端用来测试。<br /><br />　　请运行{$JBOSS_HOME}/bin目录下的run.bat: run –c all,启动JBOSS。<br /><br />　　http://localhost:8080/jmx-console/HtmlAdaptor?action=inspectMBean&amp;name=jboss%3Aservice%3DHypersonic%2Cdatabase%3DlocalDB，然后调用startDatabaseManager()方法，打开HSQL管理工具管理数据库。<br /><br />　　在Eclipse的Ant视图中执行ejbjar target。或者在命令行下，进入到此工程目录下，执行ant ejbjar,将编译打包发布此EJB。<br /><br />　　在Eclipse的Ant视图中执行run target。或者在命令行下，进入到此工程目录下，执行ant run,测试这个EJB。</span><br /></td></tr></tbody></table></td></tr></tbody></table><img src ="http://www.blogjava.net/liaojiyong/aggbug/56459.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/liaojiyong/" target="_blank">liaojiyong</a> 2006-07-04 09:27 <a href="http://www.blogjava.net/liaojiyong/archive/2006/07/04/56459.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>EJB 3.0开发指南之多表映射</title><link>http://www.blogjava.net/liaojiyong/archive/2006/07/04/56458.html</link><dc:creator>liaojiyong</dc:creator><author>liaojiyong</author><pubDate>Tue, 04 Jul 2006 01:26:00 GMT</pubDate><guid>http://www.blogjava.net/liaojiyong/archive/2006/07/04/56458.html</guid><wfw:comment>http://www.blogjava.net/liaojiyong/comments/56458.html</wfw:comment><comments>http://www.blogjava.net/liaojiyong/archive/2006/07/04/56458.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/liaojiyong/comments/commentRss/56458.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/liaojiyong/services/trackbacks/56458.html</trackback:ping><description><![CDATA[在前面的例子中，我们每一个实体Bean只映射到数据库中的一张表上。事实上，一个实体Bean可以映射到多张表上。在一些需要字典表的项目上会经常用到，象以前我做过的项目，使用到很多国标规定的数据表。在我们下面这个例子中，性别作为一个字典表存在，学生这个实体将映射到学生信息表、性别表这两个表。 <br /><br />　　从表可以使用@SecondaryTable来注释：<br /><br /><table bordercolor="#ffcc66" width="90%" align="center" bgcolor="#dadacf" border="1"><tbody><tr><td>@Target({TYPE}) @Retention(RUNTIME)<br /><br />public @interface SecondaryTable {<br />　String name();<br />　String catalog() default "";<br />　String schema() default "";<br />　JoinColumn[] join() default {};<br />　UniqueConstraint[] uniqueConstraints() default {};<br />}</td></tr></tbody></table><br />　　这个注释可以指定表名、分类、schema、联合列、约束等。假如你使用多张表，你可以使用下面的注释来声明多张表:<br /><br /><table bordercolor="#ffcc66" width="90%" align="center" bgcolor="#dadacf" border="1"><tbody><tr><td>@SecondaryTable<br />@Target({TYPE}) @Retention(RUNTIME)<br /><br />public @interface SecondaryTables {<br />　SecondaryTable[] value() default {};<br />}</td></tr></tbody></table><br />　　这个例子主要有以下几个文件，这个例子主要实现了管理学生的功能。Student是一个实体Bean，这个Bean的name属性是一个类，也就是Name类，这个Name类就是一个依赖值对象。学生的性别映射到第二张表中。StudentDAOBean是一个无状态的会话Bean，用来调用实体Bean。和前面的例子一样，我们还是使用Client测试。<br /><br />　　这个例子和上一个例子基本相同，只是Student.java和Client有所不同。<br /><br />　　　Student.java：实体Bean。<br /><br />　　　Name.java：实体Bean所依赖的类。<br /><br />　　　StudentDAO.java：会话Bean的业务接口<br /><br />　　　StudentDAOBean.java：会话Bean的实现类<br /><br />　　　Client.java：测试EJB的客户端类。<br /><br />　　　jndi.properties：jndi属性文件，提供访问jdni的基本配置属性。<br /><br />　　　Build.xml：ant 配置文件，用以编译、发布、测试、清除EJB。<br /><br />　　下面针对每个文件的内容做一个介绍。<br /><br /><table bordercolor="#ffcc66" width="90%" align="center" bgcolor="#dadacf" border="1"><tbody><tr><td>Student.java<br /><br />package com.kuaff.ejb3.secondary;<br /><br />import javax.ejb.Dependent;<br />import javax.ejb.DependentAttribute;<br />import javax.ejb.Column;<br />import javax.ejb.Entity;<br />import javax.ejb.GeneratorType;<br />import javax.ejb.Id;<br />import javax.ejb.Table;<br />import javax.ejb.SecondaryTables;<br />import javax.ejb.SecondaryTable;<br />import javax.ejb.JoinColumn;<br /><br />@Entity <br />@Table(name = "STUDENT")<br />@SecondaryTables({<br />@SecondaryTable(name = "GENDER", join = {@JoinColumn(name = "GENDER_ID")})<br />})<br /><br />public class Student implements java.io.Serializable<br />{<br />　private int id;<br />　private Name name;<br />　private String grade;<br />　private String email;<br />　private String gender;<br /><br />　@Id(generate = GeneratorType.AUTO) <br /><br />　public int getId()<br />　{<br />　　return id;<br />　}<br /><br />　public void setId(int id)<br />　{<br />　　this.id = id;<br />　}<br /><br />　public void setName(Name name)<br />　{<br />　　this.name = name;<br />　}<br /><br />@Dependent({ @DependentAttribute(name = "first", column ={ @Column(name = "FIRST") }), <br /><br />@DependentAttribute(name = "last", column ={ @Column(name = "LAST") }) }) <br /><br />public Name getName()<br />{<br />　return name;<br />}<br /><br />public void setGrade(String grade)<br />{<br />　this.grade = grade;<br />}<br /><br />@Column(name = "GRADE") <br /><br />public String getGrade()<br />{<br />　return grade;<br />}<br /><br />public void setEmail(String email)<br />{<br />　this.email = email;<br />}<br /><br />@Column(name = "EMAIL") <br /><br />public String getEmail()<br />{<br />　return email;<br />}<br /><br />public void setGender(String gender)<br />{<br />　this.gender = gender;<br />}<br /><br />@Column(name = "gender", secondaryTable = "GENDER")<br /><br />public String getGender()<br />{<br />　return gender;<br />}<br /><br />}<br /></td></tr></tbody></table><br />　　Student.java实现了Student实体Bean，它提供学生的基本情况。在类上声明上加上了第二张表的注释：<br /><br /><table bordercolor="#ffcc66" width="90%" align="center" bgcolor="#dadacf" border="1"><tbody><tr><td>@SecondaryTables({<br />@SecondaryTable(name = "GENDER", join = {@JoinColumn(name = "GENDER_ID")})<br />})</td></tr></tbody></table><br />　　在gender属性上加上了映射第二张的注释：<br /><br /><table bordercolor="#ffcc66" width="90%" align="center" bgcolor="#dadacf" border="1"><tbody><tr><td>@Column(name = "gender", secondaryTable = "GENDER")<br /><br />Client.java<br /><br />package com.kuaff.ejb3.secondary;<br /><br />import javax.naming.InitialContext;<br /><br />import javax.naming.NamingException;<br /><br />import java.util.List;<br /><br /><br />public class Client<br />{<br />public static void main(String[] args) throws NamingException<br /><br />{<br /><br />InitialContext ctx = new InitialContext();<br /><br />StudentDAO dao = (StudentDAO) ctx.lookup(StudentDAO.class.getName());<br /><br />int id = dao.create("晁","岳攀","8","smallnest@kuaff.com","男");<br /><br />dao.create("朱","立焕","6","zhuzhu@kuaff.com","女");<br /><br /><br /><br />List list = dao.findAll();<br /><br />for(Object o:list)<br /><br />{<br /><br />Student s = (Student)o;<br /><br />System.out.printf("%s%s的性别:%s%n",s.getName().getFirst(),s.getName().getLast(),s.getGender());<br /><br />dao.evict(s);<br /><br />}</td></tr></tbody></table><br />　　这个客户端增加学生的分数，并且测试显示这个学生的email。<br /><br />　　请运行{$JBOSS_HOME}/bin目录下的run.bat: run –c all,启动JBOSS。<br /><br />http://localhost:8080/jmx-console/HtmlAdaptor?action=inspectMBean&amp;name=jboss%3Aservice%3DHypersonic%2Cdatabase%3DlocalDB，<br /><br />　　然后调用startDatabaseManager()方法，打开HSQL管理工具管理数据库。<br /><br />　　在Eclipse的Ant视图中执行ejbjar target。或者在命令行下，进入到此工程目录下，执行ant ejbjar,将编译打包发布此EJB。<br /><br />　　在Eclipse的Ant视图中执行run target。或者在命令行下，进入到此工程目录下，执行ant run,测试这个EJB。<br /><img src ="http://www.blogjava.net/liaojiyong/aggbug/56458.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/liaojiyong/" target="_blank">liaojiyong</a> 2006-07-04 09:26 <a href="http://www.blogjava.net/liaojiyong/archive/2006/07/04/56458.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>EJB 3.0开发指南之使用实体Bean</title><link>http://www.blogjava.net/liaojiyong/archive/2006/07/04/56456.html</link><dc:creator>liaojiyong</dc:creator><author>liaojiyong</author><pubDate>Tue, 04 Jul 2006 01:25:00 GMT</pubDate><guid>http://www.blogjava.net/liaojiyong/archive/2006/07/04/56456.html</guid><wfw:comment>http://www.blogjava.net/liaojiyong/comments/56456.html</wfw:comment><comments>http://www.blogjava.net/liaojiyong/archive/2006/07/04/56456.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.blogjava.net/liaojiyong/comments/commentRss/56456.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/liaojiyong/services/trackbacks/56456.html</trackback:ping><description><![CDATA[　在上面一个例子中，实体Bean的属性对应到数据表中的列，都是采用默认的设置。通过Column，你可以为属性指定数据表中的列名。 <br />Column的声明如下：<br /><br /><table bordercolor="#ffcc66" width="90%" align="center" bgcolor="#dadacf" border="1"><tbody><tr><td>@Target({TYPE, METHOD, FIELD}) @Retention(RUNTIME)<br />public @interface Column {<br />　String name() default "";<br />　boolean primaryKey() default false;<br />　boolean unique() default false;<br />　boolean nullable() default true;<br />　boolean insertable() default true;<br />　boolean updatable() default true;<br />　String columnDefinition() default "";<br />　String secondaryTable() default "";<br />　int length() default 255;<br />　int precision() default 0;<br />　int scale() default 0;<br />　boolean specified() default true; // For internal use only<br />}</td></tr></tbody></table><br />　　EntityManager 是用来处理实体Bean的辅助类。它可以用来产生/删除持久化的实体Bean，通过主键查找实体bean，通过查询语言来查询实体Bean。<br /><br />　　下面是EntityManager接口的声明：<br /><br /><table bordercolor="#ffcc66" width="90%" align="center" bgcolor="#dadacf" border="1"><tbody><tr><td>package javax.ejb;<br /><br />import java.sql.Connection;<br />/**<br />* 用来和持久化上下文交互的接口<br />*/<br /><br />public interface EntityManager {<br /><br />　/**<br />　* 使实体bean受持久化管理<br />　* @param entity<br />　*/<br /><br />　public void create(Object entity);<br />　<br />　/**<br />　* 将给定的实体Bean的状态和持久化上下文结合。类似数据库的更新操作。<br />　* @param entity<br />　* @return 被结合的实体实例<br />　*/<br /><br />　public &lt;T&gt; T merge(T entity);<br /><br />　/**<br />　* 删除实例<br />　* @param entity<br />　*/<br /><br />　public void remove(Object entity);<br />　/**<br />　* 根据主键查找.<br />　* @param entityName<br />　* @param primaryKey<br />　* @return 查询实例<br />　*/<br /><br />　public Object find(String entityName, Object primaryKey);<br />　/**<br />　* 根据主键查找<br />　* @param primaryKey<br />　* @return 查询实例<br />　*/<br /><br />　public &lt;T&gt; T find(Class&lt;T&gt; entityClass, Object primaryKey);<br />　/**<br />　* 持久化上下文与底层数据库的同步<br />　*/<br /><br />　public void flush();<br />　/**<br />　* 执行一个EJBQL查询<br />　* @param ejbqlString EJBQL查询语句<br />　* @return the new query instance<br />　*/<br /><br />　public Query createQuery(String ejbqlString);<br />　/**<br />　* 执行命名的查询<br />　* @param name 预定义的查询名称<br />　* @return 查询实例<br />　*/<br /><br />　public Query createNamedQuery(String name);<br />　/**<br />　* 执行一个本地SQL查询语句<br />　* @param sqlString 本地查询语句<br />　* @return 返回查询实例<br />　*/<br /><br />　public Query createNativeQuery(String sqlString);<br />　/**<br />　* 更新到数据库中<br />　* @param entity<br />　*/<br /><br />　public void refresh(Object entity);<br />　/**<br />　* 持久化上下文中删除实体<br />　* @param entity<br />　*/<br /><br />　public void evict(Object entity);<br />　/**<br />　* 检查当前上下文中是否包含此实体<br />　* context.<br />　* @param entity<br />　* @return<br />　*/<br /><br />　public boolean contains(Object entity);<br />}<br /></td></tr></tbody></table><br />　　@JoinColumns<br /><br />　　用来指示符合主键，在后面的章节中介绍。<br /><br />　　 这个例子主要有以下几个文件，这个例子主要实现了管理学生分数的功能。Student是一个实体Bean，管理学生的基本信息（姓名和各课分数），其中学生的分数又是一个实体Bean。TacherBean是一个无状态的会话Bean，用来调用实体Bean。和前面的例子一样，我们还是使用Client测试。<br /><br />　　·Student.java：实体Bean。<br /><br />　　·Score.java：实体Bean。<br /><br />　　·Teacher.java：会话Bean的业务接口<br /><br />　　·TeacherBean.java：会话Bean的实现类<br /><br />　　·Client.java：测试EJB的客户端类。<br /><br />　　·jndi.properties：jndi属性文件，提供访问jdni的基本配置属性。<br /><br />　　·Build.xml：ant 配置文件，用以编译、发布、测试、清除EJB。<br /><br />　　下面针对每个文件的内容做一个介绍。<br /><br />　　Student.java<br /><br /><table bordercolor="#ffcc66" width="90%" align="center" bgcolor="#dadacf" border="1"><tbody><tr><td>package com.kuaff.ejb3.entity;<br /><br />import javax.ejb.CascadeType;<br />import javax.ejb.Entity;<br />import javax.ejb.FetchType;<br />import javax.ejb.GeneratorType;<br />import javax.ejb.Id;<br />import javax.ejb.JoinColumn;<br />import javax.ejb.OneToMany;<br />import javax.ejb.Table;<br />import java.util.ArrayList;<br />import java.util.Collection;<br />import java.io.Serializable;<br /><br />@Entity<br />@Table(name = "STUDENT")<br /><br />public class Student implements Serializable<br />{<br />　//主键<br />　private int id;<br />　//学生名<br />　private String name;<br />　//学生的分数<br />　private Collection&lt;Score&gt; scores;<br />　//主键自动产生<br /><br />　@Id(generate = GeneratorType.AUTO)<br /><br />　public int getId()<br />　{<br />　　return id;<br />　}<br /><br />　public void setId(int id)<br />　{<br />　　this.id = id;<br />　}<br /><br />　public String getName()<br />　{<br />　　return name;<br />　}<br /><br />　public void setName(String name)<br />　{<br />　　this.name = name;<br />　}<br /><br />　public void addScores(String name,int number)<br />　{<br />　　if (scores == null)<br />　　{<br />　　　scores = new ArrayList&lt;Score&gt;();<br />　　}<br />　　Score score = new Score();<br />　　score.setName(name);<br />　　score.setNumber(number);<br />　　score.setStudent(this);<br />　　scores.add(score);<br />　}<br /><br />　@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)<br />　@JoinColumn(name = "student_id")<br /><br />　public Collection&lt;Score&gt; getScores()<br />　{<br />　　return scores;<br />　}<br /><br />　public void setScores(Collection&lt;Score&gt; scores)<br />　{<br />　　this.scores = scores;<br />　}<br />}</td></tr></tbody></table><br />　　Student.java实现了Student实体Bean，它提供学生的基本情况以及学生的得分情况，得分是另外一个实体Bean。Student实体Bean和Score实体Bean是一对多的关系，站在Score的角度看是多对一的关系。<br /><br />　　实体Bean需要使用@Entity做注释，另外它指定这个实体Bean与表STUDENT对应（通过注释@Table(name = "STUDENT")），你可以在JBOSS的数据库中看到这个表。<br /><br />　　Score.java<br /><br /><table bordercolor="#ffcc66" width="90%" align="center" bgcolor="#dadacf" border="1"><tbody><tr><td>package com.kuaff.ejb3.entity;<br /><br />import java.io.Serializable;<br />import javax.ejb.Entity;<br />import javax.ejb.GeneratorType;<br />import javax.ejb.Id;<br />import javax.ejb.JoinColumn;<br />import javax.ejb.ManyToOne;<br />import javax.ejb.Table;<br /><br />@Entity<br />@Table(name = "Score")<br /><br />public class Score implements Serializable<br />{<br />　private int id;<br />　private String name;<br />　private int number;<br />　private Student student;<br /><br />　//主键自动产生<br /><br />　@Id(generate = GeneratorType.AUTO)<br /><br />　public int getId()<br />　{<br />　　return id;<br />　}<br /><br />　public void setId(int id)<br />　{<br />　　this.id = id;<br />　}<br /><br />　public String getName()<br />　{<br />　　return name;<br />　}<br /><br />　public void setName(String name)<br />　{<br />　　this.name = name;<br />　}<br /><br />　public int getNumber()<br />　{<br />　　return number;<br />　}<br /><br />　public void setNumber(int number)<br />　{<br />　　this.number = number;<br />　}<br /><br />　@ManyToOne<br />　@JoinColumn(name = "student_id")<br /><br />　public Student getStudent()<br />　{<br />　　return student;<br />　}<br /><br />　public void setStudent(Student student)<br />　{<br />　　this.student = student;<br />　}<br /><br />} </td></tr></tbody></table><br />　　这个实体Bean存放学生的分数。<br /><br />　　Teacher.java<br /><br /><table bordercolor="#ffcc66" width="90%" align="center" bgcolor="#dadacf" border="1"><tbody><tr><td>package com.kuaff.ejb3.entity;<br /><br /><br /><br />import javax.ejb.Remote;<br /><br />import javax.ejb.Remove;<br /><br />import java.util.Map;<br /><br /><br /><br />@Remote<br /><br />public interface Teacher<br /><br />{<br /><br />public void addScore(String studentName,Map&lt;String,Integer&gt; map);<br /><br /><br /><br />public Student getStudent();<br /><br /><br /><br />@Remove<br /><br />public void leave();<br /><br />}</td></tr></tbody></table><br />　　这个会话Bean接口提供增加分数和得到用户的方法。<br /><br />　　TeacherBean.java<br /><br /><table bordercolor="#ffcc66" width="90%" align="center" bgcolor="#dadacf" border="1"><tbody><tr><td>package com.kuaff.ejb3.entity;<br /><br />import javax.ejb.EntityManager;<br />import javax.ejb.Inject;<br />import javax.ejb.Remove;<br />import javax.ejb.Stateful;<br />import java.util.Map;<br />import java.util.Set;<br /><br />@Stateful<br /><br />public class TeacherBean implements Teacher<br />{<br />　@Inject<br />　private EntityManager manager;<br />　private Student student;<br /><br />　public Student getStudent()<br />　{<br />　　return student;<br />　}<br /><br />　public void addScore(String studentName, Map&lt;String,Integer&gt; map)<br />　{<br />　　if (student == null)<br />　　{<br />　　　student = new Student();<br />　　}<br />　　student.setName(studentName);<br />　　Set&lt;String&gt; set = map.keySet();<br />　　for (String sname:set)<br />　　{<br />　　　student.addScores(sname,map.get(sname).intValue());<br />　　}<br />　}<br /><br />　@Remove<br /><br />　public void leave()<br />　{<br />　　manager.create(student);<br />　}<br /><br /><br /><br />}<br /></td></tr></tbody></table><br />　　这个是会话Bean的实现类。<br /><br />　　Client.java<br /><br /><table bordercolor="#ffcc66" width="90%" align="center" bgcolor="#dadacf" border="1"><tbody><tr><td>package com.kuaff.ejb3.entity;<br /><br />import java.util.Map;<br />import java.util.HashMap;<br />import java.util.Collection;<br />import javax.naming.InitialContext;<br />import javax.naming.NamingException;<br /><br />public class Client<br />{<br />　public static void main(String[] args) throws NamingException<br />　{<br />　　InitialContext ctx = new InitialContext();<br />　　Teacher teacher = (Teacher) ctx.lookup(Teacher.class.getName());<br />　　Map&lt;String,Integer&gt; map = new HashMap&lt;String,Integer&gt;();<br />　　map.put("语文",new Integer(98));<br />　　map.put("化学",new Integer(149));<br />　　map.put("物理",new Integer(143));<br />　　teacher.addScore("smallnest",map);<br />　　Student student = teacher.getStudent();<br />　　String name = student.getName();<br />　　System.out.printf("显示%s的分数:%n",name);<br />　　Collection&lt;Score&gt; c = student.getScores();<br /><br />　　for (Score score:c)<br />　　{<br />　　　System.out.printf("%s:%s%n",score.getName(),score.getNumber()+"");<br />　　}<br />　}<br />}<br /></td></tr></tbody></table><br />　　这个客户端增加学生的分数，并且测试显示这个学生的相关信息。<br /><br />　　请运行{$JBOSS_HOME}/bin目录下的run.bat: run –c all,启动JBOSS。<br /><br />http://localhost:8080/jmx-console/HtmlAdaptor?action=inspectMBean&amp;name=jboss%3Aservice%3DHypersonic%2Cdatabase%3DlocalDB，然后调用startDatabaseManager()方法，打开HSQL管理工具管理数据库。<br /><br />　　在Eclipse的Ant视图中执行ejbjar target。或者在命令行下，进入到此工程目录下，执行ant ejbjar,将编译打包发布此EJB。<br /><br />　　在Eclipse的Ant视图中执行run target。或者在命令行下，进入到此工程目录下，执行ant run,测试这个EJB。<br /><img src ="http://www.blogjava.net/liaojiyong/aggbug/56456.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/liaojiyong/" target="_blank">liaojiyong</a> 2006-07-04 09:25 <a href="http://www.blogjava.net/liaojiyong/archive/2006/07/04/56456.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>EJB 3.0 开发指南之依赖值对象</title><link>http://www.blogjava.net/liaojiyong/archive/2006/07/04/56457.html</link><dc:creator>liaojiyong</dc:creator><author>liaojiyong</author><pubDate>Tue, 04 Jul 2006 01:25:00 GMT</pubDate><guid>http://www.blogjava.net/liaojiyong/archive/2006/07/04/56457.html</guid><wfw:comment>http://www.blogjava.net/liaojiyong/comments/56457.html</wfw:comment><comments>http://www.blogjava.net/liaojiyong/archive/2006/07/04/56457.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/liaojiyong/comments/commentRss/56457.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/liaojiyong/services/trackbacks/56457.html</trackback:ping><description><![CDATA[在上面的章节我们提到，实体bean的属性可以是java基本对象、Date等，事实上，实体Bean的属性也可以是其他的java对象。这些Java对象不能直接从持久化上下文中读取，它依赖于主实体bean。不象关联实体Bean，在EJB3.0中不支持依赖值对象的集合。 <br /><br />　　依赖值对象不支持继承，这将在EJB3.1中在讨论。<br /><br />　　依赖类需要使用◎DependentObject来注释：<br /><br /><table bordercolor="#ffcc66" width="90%" align="center" bgcolor="#dadacf" border="1"><tbody><tr><td>@Target({TYPE}) @Retention(RUNTIME)<br />public @interface DependentObject {<br />　AccessType access() default PROPERTY;<br />}</td></tr></tbody></table><br />　　这个注释可以指定容器访问这个类的方法，是通过属性还是直接通过字段来访问。<br /><br />　　在实体Bean的一个属性需要使用依赖值对象，那么这个属性的get方法需要使用@Dependent注释：<br /><br /><table bordercolor="#ffcc66" width="90%" align="center" bgcolor="#dadacf" border="1"><tbody><tr><td>@Target({METHOD, FIELD}) @Retention(RUNTIME)<br />public @interface Dependent {<br />　DependentAttribute[] value() default {};<br />}</td></tr></tbody></table><br />　　这个注释可以指定依赖的属性DependentAttribute：<br /><br /><table bordercolor="#ffcc66" width="90%" align="center" bgcolor="#dadacf" border="1"><tbody><tr><td>@Target({}) @Retention(RUNTIME)<br /><br />public @interface DependentAttribute {<br />　String name();<br />　Column[] column() default {};<br />}</td></tr></tbody></table><br />　　可以指定属性名称和映射的列名。这里，一个主实体Bean的属性可以映射到数据表中的多列。<br /><br />　　如果你还不太明白，看下面的例子。<br /><br />　　这个例子主要有以下几个文件，这个例子主要实现了管理学生的功能。Student是一个实体Bean，这个Bean的name属性是一个类，也就是Name类，这个Name类就是一个依赖值对象。StudentDAOBean是一个无状态的会话Bean，用来调用实体Bean。和前面的例子一样，我们还是使用Client测试。<br /><br />　　·Student.java：实体Bean。<br /><br />　　·Name.java：实体Bean所依赖的类。<br /><br />　　·StudentDAO.java：会话Bean的业务接口<br /><br />　　·StudentDAOBean.java：会话Bean的实现类<br /><br />　　·Client.java：测试EJB的客户端类。<br /><br />　　·jndi.properties：jndi属性文件，提供访问jdni的基本配置属性。<br /><br />　　·Build.xml：ant 配置文件，用以编译、发布、测试、清除EJB。<br /><br />　　下面针对每个文件的内容做一个介绍。<br /><br />　　Student.java<br /><br /><table bordercolor="#ffcc66" width="90%" align="center" bgcolor="#dadacf" border="1"><tbody><tr><td>package com.kuaff.ejb3.dependent;<br /><br />import javax.ejb.Dependent;<br />import javax.ejb.DependentAttribute;<br />import javax.ejb.Column;<br />import javax.ejb.Entity;<br />import javax.ejb.GeneratorType;<br />import javax.ejb.Id;<br />import javax.ejb.Table;<br /><br />@Entity @Table(name = "STUDENT") public class Student implements java.io.Serializable<br />{<br />　private int id;<br />　private Name name;<br />　private String grade;<br />　private String email;<br /><br />　@Id(generate = GeneratorType.AUTO) <br /><br />　public int getId()<br />　{<br />　　return id;<br />　}<br /><br />　public void setId(int id)<br />　{<br />　　this.id = id;<br />　}<br /><br />　public void setName(Name name)<br />　{<br />　　this.name = name;<br />　}<br /><br />@Dependent(<br />{ @DependentAttribute(name = "first", column ={ @Column(name = "FIRST") }), <br />　@DependentAttribute(name = "last", column ={ @Column(name = "LAST") }) }) <br />　public Name getName()<br />　{<br />　　return name;<br />　}<br /><br />　public void setGrade(String grade)<br />　{<br />　　this.grade = grade;<br />　}<br /><br />　@Column(name = "GRADE") <br /><br />　public String getGrade()<br />　{<br />　　return grade;<br />　}<br /><br />　public void setEmail(String email)<br />　{<br />　　this.email = email;<br />　}<br /><br />　@Column(name = "EMAIL") <br /><br />　public String getEmail()<br />　{<br />　　return email;<br />　}<br />}<br /></td></tr></tbody></table><br />　　Student.java实现了Student实体Bean，它提供学生的基本情况。学生的姓名是Name类，通过@Dependent(<br /><br />{ @DependentAttribute(name = "first", column ={ @Column(name = "FIRST") }), <br /><br />@DependentAttribute(name = "last", column ={ @Column(name = "LAST") }) }) <br /><br />来声明，并指定这个依赖类的两个属性first和last，并映射到数据表的FIRST和LAST列上。<br /><br />　　Name.java<br /><br /><table bordercolor="#ffcc66" width="90%" align="center" bgcolor="#dadacf" border="1"><tbody><tr><td>package com.kuaff.ejb3.dependent;<br /><br />import java.io.Serializable;<br />import javax.ejb.AccessType;<br />import javax.ejb.DependentObject;<br /><br />@DependentObject(access = AccessType.PROPERTY)<br /><br />public class Name implements java.io.Serializable<br />{<br />　private String first;<br />　private String last;<br /><br />　public Name()<br />　{}<br /><br />　public Name(String first, String last)<br />　{<br />　　this.first = first;<br />　　this.last = last;<br />　}<br /><br />　public String getFirst()<br />　{<br />　　return first;<br />　}<br /><br />　public void setFirst(String first)<br />　{<br />　　this.first = first;<br />　}<br /><br />　public String getLast()<br />　{<br />　　return last;<br />　}<br /><br />　public void setLast(String last)<br />　{<br />　　this.last = last;<br />　}<br />}</td></tr></tbody></table><br />　　这个值对象也很简单，和一般的javaBean差不多，但有两个地方需要注意：<br /><br />　　1． 这个类实现了java.io.Serializable接口<br /><br />　　2． 这个类使用@DependentObject做了注释<br /><br />　　StudentDAO.java<br /><br /><table bordercolor="#ffcc66" width="90%" align="center" bgcolor="#dadacf" border="1"><tbody><tr><td>package com.kuaff.ejb3.dependent;<br /><br />import javax.ejb.Remote;<br />import java.util.List;<br /><br />@Remote<br /><br />public interface StudentDAO<br />{<br />　int create(String first, String last, String grade, String email);<br />　Student find(int id);<br />　List findByFirstName(String name);<br />　List findByLastName(String name);<br />　List findByEmail(String email);<br /><br />　void merge(Student s);<br />}</td></tr></tbody></table><br />　　这个会话Bean接口提供查找用户的方法。<br /><br />　　StudentDAOBean.java<br /><br /><table bordercolor="#ffcc66" width="90%" align="center" bgcolor="#dadacf" border="1"><tbody><tr><td>package com.kuaff.ejb3.dependent;<br /><br />import java.util.List;<br />import javax.ejb.EntityManager;<br />import javax.ejb.Inject;<br />import javax.ejb.Stateless;<br /><br />@Stateless<br /><br />public class StudentDAOBean implements StudentDAO<br />{<br />　@Inject<br />　private EntityManager manager;<br /><br />　public int create(String first, String last, String grade, String email)<br />　{<br />　　Student student = new Student();<br />　　student.setName(new Name(first,last));<br />　　student.setGrade(grade);<br />　　student.setEmail(email);<br />　　manager.create(student);<br />　　return student.getId();<br />　}<br /><br />　public Student find(int id)<br />　{<br />　　return manager.find(Student.class, id);<br />　}<br /><br />　public List findByFirstName(String name)<br />　{<br />　　return manager.createQuery("from Student s where s.name.last = :name").setParameter("name", name).listResults();<br />　}<br />　public List findByLastName(String name)<br />　{<br />　　return manager.createQuery("from Student s where s.name.first = :name").setParameter("name", name).listResults();<br />　}<br /><br />　public List findByEmail(String email)<br />　{<br />　　 return manager.createQuery("from Student s where s.email = :email").setParameter("email", email).listResults();<br />　}<br /><br />　public void merge(Student s)<br />　{<br />　　manager.merge(s);<br />　}<br /><br />}</td></tr></tbody></table><br />　　这个是会话Bean的实现类。可以看到根据值对象的属性查找主实体Bean。<br /><br />　　Client.java<br /><br /><table bordercolor="#ffcc66" width="90%" align="center" bgcolor="#dadacf" border="1"><tbody><tr><td>package com.kuaff.ejb3.dependent;<br /><br />import javax.naming.InitialContext;<br />import javax.naming.NamingException;<br />import java.util.List;<br /><br />public class Client<br />{<br />　public static void main(String[] args) throws NamingException<br />　{<br />　　InitialContext ctx = new InitialContext();<br />　　StudentDAO dao = (StudentDAO) ctx.lookup(StudentDAO.class.getName());<br />　　int id = dao.create("晁","岳攀","8","smallnest@kuaff.com");<br />　　dao.create("朱","立焕","6","zhuzhu@kuaff.com");<br />　　List list = dao.findByEmail("zhuzhu@kuaff.com");<br />　　for(Object o:list)<br />　　{<br />　　　Student s = (Student)o;<br />　　　System.out.printf("%s %s的email:%s%n",s.getName().getFirst(),s.getName().getLast(),s.getEmail());<br />　　}<br />　}<br />}<br /></td></tr></tbody></table><br />　　这个客户端增加学生的分数，并且测试显示这个学生的email。<br /><br />　　请运行{$JBOSS_HOME}/bin目录下的run.bat: run –c all,启动JBOSS。<br /><br />http://localhost:8080/jmx-console/HtmlAdaptor?action=inspectMBean&amp;name=jboss%3Aservice%3DHypersonic%2Cdatabase%3DlocalDB，然后调用startDatabaseManager()方法，打开HSQL管理工具管理数据库。<br /><br />　　在Eclipse的Ant视图中执行ejbjar target。或者在命令行下，进入到此工程目录下，执行ant ejbjar,将编译打包发布此EJB。<br /><br />　　在Eclipse的Ant视图中执行run target。或者在命令行下，进入到此工程目录下，执行ant run,测试这个EJB。<br /><img src ="http://www.blogjava.net/liaojiyong/aggbug/56457.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/liaojiyong/" target="_blank">liaojiyong</a> 2006-07-04 09:25 <a href="http://www.blogjava.net/liaojiyong/archive/2006/07/04/56457.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>EJB 3.0 开发指南之定时服务</title><link>http://www.blogjava.net/liaojiyong/archive/2006/07/04/56455.html</link><dc:creator>liaojiyong</dc:creator><author>liaojiyong</author><pubDate>Tue, 04 Jul 2006 01:24:00 GMT</pubDate><guid>http://www.blogjava.net/liaojiyong/archive/2006/07/04/56455.html</guid><wfw:comment>http://www.blogjava.net/liaojiyong/comments/56455.html</wfw:comment><comments>http://www.blogjava.net/liaojiyong/archive/2006/07/04/56455.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/liaojiyong/comments/commentRss/56455.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/liaojiyong/services/trackbacks/56455.html</trackback:ping><description><![CDATA[在EJB2.1的规范中需要实现ejbTimeout方法，当然还有ejbPassivate、ejbRemove等方法。在EJB3.0中，只有你想用它们的时候，你才必须创建它们，否则不必实现。 <br /><br />　　这个例子主要有5个文件，这个例子的Bean是一个无状态会话Bean：<br /><br />　　NewsTimer.java：业务接口。<br /><br />　　NewsTimer.java：业务实现类。将来我们开发的EJB也都是这样命名（在接口名上加上Bean）。<br /><br />　　Client.java：测试EJB的客户端类。<br /><br />　　jndi.properties：jndi属性文件，提供访问jdni的基本配置属性。<br /><br />　　Build.xml：ant 配置文件，用以编译、发布、测试、清除EJB。<br /><br />　　下面针对每个文件的内容做一个介绍。<br /><br /><table bordercolor="#ffcc66" width="90%" align="center" bgcolor="#dadacf" border="1"><tbody><tr><td>NewsTimer.java<br /><br />package com.kuaff.ejb3.schedule;<br />import javax.ejb.Remote;<br />@Remote<br /><br />public interface NewsTimer<br />{<br />　public void fiveNews();<br />}<br /></td></tr></tbody></table><br />　　这个接口定义了fiveNews方法，如果这个方法被调用，5分钟后将往控制台上输出一条新闻。<br /><br />　　你不必配置它的JNDI名称，也不必写它的配置文件。在JBOSS实现的EJB3.0中，你不必写任何的EJB部署文件和jboss部署文件。JBOSS默认使用接口的全称作为它的JNDI名。在上面的例子中，它的全称可以通过NewsTimerclass.forName()得到。<br /><br /><table bordercolor="#ffcc66" width="90%" align="center" bgcolor="#dadacf" border="1"><tbody><tr><td>NewsTimerBean.java<br /><br />package com.kuaff.ejb3.schedule;<br />import java.util.Date;<br />import javax.ejb.Inject;<br />import javax.ejb.SessionContext;<br />import javax.ejb.Stateless;<br />import javax.ejb.Timer;<br /><br />@Stateless<br /><br />public class NewsTimerBean implements NewsTimer<br />{<br />　private @Inject SessionContext ctx;<br />　public void fiveNews()<br />　{<br />　　ctx.getTimerService().createTimer(new Date(new Date().getTime() + 300000), "子虚乌有电视台5分钟新闻栏目:现在过5分钟，又到即时新闻节目的时间了。");<br />　}<br /><br />　public void ejbTimeout(Timer timer)<br />　{<br />　　System.out.printf("时间到:%n%s%n" , timer.getInfo());<br />　　timer.cancel();<br />　}<br />}<br /><br />Client.java<br /><br />package com.kuaff.ejb3.schedule;<br /><br />import javax.naming.InitialContext;<br />import javax.naming.NamingException;<br /><br />public class Client<br />{<br />　public static void main(String[] args) throws NamingException<br />　{<br />　　InitialContext ctx = new InitialContext();<br />　　NewsTimer timer = (NewsTimer) ctx.lookup(NewsTimer.class.getName());<br />　　timer.fiveNews();<br />　}<br />}<br /><br /></td></tr></tbody></table><br />　　这个类用来测试我们发布的计数器EJB。首先通过<br /><br /><table bordercolor="#ffcc66" width="90%" align="center" bgcolor="#dadacf" border="1"><tbody><tr><td>ctx = new InitialContext();</td></tr></tbody></table><br />　　得到上下文，然后通过lookup查找NewsTimer，然后启动计时。。<br /><br />　　请运行{$JBOSS_HOME}/bin目录下的run.bat: run –c all,启动JBOSS。<br /><br />　　在Eclipse的Ant视图中执行ejbjar target。或者在命令行下，进入到此工程目录下，执行ant ejbjar,将编译打包发布此EJB。<br /><br />　　在Eclipse的Ant视图中执行run target。或者在命令行下，进入到此工程目录下，执行ant run,测试这个EJB。<br /><img src ="http://www.blogjava.net/liaojiyong/aggbug/56455.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/liaojiyong/" target="_blank">liaojiyong</a> 2006-07-04 09:24 <a href="http://www.blogjava.net/liaojiyong/archive/2006/07/04/56455.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>EJB 3.0开发指南之依赖注入</title><link>http://www.blogjava.net/liaojiyong/archive/2006/07/04/56453.html</link><dc:creator>liaojiyong</dc:creator><author>liaojiyong</author><pubDate>Tue, 04 Jul 2006 01:23:00 GMT</pubDate><guid>http://www.blogjava.net/liaojiyong/archive/2006/07/04/56453.html</guid><wfw:comment>http://www.blogjava.net/liaojiyong/comments/56453.html</wfw:comment><comments>http://www.blogjava.net/liaojiyong/archive/2006/07/04/56453.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/liaojiyong/comments/commentRss/56453.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/liaojiyong/services/trackbacks/56453.html</trackback:ping><description><![CDATA[依赖注入（Dependency Injection），又称作控制反转(IOC)，本来是一种设计模式，现在被吵得热火朝天，有点过了。比较有名项目如String,picoContainer等。 <br /><br />　　在EJB3.0中，可以通过在字段和设置方法上加上注释注入依赖，我想在很快会有新的项目，或者在原来的项目的基础上，一些IOC容器会采用注释的方式注入依赖，JDK5.0加入的注释的确是一个很强大的功能，相对而言，在.net中的属性却没有发挥那么大的价值。这就是开源的威力，成千上万的在开源java程序员不断涌现出新的想法新的功能。<br /><br />　　看下面的例子：我们知道,JBOSS中已经默认配置了一个数据源，它的JNDI名称是"java:/DefaultDS"。下面这个例子声明了一个数据源，通过注释，就可以将JBOSS的这个默认的数据源赋值给它。<br /><br /><table bordercolor="#ffcc66" width="90%" align="center" bgcolor="#d8d8d1" border="1"><tbody><tr><td>@Resource(jndiName="java:/DefaultDS") <br />public DataSource customerDB;<br />Resource注释的声明<br />@Target({TYPE, METHOD, FIELD, PARAMETER}) @Retention(RUNTIME)<br /><br />public @interface Resource {<br /><br />String name() default "";<br /><br />String resourceType() default "";<br /><br />AuthenticationType authenticationType() default CONTAINER;<br /><br />boolean shareable() default true;<br /><br />String jndiName() default "";<br /><br />}<br /><br /><br />public enum Authentication Type {<br /><br />CONTAINER,<br /><br />APPLICATION<br /><br />}<br /><br />@Target(TYPE) @Retention(RUNTIME)<br /><br />public @interface Resources {<br /><br />Resource[] value();<br /><br />}</td></tr></tbody></table><br />　　Resource的name指向一个在环境属性中命名的资源，AuthenticationType用来指定是容器还是EJB组件来进行身份验证，sharebale指定是否共享,jndiName用来指定JDNI中的名称。resourceType()用来指定资源的类型。<br /><br />　　如果name和resourceType都指向被注释的程序成员，AuthenticationType和resourceType都是缺省的，则可以使用Inject注释：<br /><br /><table bordercolor="#ffcc66" width="90%" align="center" bgcolor="#d8d8d1" border="1"><tbody><tr><td>@Inject(jndiName="java:/DefaultDS") <br /><br />public DataSource customerDB;</td></tr></tbody></table><br />　　对于单例的成员，你可以更简化：<br /><br /><table bordercolor="#ffcc66" width="90%" align="center" bgcolor="#d8d8d1" border="1"><tbody><tr><td>@Inject javax.ejb.SessionContext ctx;<br /><br />@Inject javax.ejb.TimerService timer;<br /><br />@Inject javax.ejb.UserTransaction ut;<br /><br />@Inject javax.ejb.EntityManager manager;</td></tr></tbody></table><br />　　Resources注释可以注入多个资源。<br /><br />　　在Eclipse中导入本文提供的例子DI。<br /><br />　　这个例子从数据库中读取JMS_USER表，并显示表中的内容。这个例子使用依赖注入的方式得到JBOSS默认的数据源。<br /><br />　　这个例子主要有5个文件：<br /><br />　　　JmsUsers.java：业务接口。<br /><br />　　　JmsUsersBean.java：业务实现类。将来我们开发的EJB也都是这样命名（在接口名上加上Bean）。<br /><br />　　　Client.java：测试EJB的客户端类。<br /><br />　　　jndi.properties：jndi属性文件，提供访问jdni的基本配置属性。<br /><br />　　　Build.xml：ant 配置文件，用以编译、发布、测试、清除EJB。<br /><br />　　下面针对每个文件的内容做一个介绍。<br /><br /><table bordercolor="#ffcc66" width="90%" align="center" bgcolor="#d8d8d1" border="1"><tbody><tr><td>JmsUsers.java<br /><br />package com.kuaff.ejb3.di;<br />import java.util.List;<br />import javax.ejb.Remote;<br />import javax.sql.*;<br /><br />@Remote<br />public interface JmsUsers<br />{<br />　public List&lt;String&gt; getUsers();<br />}</td></tr></tbody></table><br />　　这个接口很简单，定义了一个得到全部用户的方法，JBOSS默认使用接口的全称作为它的JNDI名。在上面的例子中，它的全称可以通过JmsUsers.class。getName（）得到。<br /><br /><table bordercolor="#ffcc66" width="90%" align="center" bgcolor="#d8d8d1" border="1"><tbody><tr><td>CounterBean.java<br /><br />package com.kuaff.ejb3.di;<br />import java.util.List;<br />import java.util.ArrayList;<br />import javax.ejb.Stateless;<br />import javax.ejb.Resource;<br />import javax.sql.*;<br />import java.sql.*;<br /><br /><br />@Stateless<br />public class JmsUsersBean implements JmsUsers<br />{<br />　@Resource(jndiName="java:/DefaultDS",resourceType="javax.sql.DataSource") <br />　public DataSource customerDB;<br />　public List&lt;String&gt; getUsers() <br />　{<br />　　List&lt;String&gt; list = new ArrayList&lt;String&gt;();<br />　　try<br />　　{<br />　　　Connection conn = customerDB.getConnection();<br />　　　Statement st = conn.createStatement();<br />　　　ResultSet rs = st.executeQuery("select * from jms_users");<br />　　　while(rs.next())<br />　　　{<br />　　　　list.add(rs.getString("userid"));<br />　　　}<br />　　}<br />　　catch(SQLException e)<br />　　{}<br />　　return list;<br />　}<br />}</td></tr></tbody></table><br />　　这个是业务逻辑的具体实现。一旦这个EJB被容器产生，则容器将JBOSS的数据源注入到customerDB变量上，所以不要以为customerDB没有被初始化，这些工作是容器做的。<br /><br /><table bordercolor="#ffcc66" width="90%" align="center" bgcolor="#d8d8d1" border="1"><tbody><tr><td>Client.java<br /><br />package com.kuaff.ejb3.di;<br />import java.util.List;<br />import javax.naming.InitialContext;<br />import javax.naming.NamingException;<br /><br />public class Client<br />{<br />　public static void main(String[] args)<br />　{<br />　　InitialContext ctx;<br />　　try<br />　　{<br />　　　ctx = new InitialContext();<br />　　　JmsUsers users = (JmsUsers) ctx.lookup(JmsUsers.class.getName());<br />　　　List&lt;String&gt; jmsUsers = users.getUsers();<br />　　　for(String user:jmsUsers)<br />　　　{<br />　　　　System.out.printf("用户名:%s%n",user);<br />　　　}<br />　　}<br />　　catch (NamingException e)<br />　　{<br />　　　e.printStackTrace();<br />　　}<br />　}<br />}</td></tr></tbody></table><br />　　这个类用来测试我们发布的EJB组件。显示从JMS_USERS表中读取的数据。<br /><br />　　请运行{$JBOSS_HOME}/bin目录下的run.bat: run ?call,启动JBOSS。<br /><br />　　在Eclipse的Ant视图中执行ejbjar target。或者在命令行下，进入到此工程目录下，执行ant ejbjar,将编译打包发布此EJB<br /><br />　　在Eclipse的Ant视图中执行run target。或者在命令行下，进入到此工程目录下，执行ant run,测试这个EJB。<br /><img src ="http://www.blogjava.net/liaojiyong/aggbug/56453.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/liaojiyong/" target="_blank">liaojiyong</a> 2006-07-04 09:23 <a href="http://www.blogjava.net/liaojiyong/archive/2006/07/04/56453.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>EJB 3.0开发指南之消息驱动Bean</title><link>http://www.blogjava.net/liaojiyong/archive/2006/07/04/56454.html</link><dc:creator>liaojiyong</dc:creator><author>liaojiyong</author><pubDate>Tue, 04 Jul 2006 01:23:00 GMT</pubDate><guid>http://www.blogjava.net/liaojiyong/archive/2006/07/04/56454.html</guid><wfw:comment>http://www.blogjava.net/liaojiyong/comments/56454.html</wfw:comment><comments>http://www.blogjava.net/liaojiyong/archive/2006/07/04/56454.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/liaojiyong/comments/commentRss/56454.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/liaojiyong/services/trackbacks/56454.html</trackback:ping><description><![CDATA[消息驱动Bean的业务接口已经被定义，对于使用JMS来说那就是MessageListener接口，这个接口定义了OnMessage方法。 <br /><br />　　实现类必须使用MessageDriven注释。可以实现也可以不实现setMessageDrivenContext和ejbRemove方法。<br /><br />　　在JBOSS中，通过ConnectionConfig指定消息的队列的JNDI名称。<br /><br /><table bordercolor="#ffcc66" width="90%" align="center" bgcolor="#d8d8d1" border="1"><tbody><tr><td>@ConnectionConfig(destinationType = javax.jms.Queue.class, destinationJndiName = "queue/kuaffejb3/sample", durable = true, subscriptionId = "kuaffMessage")</td></tr></tbody></table><br />　　在Eclipse中导入本文提供的例子Messager。<br /><br />　　这个例子从客户端发送一个TextMessage，这个Bean组件接收到这个消息后，将把这个消息输出到控制台上。<br /><br />　　这个例子主要有5个文件：<br /><br />　　　Messager.java：业务组件。<br />　　<br />　　　Client.java：测试EJB的客户端类。<br />　<br />　　　jndi.properties：jndi属性文件，提供访问jdni的基本配置属性。<br /><br />　　　Build.xml：ant 配置文件，用以编译、发布、测试、清除EJB。<br /><br />　　　queue-example-service.xml：消息服务，用来测试消息。<br /><br />　　下面针对每个文件的内容做一个介绍。<br /><br /><table bordercolor="#ffcc66" width="90%" align="center" bgcolor="#d8d8d1" border="1"><tbody><tr><td>Messager.java<br /><br />package com.kuaff.ejb3.messager;<br /><br />import org.jboss.ejb3.mdb.ConnectionConfig;<br />import javax.ejb.MessageDriven;<br />import javax.jms.JMSException;<br />import javax.jms.Message;<br />import javax.jms.TextMessage;<br />import javax.jms.MessageListener;<br /><br />@MessageDriven <br />@ConnectionConfig(destinationType = javax.jms.Queue.class, destinationJndiName = "queue/kuaffejb3/sample", durable = true, subscriptionId = "kuaffMessage") <br /><br />public class Messager implements MessageListener<br />{<br />　public void onMessage(Message recvMsg)<br />　{<br />　　System.out.println("接收到的消息:");<br />　　try<br />　　{<br />　　　TextMessage message = (TextMessage)recvMsg;<br />　　　System.out.println(message.getText());<br />　　}<br />　　catch (JMSException e)<br />　　{<br />　　　e.printStackTrace();<br />　　}<br />　}<br />}</td></tr></tbody></table><br />　　这个消息Bean很简单，接收到消息后不做什么处理，就是将消息内容输出到控制台上，<br /><br /><table bordercolor="#ffcc66" width="90%" align="center" bgcolor="#d8d8d1" border="1"><tbody><tr><td>Client.java<br /><br />package com.kuaff.ejb3.messager;<br /><br />import javax.jms.Queue;<br />import javax.jms.QueueConnection;<br />import javax.jms.QueueConnectionFactory;<br />import javax.jms.QueueSender;<br />import javax.jms.QueueSession;<br />import javax.jms.TextMessage;<br />import javax.naming.InitialContext;<br /><br />public class Client<br />{<br />　public static void main(String[] args) throws Exception<br />　{<br />　　QueueConnection cnn = null;<br />　　QueueSender sender = null;<br />　　QueueSession session = null;<br />　　InitialContext ctx = new InitialContext();<br />　　Queue queue = (Queue) ctx.lookup("queue/kuaffejb3/sample");<br />　　QueueConnectionFactory factory = (QueueConnectionFactory) ctx.lookup("ConnectionFactory");<br />　　cnn = factory.createQueueConnection();<br />　　session = cnn.createQueueSession(false, QueueSession.AUTO_ACKNOWLEDGE);<br />　　TextMessage msg = session.createTextMessage("江湖快报:玉树临风风流倜傥的公子小巢又出现了。");<br />　　sender = session.createSender(queue);<br />　　sender.send(msg);<br />　　System.out.println("消息已经发出");<br />　}<br />}</td></tr></tbody></table><br />　　这个客户端将发送一个文本消息到队列中。<br /><br /><table bordercolor="#ffcc66" width="90%" align="center" bgcolor="#d8d8d1" border="1"><tbody><tr><td>queue-example-service.xml<br />＜?xml version="1.0" encoding="UTF-8"?＞<br />＜server＞<br />＜mbean code="org.jboss.mq.server.jmx.Queue" name="jboss.mq.destination:service=Queue,name=kuaffMessage"＞<br />　＜attribute name="JNDIName"＞queue/kuaffejb3/sample＜/attribute＞<br />　＜depends optional-attribute-name="DestinationManager"＞jboss.mq:service=DestinationManager＜/depends＞<br />＜/mbean＞<br />＜/server＞</td></tr></tbody></table><br />　　配置这个程序所需的消息服务。<br /><br />　　请运行{$JBOSS_HOME}/bin目录下的run.bat: run ?call,启动JBOSS。<br /><br />　　在Eclipse的Ant视图中执行ejbjar target。或者在命令行下，进入到此工程目录下，执行ant ejbjar,将编译打包发布此EJB。<br /><br />　　在Eclipse的Ant视图中执行run target。或者在命令行下，进入到此工程目录下，执行ant run,测试这个EJB。 <br /><br /><br /><img src ="http://www.blogjava.net/liaojiyong/aggbug/56454.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/liaojiyong/" target="_blank">liaojiyong</a> 2006-07-04 09:23 <a href="http://www.blogjava.net/liaojiyong/archive/2006/07/04/56454.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>EJB3.0开发指南之有状态会话Bean(转)</title><link>http://www.blogjava.net/liaojiyong/archive/2006/07/03/56244.html</link><dc:creator>liaojiyong</dc:creator><author>liaojiyong</author><pubDate>Mon, 03 Jul 2006 01:43:00 GMT</pubDate><guid>http://www.blogjava.net/liaojiyong/archive/2006/07/03/56244.html</guid><wfw:comment>http://www.blogjava.net/liaojiyong/comments/56244.html</wfw:comment><comments>http://www.blogjava.net/liaojiyong/archive/2006/07/03/56244.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/liaojiyong/comments/commentRss/56244.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/liaojiyong/services/trackbacks/56244.html</trackback:ping><description><![CDATA[　和无状态会话Bean一样，一个有状态会话Bean必须有一个业务接口，这个接口由会话Bean来实现，或者也可以由会话Bean来产生。这样，你可以只写一个文件，就可以生成业务逻辑实现类、远程接口、本地接口等。 <br /><br />　　在目前jboss的实现中，必须要有一个独立的业务接口。<br /><br />　　这个接口不必实现EJBObject或者EJBLocalObject。<br /><br />　　一个有状态会话Bean 必须使用Statelfull注释，以表明它是一个有状态的会话Bean。EJB容器将根据这个注释来判定它的类型。或者实现javax.ejb.SessionBean接口。<br /><br />　　一个有状态的会话Bean可以实现setSessionContext方法，也可以不实现。<br /><br />　　在EJB2.0中调用EJBObject.remove方法以达到从容器中删除有状态会话Bean的功能。在EJB3.0中只需在一些方法加上Remove注释。一旦这些被标记的方法被调用后，此EJB将从容器中删除。<br /><br />　　一个有状态的会话Bean可以通过依赖注入获取容器的资源和环境属性。<br /><br />　　在Eclipse中导入本文提供的例子Stateful。<br /><br />　　这个例子和无状态会话Bean的例子类似，下面只列出了不同的代码。<br /><br />　　这个例子主要有5个文件：<br /><br />　　　Counter.java：业务接口。<br /><br />　　　CounterBean.java：业务实现类。将来我们开发的EJB也都是这样命名（在接口名上加上Bean）。<br /><br />　　　Client.java：测试EJB的客户端类。<br /><br />　　　jndi.properties：jndi属性文件，提供访问jdni的基本配置属性。<br /><br />　　　Build.xml：ant 配置文件，用以编译、发布、测试、清除EJB。<br /><br />　　下面针对每个文件的内容做一个介绍。<br /><br /><table bordercolor="#ffcc66" width="90%" align="center" bgcolor="#d8d8d1" border="1"><tbody><tr><td>Counter.java<br />……<br />import javax.ejb.Remove;<br />……<br />@Remote<br /><br />public interface Counter<br />{<br />　……<br />　@Remove<br />　public void clean();<br />}</td></tr></tbody></table><br /><br />　　这个接口很简单，和无状态会话Bean基本相同，但新增加了一个Clean方法，并为此方法加上Remove注释。一旦此方法被执行完毕，此Bean将被从容器中删除。<br /><br />　　JBOSS默认使用接口的全称作为它的JNDI名。在上面的例子中，它的全称就是：com.kuaff.ejb3.stateful.Counter，你也可以通过Counter.class得到。<br /><br /><table bordercolor="#ffcc66" width="90%" align="center" bgcolor="#d8d8d1" border="1"><tbody><tr><td>CounterBean.java<br />……<br />import javax.ejb.Stateful;<br />……<br />@Stateful<br /><br />public class CounterBean implements Counter<br />{<br />　//增加事务支持 <br />　@Tx(TxType.REQUIRESNEW)<br />　public int getNumber()<br />　{<br />　　return number;<br />　}<br /><br />　@Remove<br /><br />　public void clean()<br />　{<br />　　System.out.println("我，被删除了!");<br />　}<br />}</td></tr></tbody></table><br />　　这个是计数器的实现类。注意这个类使用Stateful做了注释，这是必须的。同时，这个例子也演示了如何使用事务。事务的详细用法将在后面的章节中介绍。<br /><br /><table bordercolor="#ffcc66" width="90%" align="center" bgcolor="#d8d8d1" border="1"><tbody><tr><td>Client.java<br />package com.kuaff.ejb3.stateful;<br /><br />import javax.ejb.EJBException;<br />import java.rmi.NoSuchObjectException;<br />import javax.naming.InitialContext;<br />import javax.naming.NamingException;<br /><br />public class Client<br />{<br />　public static void main(String[] args)<br />　{<br />　　InitialContext ctx;<br />　　try<br />　　{<br />　　　ctx = new InitialContext();<br />　　　Counter counter = (Counter) ctx.lookup(Counter.class.getName());<br />　　　counter.add(10);<br />　　　System.out.println("当前的number:" + counter.getNumber());<br />　　　counter.add(10);<br />　　　System.out.println("当前的number:" + counter.getNumber());<br />　　　Counter counter2 = (Counter) ctx.lookup(Counter.class.getName());<br />　　　counter2.add(10);<br />　　　System.out.println("当前的number:" + counter2.getNumber());<br />　　　//删除<br />　　　counter2.clean();<br />　　　//下面如果再使用counter2,将出错<br />　　　try<br />　　　{<br />　　　　System.out.println("当前的number:" + counter2.getNumber());<br />　　　}<br />　　　catch(EJBException ex)<br />　　　{<br />　　　　if (ex.getCausedByException() instanceof NoSuchObjectException)<br />　　　　{<br />　　　　　System.out.println("我都被删除啦，还找我！");<br />　　　　}<br />　　　　else<br />　　　　{<br />　　　　　throw ex;<br />　　　　}<br />　　　}<br />　　}<br />　　catch (NamingException e)<br />　　{<br />　　　e.printStackTrace();<br />　　}<br />　}<br />}</td></tr></tbody></table><br />　　这个类用来测试我们发布的计数器EJB。首先通过<br /><br />　　ctx = new InitialContext();得到上下文，然后通过lookup查找计数器，然后给计数器加10，显示当前的计数器信息。最后调用Clean方法，一旦这个方法执行完毕，此EJB将从容器中删除，在使用这个EJB将会出现异常。<br /><br />　　请运行{$JBOSS_HOME}/bin目录下的run.bat: run ?call,启动JBOSS。<br /><br />　　在Eclipse的Ant视图中执行ejbjar target。或者在命令行下，进入到此工程目录下，执行ant ejbjar,将编译打包发布此EJB。<br /><br />　　在Eclipse的Ant视图中执行run target。或者在命令行下，进入到此工程目录下，执行ant run,测试这个EJB。<br /><p><strong><font color="#212121" size="5"></font></strong> </p><img src ="http://www.blogjava.net/liaojiyong/aggbug/56244.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/liaojiyong/" target="_blank">liaojiyong</a> 2006-07-03 09:43 <a href="http://www.blogjava.net/liaojiyong/archive/2006/07/03/56244.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>EJB设计模式概述（转）</title><link>http://www.blogjava.net/liaojiyong/archive/2006/07/03/56241.html</link><dc:creator>liaojiyong</dc:creator><author>liaojiyong</author><pubDate>Mon, 03 Jul 2006 01:30:00 GMT</pubDate><guid>http://www.blogjava.net/liaojiyong/archive/2006/07/03/56241.html</guid><wfw:comment>http://www.blogjava.net/liaojiyong/comments/56241.html</wfw:comment><comments>http://www.blogjava.net/liaojiyong/archive/2006/07/03/56241.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/liaojiyong/comments/commentRss/56241.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/liaojiyong/services/trackbacks/56241.html</trackback:ping><description><![CDATA[
		<br />
		<br />
		<table cellspacing="0" cellpadding="0" width="100%" border="0">
				<tbody>
						<tr>
								<td height="64">
										<br />
										<script language="JavaScript" src="http://203.81.25.103/cgi-bin/beadevcount.cgi?d_id=85" type="text/JavaScript">
										</script>
										<br />本文关键字：<a href="http://dev2dev.bea.com.cn/products/search.jsp?searchtype=keywords&amp;keywords=EJB">EJB</a>, <a href="http://dev2dev.bea.com.cn/products/search.jsp?searchtype=keywords&amp;keywords=设计模式">设计模式</a>, <a href="http://dev2dev.bea.com.cn/products/search.jsp?searchtype=keywords&amp;keywords=pattern">pattern</a>, <a href="http://dev2dev.bea.com.cn/products/search.jsp?searchtype=keywords&amp;keywords=session bean">session bean</a>, <a href="http://dev2dev.bea.com.cn/products/search.jsp?searchtype=keywords&amp;keywords=entity bean">entity bean</a>, <a href="http://dev2dev.bea.com.cn/products/search.jsp?searchtype=keywords&amp;keywords=message driven bean">message driven bean</a>, <a href="http://dev2dev.bea.com.cn/products/search.jsp?searchtype=keywords&amp;keywords=command">command</a>, <a href="http://dev2dev.bea.com.cn/products/search.jsp?searchtype=keywords&amp;keywords=dto">dto</a>, <a href="http://dev2dev.bea.com.cn/products/search.jsp?searchtype=keywords&amp;keywords=factory">factory</a></td>
								<td>
										<table class="box_content" cellspacing="0" cellpadding="0" border="0">
												<tbody>
														<tr>
																<td>
																		<span class="h2b">文章工具</span>
																		<br />
																		<img height="10" alt="推荐给朋友" src="http://dev2dev.bea.com.cn/images/letter001.gif" width="19" align="absMiddle" /> <a href="javascript:sendmail()">推荐给朋友</a><br /><img height="18" alt="打印文章" src="http://dev2dev.bea.com.cn/images/print001.gif" width="19" align="absMiddle" /> <a href="javascript:window.print()">打印文章</a></td>
														</tr>
												</tbody>
										</table>
								</td>
						</tr>
				</tbody>
		</table>
		<!-- 提取技术文章 -->
		<div class="beas">
				<img height="1" alt="" src="http://dev2dev.bea.com.cn/images/dot6B6B6B.gif" width="100%" />
		</div>一． 设计模式重要性<br />采用ＥＪＢ技术的Ｊ２ＥＥ项目中，ＥＪＢ架构的设计好坏将直接影响系统的性能、可扩展性、可维护性、组件可重用性及开发效率。项目越复杂，项目队伍越庞大则越能体现良好设计的重要性。 
<p>二． 常见EJB设计模式<br /><br />Session Facade Pattern <br />通常项目中，客户端往往需要频繁的对服务器端数据进行操作。当采用实体ＥＪＢ作为数据的抽象层时，如果直接让客户端程序与实体ＥＪＢ交互，会产生实现一个业务需求便需要大量的ＥＪＢ属性操作（如下图１）。这直接导致如下问题：网络负载大（远程客户端时）、并发性能低、客户端与服务器端关联度大、可重用性和可维护性差、性能 <br />因此有必要在客户端与实体ＥＪＢ层间加入Session　ＥＪＢ层，在Sessino EJB中实现商业逻辑并封装对实体ＥＪＢ的操作。（如下图２）<br /><img height="384" src="http://dev2dev.bea.com.cn/images/article/other031028/image001.jpg" width="573" /><br />图１：客户端直接与实体ＥＪＢ交互<br /><img height="407" src="http://dev2dev.bea.com.cn/images/article/other031028/image002.gif" width="543" /><br />图２：通过SessionEJB层实现<br />Session Fa?ade模式的好处是：降低了网络负载，SessionEjb可以调用实体ＥＪＢ的本地接口；将商业逻辑与商业数据隔离；维护与开发方便；显著提高性能。<br />Session Fa?ade模式因其简单使用，是目前使用很广的模式。但具体应用过程中应注意：避免将所有的操作封装到一个很大的SessionEJB内；服务器端数据结构应由实体EJB实现,除非特例否则避免直接的数据库操作；SessionEjb内某些系统通用操作的代码容易重复（比如权限检查等，解决办法是将系统通用服务封装在Java Class内）。</p><p><b>Message Facade Pattern</b><br />很多时候，一次Request需要操作多个ＥＪＢ又不需要得到即时返回。对这种异步调用，通常应用Message Fa?ade Pattern.<br />这种时候，如采用Session Fa?ade Pattern存在如下问题：<br />1. 客户端等待返回的时间过长。一个SessionEjb的实例在完成客户请求过程中中涉及到的每一次对其他实体Ejb的调用过程中都会被锁定直到得到实体EJB返回信息后才能进行下一步操作。这样造成客户不必要的等待，并很容易因时间导致整个事务失败。<br />2. 系统可靠性和容错性低。如果需要调用不同系统或服务器上或多个异构数据源的多个ＥＪＢ时，任何一个环节出错，均导致客户请求失败。<br />以Message-Driven Bean为基础的Message Facade Pattern则可以解决上述异步请求需求。具体架构见下图３ <br /><img height="427" src="http://dev2dev.bea.com.cn/images/article/other031028/image004.jpg" width="672" /><br />　图３：使用Message Facade Pattern</p><p>Message Facade Pattern的不足之处在于：<br />１． Message-Driven Bean没有返回值。这样通知客户执行结果只能依赖于Ｅｍａｉｌ或人工等其他手段。<br />２． Message-Driven Bean执行过程中无法将捕获的异常直接返回给客户端，即无法使客户端直接直到错误信息。<br />３． Message-Driven Bean通过接收Message响应客户请求，对Message内容的合法性（比如对象的类型等）依赖与客户端.容易产生运行时错误。<br />Message Facade Pattern经常与Session Facade Pattern在同一个项目里共同使用。</p><p><b>EJB Command Pattern</b></p><p>Session Facade Pattern中将商业逻辑实现封装在Session EJB中，这种做法带来诸多益处之外也带来如下问题：<br />１． 由于业务经常的变化，导致经常需要更新Session EJB代码。<br />２． 客户端代码不得不包含大量EJB相关的ＡＰＩ，不利于后期项目维护。<br />３． 项目开发测试需要经常的EJB重部署过程。<br />引起上述问题的重要根结就是Session EJB本身重量级组件，其开发测试部署工作量较大，开发周期较长。以上不足可以通过EJB Command Pattern克服。<br />EJB Command Pattern中将商业逻辑实现封装在普通的Java Class（称之为Command Bean）中。该模式的具体实现有很多种，通常的框架都包括三部分： <br />１． Command Bean.由应用开发者写的具体实现某商业操作的Java Class.主要包含getXXX(),setXXX(),execute()方法。<br />２． Client-Side Routing Logic.由多个Class组成，用于将请求转发至Command Sever，这个过程对客户是透明的。这部分代码可以跨项目使用。路由规则中可以考虑用ＸＭＬ技术。<br />３． Remote Command Server.实际执行商业操作请求。通常可以用Session EJB层实现。</p><p>　整个框架见下图４：<br /></p><p><br /><img height="415" src="http://dev2dev.bea.com.cn/images/article/other031028/image006.jpg" width="684" /><br />　图４：Command的基本框架<br />EJB Command Pattern具有如下好处：<br />１． 适应与需要快速开发环境。因Command Bean是轻量级的Java Class，其编译和调试比较方便。<br />２． 将表现层与商业实现层隔离，同时将客户端代码与EJB层隔离。<br />３． 将客户端代码开发与服务器端代码开发相对清晰。早期可以创建空的Command Bean方便客户端代码调试。<br />　　　　EJB Command Pattern的弱处在于：<br />１． Command Bean中对事务的控制不如Session EJB中。<br />２． Command Bean是无状态的。<br />３． 无法将异常直接返回给客户。<br />４． 在大项目中，由于商业逻辑复杂，常导致大数量的Command Bean存在.<br />５． 作为Command Server的Session EJB打包时必须包含Command Bean以致存在维护上的不便。<br />　　EJB Command Pattern的一个实际实现可以参考IBM's Command Framework.</p><p><br /><b>Data Transfer Object Factory</b><br />基于EJB的J2EE项目，经常需要在客户端与服务器端传输大量数据。数据的组织形式常用的是DTO(Data Transfer Object，服务器端数据对象的抽象)。但因为客户端表现层经常是变化的，所需要服务器端数据也变动频繁，换句话说，DTO的数量和属性经常要更改。因此如何以及在何处生成和维护DTO便是需要考虑的问题。<br />一种解决方案是直接在Entity EJB中直接处理，即在Entity EJB的Bean类中加入getXXXDTO()、setXXXDTO()等。但这样做导致EJB与DTO层紧紧绑定。一旦DTO更改，与该DTO相关的EJB即需要重编译打包。EJB层与客户端层相关联不仅使维护困难而且导致EJB的重用性大大降低。<br />更好的解决方案是利用Data Transfer Object Factory封装对DTO的操作逻辑（如下图６）。<br /></p><p><img height="293" src="http://dev2dev.bea.com.cn/images/article/other031028/image008.jpg" width="278" /><br />图６：DTO Factory示例<br />DTO Factory具体实现方式通常有两种：<br />１． 普通Java Class实现，用于Session Facade Pattern使用DTO环境下。<br />２． Stateless Session EJB实现，用于非EJB客户端使用DTO环境下（见图７）。<br /></p><p><img height="382" src="http://dev2dev.bea.com.cn/images/article/other031028/image010.jpg" width="624" /><br />图７：SessionEJB实现DTOFactory<br />DTO Factory带来如下好处：<br />１． 使Entity EJB的重用成为可能。由于不含DTO处理逻辑，Entity EJB功能单一化，只作为数据源。不通客户端通过各自的DTO Factory可以从同一个Entity EJB得到各自所需的个性化数据（自定义DTO）。<br />２． 提高可维护性和性能。<br />３． 可以根据在DTO Factory层生成很复杂的DTO结构，诸如继承、关联关系等，而对客户端提供一个透明、细化的数据接口。<br />　　　使用DTO Factory时需要注意的是：不需为每个Entity EJB定义一个Factory。可以为一系列相关的Entity EJB创建一个Factory，或者只创建一个Factory。</p><p><b>Generic Attribute Access</b></p><p>使用Entity EJB作为商业数据层时，我们首先需要从数据库加载数据，创建对应的Entity EJB实例，之后对内存中Entity EJB实例的属性进行相应操作。对属性的操作比较直接的做法是：直接调用Entity EJB的getXXX()/setXXX()，通常利用EJB2.0的本地接口；通过DTO Factory生成DTO。但这两种做法都存在如下问题：<br />１． 当Entity EJB的属性特别多时候，以上做法会带来复杂罗嗦的代码，使EJB变的庞大无比。<br />２． 使Entity EJB的客户端（比如Session EJB）和Entity EJB的接口紧密关联。Entity EJB属性的增删都需要更改客户端代码，给项目开发和维护带来不便。<br />事实上可以利用更通用的方式访问Entity EJB的属性，即定义Generic Attribute Access Interface。见下图８：<br /></p><p><img height="118" src="http://dev2dev.bea.com.cn/images/article/other031028/image012.jpg" width="588" /><br />　图８：Generic Attribute Access Interface示例</p><p>Generic Attribute Access Interface由Entity EJB的本地或远程接口实现，并利用Hash Maps传输数据。实现方式常见如下：<br />１． BMP类型实体EJB可以在Bean类中定义包含所有属性的私有成员变量HashMap。<br />２． CMP类型实体EJB可以在Bean类中可以适用Java Reflection API实现。<br />３． 建立一个父类，在不同的情况下定义子类重载父类方法。<br />使用Generic Attribute Access Interface需要在客户端与服务器端对属性以及对应的关键字建立统一的命名习惯。常见的做法如下：<br />１． 建立并保持良好的文档记录和命名约定。<br />２． 在实体EJB的实现类中定义静态成员映射属性。<br />３． 创建共享静态类，通过成员变量映射实体EJB属性。<br />４． 通过JNDI在服务器端保存属性映射关系。<br />Generic Attribute Access Interface的运用带来一下益处：<br />１． 接口实现后对不通实体EJB都适用。<br />２． 对属性较多实体EJB能精简代码，并更具维护性。<br />３． 使运行中动态增删实体EJB属性成为可能。<br />Generic Attribute Access Interface的缺点在于：<br />１． 访问EJB属性时增加了额外的操作。需要通过关键字映射属性，最后还需进行类型转换。<br />２． 需要建立客户端与服务器端的命名约定。 <br />３． 因为通过HashMap操作时候需要进行类型转换，容易产生运行时类型不匹配异常。</p><p><b><br />Business Interface </b></p><p>EJB规范要求Bean实现类必须实现所有在远程（或本地）接口中定义的所有方法，同时不允许Bean实现类直接继承远程（或本地）接口。这就导致编译时候很容易产生两者不一致的问题，即远程（或本地）接口中定义的某方法为在Bean实现类中被实现等错误。为避免上诉错误，可以利用应用服务器厂商所提供的工具。但也可以应用EJB的设计架构来实现：定义商业接口。<br />Business Interface即创建自定义商业接口，在接口中定义所有EJB提供的商业方法，并让Bean实现类和远程（或本地）接口都实现该商业接口。其继承关系见下图９：<br /></p><p><img height="464" src="http://dev2dev.bea.com.cn/images/article/other031028/image014.jpg" width="552" /><br />图９：商业接口的使用<br />Business Interface是个普通的Java Class。依赖于使用本地接口与远程接口的不通，Business Interface的定义略有不同：应用与远程接口时，在接口中的方法需要抛出java.rmi.RemoteException；而应用与本地接口时候则不需要作任何特别处理。<br />应用Business Interface时候必须注意一点：EJB规范不允许直接EJB的实例将对自己的引用（this对象）返回给客户端，否则编译时候即报错。但使用Business Interface后，编译时候无法检查出有无将this对象返回给客户端。这一点需要程序员自己保证。</p><p><br />三． 内部数据转换策略</p><p><b>Data Transfer Object</b><br />基于EJB的J2EE多层架构应用中，经常涉及的一个问题就是如何在各层之间传递批量数据，比如客户端对服务器端数据的批量读写操作等。比如需要得到实体EJB的属性，直接的方法是多次调用不通的属性，如下图１０：<br /></p><p><img height="324" src="http://dev2dev.bea.com.cn/images/article/other031028/image016.jpg" width="496" /><br />图１０：低效的数据传递方式<br />　　但这种方法容易导致许多问题，比如性能以及代码的复杂度等，更有效的办法是在一个调用中得到所有需要的属性。所以可以引入Data Transfer Object来封装所需要的属性，并在客户与服务器端通过传递该对象一次实现对数据的操作。如下图１１：<br /><img height="310" src="http://dev2dev.bea.com.cn/images/article/other031028/image017.gif" width="501" /><br />　图１１：通过DTO传递数据<br />　　<br />DTO为普通的Java Class，通常是服务器端数据的快照。由于网络传输的需要，DTO应该实现java.io.Serializable接口。<br />DTO的设计有两种模型：Domain DTO以及Custom DTO。<br />Domain DTO仅仅实现对服务器数据的拷贝，通常与实体EJB为一对一的关系(也存在为多个相关联的实体EJB对应一个Domain DTO)。Domain DTO通常除用于读取更改实体EJB属性外也可用于创建实体EJB时候。实体EJB与Domain DTO对应关系如下图１２：<br /><img height="244" src="http://dev2dev.bea.com.cn/images/article/other031028/image018.gif" width="467" /><br />　图１２：Account EJB 与　Account DomainDTO<br />Domain DTO的应用除了DTO所具有的一般优点外，还有别的益处：<br />１． 开发迅速。因为一旦实体EJB设计好后，很容易转换得到Domain DTO。<br />２． 可以利用Domain DTO的setXXX()方法在客户端进行属性有效性效验。<br />Domain DTO的缺点有：<br />１． 客户端绑定了服务器端数据模型，不利于维护。<br />２． 不够灵活，无法处理客户端的多样化数据要求。对一个数百个属性的实体EJB请求一个属性时候却返回一个包含所有属性值的Domain DTO明显是笨重的实现。<br />３． 导致代码的重复。<br />４． Domain DTO中如果嵌套包含了别的Domain DTO时，一旦需服务器端数据的更改而需要重定义Domain DTO模型时候异常困难。</p><p>Custom DTO则可以克服上述的一些缺点。Customer DTO仅仅封装用户感兴趣的服务器数据集即可以根据客户端需求创建Customer DTO。这样作的优点是灵活高效；缺点是大项目中可能导致大量的Customer DTO存在。<br />通常Domain DTO可以用于数据的更新与创建；Customer DTO可以用于客户用于表现层的数据读取。两者可以相辅相成。而且使用DTO一般与DTO Factory同时使用。</p><p><b>Domain Transfer Hash Map</b><br />　　DTO的使用往往缺乏通用性。不通的用户案例需要创建不同的DTO。当项目很复杂时，从维护性考虑需要更好的数据传输的实现方式。 <br />Domain Transfer Hash Map即利用HashMap作为客户所需数据集的封装。好处是：<br />１． 良好的维护性。<br />２． 较大的通用性。不同的客户端可以使用相同的数据传递方式。<br />缺点是：<br />１． 需要维护客户端与服务器端在属性及其对应关键字的映射关系。<br />２． 当需要使用基本类型的数据时候，因为Hash Map的限制必须将基本类型先转换成对象。<br />３． 使用得到的数据时，需要进行类型强制转换。</p><p>Data Transfer RowSet<br />当需要处理直接的JDBC调用得到的结果集时，显然用DTO/Hash Map已经不合适，因为需要对大量数据进行类型转换等额外操作是很费资源和不必要的，而且最终用户常需要以表格式样显示数据。 <br />所以对二维表式数据，更好的处理方式是利用Data Transfer RowSet。Data Transfer RowSet通过将ResultSet直接转换为RowSet传递给客户端。<br />在Session EJB中使用RowSet的一段示例代码如下图１３：<br /><img height="170" src="http://dev2dev.bea.com.cn/images/article/other031028/image019.gif" width="467" /><br />图１３：使用RowSet<br />使用RowSet的好处很多：<br />１． 接口通用于各样的数据库查询操作。<br />２． 当需要表格式数据显示时，因为直接从ResultSet得到，所以不需要额外的数据类型转换。<br />缺点是：<br />１． 数据库结构暴露给客户端。<br />２． 不符合面向对象设计思想。<br />３． 依赖于SQL。<br />Data Transfer RowSet通常用于只读式数据的显示操作，经常和JDBC for Reading Pattern连用。</p><p>四．事务和数据持久机制</p><p>　　<b>JDBC for Reading Pattern</b><br /><br />基于EJB的J2EE应用中，通过EJB对数据库的操作可以有两种方式：实体EJB或者Session EJB中直接利用JDBC访问。<br />客户很多时候取出数据库中数据并以表格方式显示。这种情形如果使用实体EJB会导致如下问题：<br />１． 引用服务器端频繁的数据库查询和加载操作。因为加载N个实体EJB总需要进行一次find()操作　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　N次数据加载。<br />２． 如果使用Remote接口，引起频繁的额外网络操作。<br />３． 对关联关系比较复杂的数据库表结构，很难直接通过Entity EJB表现。<br />因此建议在只需对数据库表数据进行只读访问时候，应该采用JDBC for Reading Pattern，即通过JDBC直接访问数据库。除了避免上述使用实体EJB的缺点还带来一下好处：<br />１． 充分利用数据库能力，比如数