在此博客文章中,我們將研究一些基本示例以了解如何使用EJB API。
基本EJB
EJB本質上是帶有一些額外EJB元數據的POJO。 可以通過使用EJB批注或通過標準部署描述符來提供將其部署為EJB組件所需的元數據。 以下類實現了一個非常基本的無狀態會話EJB:
package es.reacts;import javax.ejb.Stateless;@Stateless(name = "UniqueLocalSessionEJB")
public class UniqueLocalSessionEJBBean implements UniqueLocalBusinessInterface {public UniqueLocalSessionEJBBean() {}public String sayLocalHello() {return this.getClass().getName() + "::" + "Local hello.";}
}
正如您可能從我們以前的博客文章中所回顧的那樣, @Stateless批注用于定義無狀態會話bean。 可選的name元素用于定義會話bean 名稱 。 該元素類似于標準部署描述符的<ejb-name />元素。 此元素默認為bean類(UniqueLocalSessionEJBBean在上面的例子中),和上述使用它的示例的非限定名稱重新命名bean來UniqueLocalSessionEJB。
由于我們使用@Stateless批注,因此不再需要在部署描述符中聲明EJB。
在此示例中,我們假設EJB打包在EJB模塊中,該模塊取決于包含其業務接口定義的模塊(如以下部分所述)。
業務接口
每個EJB都實現一個或多個業務接口。 業務接口可以是本地或遠程的 。 兩種類型的業務接口之間最重要的區別可以歸納如下:
- 本地業務接口對其方法使用按引用傳遞語義,并且方法調用不能跨越JVM邊界。 本地業務接口僅對被調用方的相同應用程序和JVM實例中的調用方可用。
- 遠程業務接口對其方法使用按值傳遞語義,并且方法調用可以跨越JVM邊界。 遠程業務接口可用于被呼叫者應用程序之外的呼叫者。
在前面的示例中,業務接口UniqueLocalBusinessInterface聲明如下:
package es.reacts;import javax.ejb.Local;@Local
public interface UniqueLocalBusinessInterface {String sayLocalHello();
}
在EJB v。3.0世界中,業務接口只是用@Local或@Remote批注進行批注的普通Java接口。
包裝業務接口
在此示例中,我們假設EJB業務接口打包在EJB模塊依賴的JAR文件中。 由于EJB客戶端僅依賴EJB業務接口,因此,將業務接口打包在一個單獨的庫中是一個好習慣,以簡化接口分配并使它們與實現分離。
將EJB注入Java Servlet
既然我們已經定義了EJB,就可以在Java EE Web模塊中的servlet中使用它了。 假設在我們的應用程序中只有一個EJB實現了UniqueLocalBusinessInterface ,我們可以使用空的@EJB注釋將其注入:
package es.reacts;import java.io.IOException;
import java.io.PrintWriter;import javax.ejb.EJB;import javax.servlet.*;
import javax.servlet.http.*;public class ServletTest1 extends HttpServlet {@EJBUniqueLocalBusinessInterface lc;public void doGet(HttpServletRequest request,HttpServletResponse response)throws ServletException, IOException {[...]lc.sayLocalHello();[...]}
首先要注意的是,由于僅bean接口就足以識別目標EJB,因此應用服務器將EJB注入了EJB。 在這種情況下,@EJB批注的beanInterface元件取它的默認值,因為在我們解釋之前的帖子 UniqueLocalBusinessInterface:,那是注入字段的類型。 由于應用程序中只有一個EJB可以實現此業務接口,因此servlet的lc字段將注入對此類實例的引用。
值得指出的第二件事是,由于EJB是無狀態的 ,因此我們正在將EJB安全地注入到servlet字段中。 由于servlet的默認情況下無狀態的 ,你不應該注射狀態的資源轉換成Servlet時域特性,否則你可能會碰到并發相關的問題。 如果需要在Servlet中使用有狀態EJB,則應通過程序化JNDI查找來檢索引用,因為這將確保每次查找操作都返回一個新實例。
讓我們部署并運行我們的應用程序,我們將看到servlet注入了它的目標EJB,并且正確執行了對其業務接口的sayLocalHello()方法的方法調用。
如果我們想注入對遠程接口的引用,則客戶端代碼不會受到影響。 如果嘗試將UniqueLocalBusinessInterface從@Local更改為@Remote ,那么您會看到該servlet沒有任何變化,并且可以繼續正常工作。
如果一個以上的EJB實現相同的接口會發生什么?
假設我們在此應用程序的EJB模塊中添加了另一個EJB,它實現了與上一個相同的接口UniqueLocalBusinessInterface 。 在這種情況下,由于bean接口不再足以確定要注入的目標bean,因此將返回一個錯誤。 例如,在WebLogic Application Server中部署這樣的應用程序會導致引發以下錯誤:
[08:46:25 PM] Caused by: weblogic.deployment.EnvironmentException: [J2EE:160199]Error resolving ejb-ref 'es.reacts.ServletTest1/lc1' from module 'WebTest0' of application 'EJBTestApp'. The ejb-ref does not have an ejb-link and the JNDI name of the target bean has not been specified. Attempts to automatically link the ejb-ref to its target bean failed because multiple EJBs in the application were found to implement the 'es.reacts.UniqueLocalBusinessInterface' interface. Please specify a qualified ejb-link for this ejb-ref to indicate which EJB is the target of this ejb-ref.
注入對特定EJB實例的引用
為了解決上一節中出現的問題,我們需要為應用程序服務器提供所需的信息,以標識目標EJB。 如前一篇文章所述 ,我們可以使用以下兩種方法:
- 我們可以使用@EJB批注的name元素(或部署描述符的相應<ejb-ref-name />元素)在應用程序的私有名稱空間中聲明EJB引用,然后使用EJB鏈接到目標bean。部署描述符。
- 或者,我們使用@EJB批注的beanName元素(或部署描述符的相應<ejb-link />元素)直接在我們的代碼中進行操作。
將EJB映射到私有命名空間
使用第一種方法,我們將在servlet中獲得以下代碼:
@EJB(name = "ejb/bean-name")
UniqueLocalBusinessInterface lc;
以及充當EJB客戶端的Java EE Web模塊的部署描述符(web.xml)中的以下元素:
<ejb-local-ref><ejb-ref-name>ejb/bean-name</ejb-ref-name><ejb-ref-type>Session</ejb-ref-type><local>es.reacts.UniqueLocalBusinessInterface</local><ejb-link>UniqueLocalSessionEJB</ejb-link>
</ejb-local-ref>
<ejb-link />元素包含我們在示例開頭定義的帶注釋的Bean名稱:
@Stateless(name = "UniqueLocalSessionEJB")
在EJB實現類中。
請注意,在此示例中,我們顯式使用了@EJB name元素,但是我們可以使用其默認值來建立鏈接。 name元素的默認值為:
[合格的類名稱] / [屬性或字段名稱]在這種情況下,將是:
es.reacts.ServletTest1 / lc
使用默認的自動生成的名稱以及使用<ejb-link />進行EJB鏈接的缺點是,每次重構代碼時,都必須檢查部署描述符。 盡管開發人員有時會另外考慮,但Java EE規范定義了一些其他角色,例如,攻擊者和部署者。 在大型公司環境中,此類概要文件會覆蓋開發人員的注釋以“插入”應用程序使用的組件并不少見。 注釋覆蓋是標準部署描述符仍然存在的原因之一。 當引用是在應用程序內部或外部的遠程組件時,尤其如此。 為此,我建議你不要依賴于自動生成的名稱,并使用自定義的有據可查的名稱代替。
將EJB鏈接到私有命名空間中的引用
第二種方法提供了使用@EJB批注的beanName元素將引用鏈接到其目標bean的直接方法。 Servlet代碼將使用以下EJB參考:
@EJB(beanName = "UniqueLocalSessionEJB")
UniqueLocalBusinessInterface lc;
并且我們不需要部署描述符中的其他信息。
盡管此方法允許開發人員在不依賴部署描述符的情況下將引用鏈接到EJB,但是上一節末尾給出的建議仍然有效。 請記住,可以在部署時覆蓋注釋! 如果事先知道這樣的引用可以覆蓋,則不要將EJB鏈接到引用。 在這種情況下,最好為引用指定一個名稱,如上一節所述。
參考: The Gray Blog上的JCG合作伙伴 Gray提供了基本的EJB參考,注入和查找 。
- EJB 3.0注入和查找簡介
- EJB程序化查找
- 使用Oracle WebLogic對應用程序外部的EJB的引用
- EJB 3.1全局JNDI訪問
- GWT EJB3 Maven JBoss 5.1集成教程
- Java泛型快速教程
- JVM如何處理鎖
翻譯自: https://www.javacodegeeks.com/2011/08/basic-ejb-references-injection-and.html