原文地址:
http://testwww.netbeans.org/kb/55/ejb30_zh_CN.html
EJB 3.0 Enterprise Beans
本文檔介紹了有關(guān)使用 EJB 3.0 技術(shù)(作為 Java EE 5 平臺(tái)的一部分)開發(fā)企業(yè)應(yīng)用程序的基礎(chǔ)知識(shí),同時(shí)說明了 EJB 3.0 技術(shù)是如何簡(jiǎn)化企業(yè)應(yīng)用程序的開發(fā)過程的。本文檔使用的是 NetBeans IDE 5.5 發(fā)行版本。
預(yù)計(jì)持續(xù)時(shí)間:30 分鐘
先決條件
本文檔假定您已具備了以下技術(shù)的一些基本知識(shí)或編程經(jīng)驗(yàn):
本教程所需的軟件
在學(xué)習(xí)本教程之前,您需要在計(jì)算機(jī)中安裝以下軟件:
- NetBeans IDE 5.5(下載)
- Java Standard Development Kit (JDK) 版本 5.0 或版本 6.0(下載)
- Sun Java System Application Server Platform Edition 9(下載)
在學(xué)習(xí)本教程之前,您需要在 IDE 中注冊(cè) Sun Java System Application Server 的本地實(shí)例。
教程練習(xí)
建立企業(yè)應(yīng)用程序項(xiàng)目
本練習(xí)的目的是:創(chuàng)建包含一個(gè) EJB 模塊和一個(gè) Web 模塊的 NewsApp 企業(yè)應(yīng)用程序項(xiàng)目。NewsApp 應(yīng)用程序使用消息驅(qū)動(dòng) Bean 接收和處理 Servlet 發(fā)送到隊(duì)列中的消息。該應(yīng)用程序使用 Servlet 將消息發(fā)送到消息驅(qū)動(dòng) Bean 并顯示消息。
創(chuàng)建企業(yè)應(yīng)用程序
- 從主菜單中選擇“文件”>“新建項(xiàng)目”(Ctrl-Shift-N)。
- 從“企業(yè)”類別中選擇“企業(yè)應(yīng)用程序”,然后單擊“下一步”。
- 將項(xiàng)目命名為 NewsApp,并將服務(wù)器設(shè)置為 Sun Java System Application Server。
- 將 J2EE 版本設(shè)置為 "Java EE 5",然后選中“創(chuàng)建 EJB 模塊”和“創(chuàng)建 Web 應(yīng)用程序模塊”(如果未選中)。
- 單擊“完成”。
小結(jié)
在本練習(xí)中,我們創(chuàng)建了包含一個(gè) EJB 模塊和一個(gè) Web 模塊的 Java EE 5 企業(yè)應(yīng)用程序。
對(duì) EJB 模塊進(jìn)行編碼
在本練習(xí)中,我們將在 EJB 模塊中創(chuàng)建對(duì)象。我們將創(chuàng)建實(shí)體類、消息驅(qū)動(dòng) Bean 和會(huì)話 Facade。我們還將創(chuàng)建一個(gè)持久性單元,以便為容器提供用于管理實(shí)體的信息,以及消息驅(qū)動(dòng) Bean 將使用的 Java 消息服務(wù) (Java Message Service, JMS) 資源。
創(chuàng)建持久性單元
首先,我們將創(chuàng)建一個(gè)持久性單元,它用于定義在應(yīng)用程序中使用的數(shù)據(jù)源和實(shí)體管理器。
- 右鍵單擊 EJB 模塊,然后選擇“新建”>“文件/文件夾”。
- 從“持久性”類別中,選擇“持久性單元”,然后單擊“下一步”。
- 保留缺省的持久性單元名稱。
- 對(duì)于持久性提供程序,請(qǐng)選擇“TopLink(缺省)”。
- 對(duì)于數(shù)據(jù)源,請(qǐng)選擇缺省的數(shù)據(jù)源 jdbc/sample。
- 檢查是否為持久性單元選中了“使用 Java 事務(wù) API”,以及“表生成策略”是否設(shè)置為“創(chuàng)建”,以便在部署應(yīng)用程序時(shí)創(chuàng)建基于實(shí)體類的表。
- 單擊“完成”。
單擊“完成”后,IDE 將創(chuàng)建 persistence.xml,并在源代碼編輯器中將其打開。關(guān)閉 persistence.xml。
創(chuàng)建 NewsEntity 實(shí)體類
在本練習(xí)中,我們將創(chuàng)建 NewsEntity 實(shí)體類。實(shí)體類是一個(gè)簡(jiǎn)單的 Java 類。在創(chuàng)建實(shí)體類時(shí),IDE 會(huì)添加 @Entity 標(biāo)注以將該類定義為實(shí)體類。當(dāng)創(chuàng)建了類后,我們將在該類中創(chuàng)建字段以表示表中所需的數(shù)據(jù)。
每個(gè)實(shí)體類都必須具有一個(gè)主鍵。在創(chuàng)建實(shí)體類時(shí),IDE 會(huì)添加 @Id 標(biāo)注以聲明要用作主鍵的字段。此外,IDE 還會(huì)添加 @Generated 標(biāo)注以指定主 Id 的鍵生成策略。
要?jiǎng)?chuàng)建 NewsEntity 類,請(qǐng)執(zhí)行以下操作:
- 在“項(xiàng)目”窗口中右鍵單擊 EJB 模塊,然后選擇“新建”>“文件/文件夾”打開“新建文件”向?qū)А?
- 從“持久性”類別中,選擇“實(shí)體類”,然后單擊“下一步”。
- 鍵入 NewsEntity 作為類名,鍵入 ejb 作為包名,并將“主鍵類型”保留為 Long。單擊“完成”。
單擊“完成”后,將在源代碼編輯器中打開實(shí)體類 NewsEntity.java。在源代碼編輯器中,請(qǐng)執(zhí)行以下操作:
- 將以下字段聲明添加到類中:
String title;
String body;
- 在源代碼編輯器中單擊鼠標(biāo)右鍵,然后選擇“重構(gòu)”>“封裝字段”以便為每個(gè)字段生成 getter 和 setter。在“封裝字段”對(duì)話框中,確保選中了字段 id、title 和 body 的 getter 和 setter 復(fù)選框。
- 在“封裝字段”對(duì)話框中單擊“下一步”,然后在“輸出”窗口的“重構(gòu)”標(biāo)簽中單擊“執(zhí)行重構(gòu)”。IDE 將為各字段添加 getter 和 setter 方法,并將字段的可視性更改為 private。
- 保存對(duì)文件所做的更改。
在接下來的步驟中,我們將創(chuàng)建 NewMessage 消息驅(qū)動(dòng) Bean。
創(chuàng)建 NewMessage 消息驅(qū)動(dòng) Bean
現(xiàn)在我們將在 EJB 模塊中創(chuàng)建 NewMessage 消息驅(qū)動(dòng) Bean。我們將使用“新建消息驅(qū)動(dòng) Bean”向?qū)韯?chuàng)建 Bean 和所需的 JMS 資源。
要?jiǎng)?chuàng)建 NewMessage 消息驅(qū)動(dòng) Bean,請(qǐng)執(zhí)行以下操作:
- 在“項(xiàng)目”窗口中右鍵單擊 EJB 模塊,然后選擇“新建”>“文件/文件夾”以打開“新建文件”向?qū)А?
- 從“企業(yè)”類別中,選擇“消息驅(qū)動(dòng) Bean”,然后單擊“下一步”。
- 鍵入 NewMessage 作為類名。
- 從“包”下拉列表中選擇 "ejb"。
- 選擇“隊(duì)列”作為目標(biāo)類型,然后單擊“完成”。
單擊“完成”后,將在源代碼編輯器中打開新建的消息驅(qū)動(dòng) Bean 類 NewMessage.java。您可以看到該類具有以下標(biāo)注:
@MessageDriven(mappedName = "jms/NewMessage")
此標(biāo)注向容器說明:該組件是一個(gè)消息驅(qū)動(dòng) Bean 并且該 Bean 使用 JMS 資源。當(dāng) IDE 生成類時(shí),將從類 (NewMessage.java) 名稱派生資源的映射名 (jms/NewMessage)。JMS 資源被映射到目標(biāo)的 JNDI 名稱,Bean 從該目標(biāo)中接收消息。“新建消息驅(qū)動(dòng) Bean”向?qū)б褳槲覀儎?chuàng)建了 JMS 資源。通過 EJB 3.0 API,我們可以從 Bean 類中查找 JNDI 名稱空間中的對(duì)象,這樣就不需要配置部署描述符來指定 JMS 資源了。
EJB 3.0 規(guī)范允許您使用標(biāo)注將資源直接引入類中。現(xiàn)在,我們準(zhǔn)備使用標(biāo)注將 MessageDrivenContext 資源引入類中,然后注入 PersistenceContext 資源,EntityManager API 將使用該資源來管理持久性實(shí)體實(shí)例。我們要在源代碼編輯器中將標(biāo)注添加到類中。
- 通過在類中添加以下帶標(biāo)注的字段(以粗體顯示),將 MessageDrivenContext 資源注入到類中:
public class NewMessage implements MessageListener {
@Resource
private MessageDrivenContext mdc;
- 在代碼中單擊鼠標(biāo)右鍵,然后從彈出式菜單中選擇“持久性”>“使用實(shí)體管理器”,將實(shí)體管理器引入類中。
這會(huì)在源代碼中添加以下標(biāo)注:
@PersistenceContext
private EntityManager em;
并在代碼中生成以下方法:
public void persist(Object object) {
// TODO:
// em.persist(object);
}
- 按如下所示修改 persist 方法:
public void save(Object object) {
em.persist(object);
}
- 通過將以下代碼添加到主體中來修改 onMessage 方法:
ObjectMessage msg = null;
try {
if (message instanceof ObjectMessage) {
msg = (ObjectMessage) message;
NewsEntity e = (NewsEntity) msg.getObject();
save(e);
}
} catch (JMSException e) {
e.printStackTrace();
mdc.setRollbackOnly();
} catch (Throwable te) {
te.printStackTrace();
}
- 按 Alt-Shift-F 組合鍵生成所有必要的 import 語句。在生成 import 語句時(shí),我們需要確保導(dǎo)入 jms 和 javax.annotation.Resource; 庫。
- 保存該文件。
創(chuàng)建會(huì)話 Bean
接下來,我們將為 NewsEntity 實(shí)體類創(chuàng)建一個(gè)會(huì)話 Facade。要?jiǎng)?chuàng)建會(huì)話 Facade,請(qǐng)執(zhí)行以下操作:
- 右鍵單擊 EJB 模塊,然后選擇“新建”>“文件/文件夾”。
- 從“持久性”類別中,選擇“實(shí)體類的會(huì)話 Bean”,然后單擊“下一步”。
- 從可用的實(shí)體類列表中,選擇 "NewsEntity",單擊“添加”,然后單擊“下一步”。
- 檢查是否將包設(shè)置為 ejb 以及是否選中了創(chuàng)建本地接口。
- 單擊“完成”。
單擊“完成”后,將創(chuàng)建會(huì)話 Facade 類 NewsEntityFacade.java,并在源代碼編輯器中將其打開。IDE 還將創(chuàng)建本地接口 NewsEntityFacadeLocal.java。
EJB 3.0 技術(shù)通過減少所需的代碼量來簡(jiǎn)化會(huì)話 Bean 的創(chuàng)建。您可以看到,標(biāo)注 @Stateless 用于將類聲明為無態(tài)會(huì)話 Bean 組件,并且該類不再需要實(shí)現(xiàn) javax.ejb.SessionBean 的語句。此外,代碼也更為簡(jiǎn)潔了,因?yàn)槔?EJB 3.0 技術(shù),業(yè)務(wù)方法不再需要使用代碼來聲明其拋出了所檢查到的異常。
您會(huì)看到,在創(chuàng)建會(huì)話 Facade 時(shí),PersistenceContext 資源已直接注入到會(huì)話 Bean 組件中。
小結(jié)
在本練習(xí)中,我們已對(duì) EJB 模塊中的實(shí)體類和消息驅(qū)動(dòng) Bean 進(jìn)行了編碼,然后為實(shí)體類創(chuàng)建了會(huì)話 Facade。此外,我們還創(chuàng)建了應(yīng)用程序使用的 JMS 資源。
對(duì) Web 模塊進(jìn)行編碼
現(xiàn)在,我們將在 Web 模塊中創(chuàng)建 Servlet ListNews 和 PostMessage。這些 Servlet 將用于讀取和添加消息。
創(chuàng)建 ListNews Servlet
在本練習(xí)中,我們將創(chuàng)建一個(gè)用于顯示數(shù)據(jù)的簡(jiǎn)單 Servlet。我們將使用標(biāo)注從 Servlet 中調(diào)用實(shí)體 Bean。
- 右鍵單擊 Web 模塊項(xiàng)目,然后選擇“新建”> "Servlet"。
- 鍵入 ListNews 作為類名。
- 輸入 web 作為包名,然后單擊“完成”。
單擊“完成”后,將在源代碼編輯器中打開類 ListNews.java。在源代碼編輯器中,請(qǐng)執(zhí)行以下操作:
- 在源代碼中,單擊鼠標(biāo)右鍵,然后選擇“企業(yè)資源”>“調(diào)用 Enterprise Bean”。
- 在“調(diào)用 Enterprise Bean”對(duì)話框中,選擇 "NewsEntityFacade",然后單擊“確定”。單擊“確定”后,將使用 @EJB 標(biāo)注在 Servlet 中注入實(shí)體 Bean 資源。
- 在 processRequest 方法中,對(duì)其進(jìn)行如下修改:取消代碼注釋,然后將下面以粗體顯示的行添加到方法主體中。
out.println("<h1>Servlet ListNews at " + request.getContextPath () + "</h1>");
List news = newsEntityFacade.findAll();
for (Iterator it = news.iterator(); it.hasNext();) {
NewsEntity elem = (NewsEntity) it.next();
out.println(" <b>"+elem.getTitle()+" </b><br />");
out.println(elem.getBody()+"<br /> ");
}
out.println("<a href='PostMessage'>Add new message</a>");
out.println("</body>");
- 按 Alt-Shift-F 組合鍵為類生成所有必要的 import 語句。在生成 import 語句時(shí),我們希望從 util 包中導(dǎo)入類。
- 保存對(duì)文件所做的更改。
創(chuàng)建 PostMessage Servlet
在本練習(xí)中,我們將創(chuàng)建用于傳遞消息的 PostMessage Servlet。我們將使用標(biāo)注將所創(chuàng)建的 JMS 資源直接注入 Servlet 中,并且指定變量名稱及其映射到的名稱。然后,添加用于發(fā)送 JMS 消息的代碼,以及用于在 HTML 表單中添加消息的代碼。
- 右鍵單擊 Web 模塊項(xiàng)目,然后選擇“新建”> "Servlet"。
- 鍵入 PostMessage 作為類名。
- 輸入 web 作為包名,然后單擊“完成”。
單擊“完成”后,將在源代碼編輯器中打開類 PostMessage.java。在源代碼編輯器中,請(qǐng)執(zhí)行以下操作:
- 通過添加下面以粗體顯示的字段聲明,使用標(biāo)注來注入 ConnectionFactory 和 Queue 資源:
public class PostMessage extends HttpServlet {
@Resource(mappedName="jms/NewMessageFactory")
private ConnectionFactory connectionFactory;
@Resource(mappedName="jms/NewMessage")
private Queue queue;
- 現(xiàn)在,通過將下面以粗體顯示的代碼添加到 processRequest 方法中,添加用于發(fā)送 JMS 消息的代碼:
response.setContentType("text/html;charset=UTF-8");
// Add the following code to send the JMS message
String title=request.getParameter("title");
String body=request.getParameter("body");
if ((title!=null) && (body!=null)) {
try {
Connection connection = connectionFactory.createConnection();
Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
MessageProducer messageProducer = session.createProducer(queue);
ObjectMessage message = session.createObjectMessage();
// here we create NewsEntity, that will be sent in JMS message
NewsEntity e = new NewsEntity();
e.setTitle(title);
e.setBody(body);
message.setObject(e);
messageProducer.send(message);
messageProducer.close();
connection.close();
response.sendRedirect("ListNews");
} catch (JMSException ex) {
ex.printStackTrace();
}
}
PrintWriter out = response.getWriter();
- 現(xiàn)在,將對(duì)輸出 HTML 的代碼取消注釋,并添加用于添加消息的 Web 表單。將下面以粗體顯示的代碼行添加到 processRequest 方法中:
out.println("Servlet PostMessage at " + request.getContextPath() + "</h1>");
// Add the following code to add the form to the web page
out.println("<form>");
out.println("Title: <input type='text' name='title'><br/>");
out.println("Message: <textarea name='body'></textarea><br/>");
out.println("<input type='submit'><br/>");
out.println("</form>");
out.println("</body>");
- 按 Alt-Shift-F 組合鍵為類生成所有必要的 import 語句。在選擇 Connection、ConnectionFactory、Session 和 Queue 的 import 語句時(shí),將導(dǎo)入 java.jms 庫。
- 保存對(duì)文件所做的更改。
運(yùn)行項(xiàng)目
現(xiàn)在可以運(yùn)行項(xiàng)目了。在運(yùn)行項(xiàng)目時(shí),我們希望瀏覽器打開包含 ListNews Servlet 的頁面。可以通過在企業(yè)應(yīng)用程序的“屬性”對(duì)話框中指定該頁的 URL 來實(shí)現(xiàn)這一目的。該 URL 是應(yīng)用程序的上下文路徑的相對(duì) URL。輸入相對(duì) URL 后,可以從“項(xiàng)目”窗口中生成、部署并運(yùn)行應(yīng)用程序。
要設(shè)置相對(duì) URL 并運(yùn)行應(yīng)用程序,請(qǐng)執(zhí)行以下操作:
- 在“項(xiàng)目”窗口中,右鍵單擊 "NewsApp" 企業(yè)應(yīng)用程序節(jié)點(diǎn),然后從彈出式菜單中選擇“屬性”。
- 在“類別”窗格中選擇“運(yùn)行”。
- 在“相對(duì) URL”文本字段中,鍵入 /ListNews。
- 單擊“確定”。
- 在“項(xiàng)目”窗口中,右鍵單擊 "NewsApp" 企業(yè)應(yīng)用程序節(jié)點(diǎn),然后選擇“運(yùn)行項(xiàng)目”。
運(yùn)行項(xiàng)目時(shí),將在瀏覽器中打開 ListNews Servlet,該 Servlet 用于顯示數(shù)據(jù)庫中的消息列表。如果您是第一次運(yùn)行項(xiàng)目,則數(shù)據(jù)庫為空,但是您可以單擊“添加消息”來添加消息。

當(dāng)您使用 PostMessage Servlet 添加消息時(shí),消息會(huì)發(fā)送到消息驅(qū)動(dòng) Bean 以寫入到持久性存儲(chǔ)中,并會(huì)調(diào)用 ListNews Servlet 來顯示數(shù)據(jù)庫中的消息。由 ListNews 檢索的數(shù)據(jù)庫中的消息列表通常不包含新消息,這是因?yàn)橄⒎?wù)是異步的。
疑難解答
下面是您創(chuàng)建項(xiàng)目時(shí)可能會(huì)遇到的一些問題。
JMS 資源問題
使用向?qū)韯?chuàng)建 JMS 資源時(shí),您可能會(huì)在輸出窗口中看到以下服務(wù)器錯(cuò)誤消息:
[com.sun.enterprise.connectors.ConnectorRuntimeException:
JMS resource not created : jms/Queue]
此消息可能表明沒有創(chuàng)建 JMS 資源,或者沒有在應(yīng)用服務(wù)器中注冊(cè)該資源。您可以使用 Sun Java System Application Server 管理控制臺(tái)來檢查、創(chuàng)建以及編輯 JMS 資源。
要打開管理控制臺(tái),請(qǐng)執(zhí)行以下操作:
- 在 IDE 的“運(yùn)行環(huán)境”中,展開“服務(wù)器”節(jié)點(diǎn)以確認(rèn) Sun Java System Application Server 正在運(yùn)行。"Sun Java System Application Server" 節(jié)點(diǎn)旁邊的小綠色箭頭表示服務(wù)器正在運(yùn)行。
- 右鍵單擊 "Sun Java System Application Server" 節(jié)點(diǎn),然后選擇“查看管理控制臺(tái)”以在瀏覽器中打開登錄窗口。
- 登錄到 Sun Java System Application Server。缺省的用戶名為 admin,口令為 adminadmin。
- 在瀏覽器的管理控制臺(tái)中,依次展開左框架中的“資源”節(jié)點(diǎn)和“JMS 資源”節(jié)點(diǎn)。
- 在左框架中單擊“連接工廠”和“目標(biāo)資源”鏈接以檢查是否在服務(wù)器中注冊(cè)了這些資源,并在必要時(shí)修改這些資源。如果這些資源不存在,您可以在管理控制臺(tái)中創(chuàng)建這些資源。
您需要確保將 PostMessage Servlet 中的 JMS 連接工廠資源映射到在 Sun Java System Application Server 中注冊(cè)的 JMS 連接工廠資源的對(duì)應(yīng) JNDI 名稱上。
應(yīng)在 Sun Java System Application Server 中注冊(cè)以下資源:
- 具有 JNDI 名稱 jms/NewMessage 和類型 javax.jms.Queue 的目標(biāo)資源
- 具有 JNDI 名稱 jms/NewMessageFactory 和類型 javax.jms.QueueConnectionFactory 的連接工廠資源
后續(xù)步驟
有關(guān)使用 NetBeans IDE 5.5 開發(fā) Java EE 應(yīng)用程序的更多信息,請(qǐng)參見以下資源:
您可以在 Java EE 5 教程中找到有關(guān)使用 EJB 3.0 Enterprise Beans 的詳細(xì)信息。
要發(fā)送意見和建議、獲得支持以及隨時(shí)了解 NetBeans IDE Java EE 開發(fā)功能的最新開發(fā)情況,請(qǐng)加入 nbj2ee 郵件列表。