程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> JAVA編程 >> 關於JAVA >> 使用Apache OpenJPA開發EJB 3.0應用,第8部分

使用Apache OpenJPA開發EJB 3.0應用,第8部分

編輯:關於JAVA

在Java EE環境下開發、部署OpenJPA 應用

在 本系列 文章的第 1 部分:OpenJPA 與 EJB 3.0中介紹 OpenJPA 時,曾經 提到“OpenJPA 可以作為獨立的持久層框架發揮作用,也可以輕松的與其它 Java EE 應用框架或者符合 EJB3.0 標准的容器集成”,在本系列的前面幾篇文章中都 只是講解了如何將 OpenJPA 作為獨立的持久層框架發揮作用,在本文中,我們將 會了解如何在 JBoss 應用服務器中使用 OpenJPA 開發實體 Bean、並且用 SessionBean 封裝實體 Bean 操作、在客戶端通過 Local 接口訪問的開發、部署 過程。

融入 Java EE

OpenJPA 是標准的 JPA 框架,因此它能夠被任何的 EJB3.0 容器所集成,作 為 JPA 的一種實現。比如我們可以將 JBoss 應用服務器中的 JPA 實現框架由系 統默認的 Hibernate 切換成 OpenJPA,同樣,我們可以將 Websphere、WebLogic 等的 JPA 實現框架由系統默認的框架切換成 OpenJPA。

要將 OpenJPA 容器 Java EE 容器,和 OpenJPA 作為獨立框架運行時相比需 要完成幾部分的轉換:

部署形式變為 EJB Jar 或者 EAR;OpenJPA 應用在 Java EE 環境下部署形式 是 EJB Jar 或者 EAR,而不再是獨立的 Java 應用或者 Servlet 容器中的 Web 應用。

使用系統級 JDBC 數據源,將事務處理委托給 JTA 事務;

在前面幾篇文章中,我們開發 OpenJPA 應用時都是在 OpenJPA 配置文件 persistence.xml 文件中直接提供訪問數據庫的 JDBC 配置,操作實體的時候, 我們也需要處理使用 entityManager.getTransaction().begin()、 entityManager.getTransaction().commit() 這樣的語句顯示的處理事務。

在 Java EE 環境下,JDBC 通常都是由容器管理,JDBC 訪問時的事務也通常 使用容器管理,這樣可以獲得更大的靈活性,也能夠最大化的利用容器的特性讓 企業應用更加強壯。要將 OpenJPA 容器 Java EE 容器,我們首要的任務就是將 OpenJPA 中的應用級 JDBC 數據源切換到 Java EE 容器的 JDBC 數據源上,另外 還需要將事務處理委托給 Java EE 容器提供的 JTA 事務,而不在使用 entityManager.getTransaction().begin()、 entityManager.getTransaction ().commit() 這樣的語句顯示的處理事務。

注入 Entity Manager Factory 或者 Entity Manager

在前面幾篇文章中,我們開發 OpenJPA 應用中操縱實體之前,都需要通過 Persistence 的 createEntityManagerFactory 方法創建 EntityManagerFactory 對象,然後創建 EntityManager 對象後操作實體。

但是根據 EJB3.0 規范中 JPA 部分的要求,在 Java EE 容器中的 JPA 應用 應該通過依賴注入獲取 Entity Manager Factory 或者是 EntityManager,也可 以選擇將 Entity Manager Factory 或者是 EntityManager 綁定到 JNDI,在代 碼中通過 JNDI 獲取,而不是采用 Persistence 的 createEntityManagerFactory 方法來創建。

要將 OpenJPA 應用切換到 Java EE 環境下,我們需要向 OpenJPA 中注入 Entity Manager Factory 或者是 EntityManager 對象,或者是將 Entity Manager Factory 或者是 EntityManager 綁定到 JNDI,這取決於 Java EE 容器 的支持方式和開發者的愛好。除此之外,OpenJPA 應用中對應部分的代碼也需要 修改,以適應 Java EE 容器端發生的變化。

使用會話 Bean 封裝 EntityBean 的訪問

在前面幾篇文章中,OpenJPA 應用中生成的實體在客戶端直接使用 Java 代碼 調用,然而在 Java EE 容器中的實體肯定是無法被客戶端代碼直接訪問的,而且 ,根據 EJB3.0 規范的描述,Java EE 容器中的實體無法和 EJB2.1 中的實體一 樣綁定到 JNDI,因此我們的選擇只能是使用會話 Bean 來封裝 EntityBean 的訪 問。

OpenJPA 應用開發

在上一章中,我們了解了如何將 OpenJPA 應用移植到 Java EE 容器時需要完 成的工作內容,本章中,我們將通過一個簡單的例子來學習如何在 Java EE 容器 中開發、部署一個 OpenJPA 應用。

Java EE 環境下,應用 OpenJPA 框架開發 EJB3.0 應用的主要步驟如下:

創建 EJB 應用目錄;

在 Java EE 容器中配置 JDBC 數據源;

編寫 ( 修改 ) 配置文件;

Java EE 容器通過 EJB jar 中的 META-INF\persistence.xml 文件來創建 EntityManagerFactory,然後在需要的時候將 EntityManagerFactory 對象或者 它創建的 EntityManager 對象注入 OpenJPA 容器中。

根據業務需要設計 Java 對象、編寫對應的 Java 實體類;

用 JDK 編譯 Java 實體類;

用 OpenJPA 提供的工具—PCEnhancer--enhance 編譯好的 Java 實體類;

被 enhance 過的類可以提供更好的運行性能、靈活的”懶加載”等方面的優 勢,更多詳細的內容請參考 OpenJPA 的幫助文檔。

使用 OpenJPA 提供的工具 MappingTool 從 Java 對象生成數據庫定義文件 (DDL);

可以通過 MappingTool 工具直接保持 Entity 和數據庫之間的一致性,也可 以使用 MappingTool 工具生成的數據庫定義文件 (DDL) 創建應用正常運行所需 要的數據庫結構。

將創建的實體類注冊到 OpenJPA 容器中;

應用會話 Bean 封裝對實體類的訪問;

客戶端通過會話 Bean 的訪問,達到訪問實體的目標。

我們將使用本系列文章的 第 2 部分:第一個 OpenJPA 應用 中使用過的簡單 例子,我們將創建名為 Animal 的實體,它有兩個屬性,分別是 id 和 name, Animal 對象將被持久化到本地的 MySQL 數據庫中,其中 id 屬性對應的數據庫 字段由 MySQL 數據庫自動生成。

演示開發環境說明

下面的演示步驟說明均基於 Windows XP 平台,JDK 版本為 1.5.0_11,數據 庫服務器為 MySQL5.0,和演示代碼位於同一台機器上。所有演示用例對應的 MySQL 數據庫為”openjpa”,訪問 MySQL 的用戶名和密碼也均為”openjpa”。

Java EE 容器使用 JBoss 應用服務器 4.2GA 或者版本,默認安裝在 C:\jboss-4.2.0.GA 目錄下。

Java EE 環境下 OpenJPA 應用開發典型步驟

請讀者注意,後面章節中關於操作的說明均基於 Windows XP 操作系統,如果 您使用的開發環境運行在其它類型的操作系統之上,請根據實際情況做出相應的 調整。

建立工程目錄

在 C: 盤根目下創建名為 ejb3demo 的目錄,它包括名為 src 的目錄,然後 在 src 目錄下創建合適的文件和目錄。ejb3demo\src 目錄是標准的 ejb 目錄, 我們所有的類文件和配置文件都將放在這個目錄下。

創建好的 ejb3demo 目錄中應該包括如下目錄和文件:

ejb3demo
   --src
     --META-INF
       persistence.xml

配置 JDBC 數據源

在 JBoss 應用服務器中配置 JDBC 數據源比較容易,我們只需要將 MySQL 數 據庫的 JDBC 驅動 jar 文件拷貝到 %JBOSS_HOME%\server\default\lib 目錄下 ,然後在 %JBOSS_HOME%\server\default\deploy 目錄下創建新的 mysql-ds.xml 文件,mysql-ds.xml 文件的內容如下:

1.     <?xml version="1.0" encoding="UTF-8"?>
2.     <datasources>
3.      <local-tx-datasource>
4.       <!-- JDBC 數據源的 JNDI 名稱à
5.        <jndi-name>mysqlDS</jndi-name>
6.       <!—目標數據庫的 JDBC 連接字符串à
7.       <connection- url>jdbc:mysql://localhost/openjpa</connection-url>
8.       <!—目標數據庫的 JDBC 驅動類名à
9.       <driver-class>com.mysql.jdbc.Driver</driver -class>
10.     <!—目標數據庫的用戶名à
11.     <user-name>openjpa</user-name>
12.     <!—目標數據庫的密碼à
13.     <password>openjpa</password>
14.
15.     <min-pool-size>5</min-pool-size>
16.     <max-pool-size>20</max-pool-size>
17.     <idle-timeout-minutes>0</idle-timeout- minutes>
18.    </local-tx-datasource>
19.
20.   </datasources>

編寫 JPA 配置文件

persistence.xml 是 EJB3.0 規范中定義的實體的配置文件,提供 OpenJPA 容器初始化、運行所需要的信息,比如 OpenJPA 的事務策略、數據庫的連接信息 等,由 Java EE 容器讀取後初始化 OpenJPA 應用中需要注入的 EntityManagerFactory 或者 EntityManager。

特別要注意的是,我們必須在 persistence.xml 中為 persistence-unit 元 素提供 provider 子元素,它的內容是” org.apache.openjpa.persistence.PersistenceProviderImpl”, 這是 OpenJPA 的 Persistence 的實現。如果我們不提供 provider 子元素,JBoss 服務器將默 認使用它內置的 Hibernate 框架作為 JPA 容器。

清單 1 中是我們演示實例中所使用的 persistence.xml 文件的內容。

清單 1. src\META-INF\persistence.xml

1.    <?xml version="1.0" encoding="UTF-8"?>
2.    <persistence  xmlns="http://java.sun.com/xml/ns/persistence"
3.     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4.     version="1.0">
5.     <!—persistence-unit 的 name 屬性提供了創建  EntityManagerFacotry 時的
6.       關鍵字,transaction-type 則指定了使用的事務管理類型 ,可以是JTA
7.       或者 RESOURCE_LOCAL,在 Java EE 環境下默認環境是  JTA,這裡使用默認值
8.     <persistence-unit name="ejb3">
9.       <!—JPA 的提供類,OpenJPA 的設置如下,如果使用其 它的 JPA 實現,這裡
10.        的內容需要修改成相應的提供類
11.      <provider>
12.         org.apache.openjpa.persistence.PersistenceProviderImpl
13.      </provider>
14.    <!—使用 Java EE 容器的 JDBC 數據源,JBoss 下  JDBC 數據源以”java:/”開頭,
15.      mysqlDS 是 JDBC 數據源的 JNDI 名稱
16.      <jta-data-source>java:/mysqlDS</jta-data- source>
17.      <!—OpenJPA 容器中管理的實體類列表
18.      <class> org.vivianj.jpademo.beans.Animal  </class>
19.    </persistence-unit>
20.   </persistence>

接下來,我們需要根據業務需要設計 Java 對象、編寫 Java 實體類、編譯實 體類、enhance 編譯好的實體類、生成數據庫定義文件、將創建的實體類注冊到 OpenJPA 容器,這些步驟和在非 Java EE 環境下開發 OpenJPA 應用是一致的, 請讀者參考本系列文章的 第 2 部分:第一個 OpenJPA 應用 的步驟完成,這裡 不再贅述。

應用 SessinBean 封裝對實體的訪問

根據 EJB3.0 規范中對容器的要求來看,實體不能和 EJB2.X 規范中的實體一 樣可以綁定到 JNDI,因此 EJB 容器外的 Java 代碼無法直接訪問實體,可選的 方法就是使用會話 Bean 封裝實體的操作,Java 客戶端通過 JNDI 訪問會話 Bean,從而達到操作實體的目標。

在 EJB3.0 標准下,開發一個會話 Bean 非常簡單,我們只需要定義業務接口 類,然後為該業務接口提供 @ javax.ejb.Remote、@javax.ejb.Local 這樣的注 釋,表明該會話 Bean 提供 Remote 接口或者 Local 接口,也可以為一個業務接 口同時提供 @ javax.ejb.Remote、@javax.ejb.Local 注釋,表示該接口同時支 持 Remote、Local 接口。另外還需要提供會話 Bean 的實現類,它需要實現 Remote 接口、Local 接口其中一種或者同時實現兩種接口。

演示例子中我們為定義了 Remote 接口 IAnimalDAO、Local 接口 ILocalAnimalDAO,它們都提供可以持久化 Animal 對象的 persistAnimal 方法 。然後創建接口的實現類 AnimalDAO,它實現了 IAnimalDAO 和 ILocalAnimalDAO 兩個接口,也就是說,這個會話 Bean 能夠同時支持 Remote、 Local 訪問。

IAnimalDAO 接口的全部源代碼如下 :

1.    package org.vivianj.jpademo;
2.
3.    import javax.ejb.Remote;
4.
5.    import org.vivianj.jpademo.beans.Animal;
6.
7.    @Remote
8.    public interface IAnimalDAO {
9.     public void persistAnimal(Animal animal);
10.   }

ILocalAnimal 接口類的全部源代碼如下:

1.    package org.vivianj.jpademo;
2.
3.    import javax.ejb.Local;
4.
5.    import org.vivianj.jpademo.beans.Animal;
6.
7.    @Local
8.    public interface ILocalAnimalDAO {
9.     public void persistAnimal(Animal animal);
10.   }

AnimalDAO 實現類中實現了上面定義的兩個接口 IAnimalDAO、 ILocalAnimalDAO,並且提供了基於 OpenJPA、Java EE 容器的實體訪問實現代碼 。實例中我們選擇 @ javax.persistence.PersistenceContext 注釋向會話 Bean 中注入 EntityManager 對象,根據實際需求的不同,還可以選擇使用 @PersistenceUnit 注釋向會話 Bean 中注入 EntityManagerFactory 對象。

AnimalDAO 中還使用了 javax.ejb.Stateless 注釋,它用於聲明當前的會話 Bean 是一個無狀態的會話 Bean。

1.    package org.vivianj.jpademo;
2.
3.    import javax.ejb.Stateless;
4.    import javax.persistence.EntityManager;
5.    import javax.persistence.PersistenceContext;
6.
7.    import org.vivianj.jpademo.beans.Animal;
8.
9.    @Stateless
10.   public class AnimalDAO implements  IAnimalDAO,ILocalAnimalDAO {
11.    // 由 Java EE 容器向會話 Bean 中注入 EntityManager  對象
12.    @PersistenceContext
13.    EntityManager em;
14.
15.    public void persistAnimal(Animal animal) {
16.      /* 由於 EntityManager 的事務已經委托給 Java EE  容器的 JTA 事務,因此
17.      * 這裡直接持久化實體 , 不再需要使用 begin()、 commit() 顯式的處理實體
18.     * 操作時候的事務
19.     */
20.      em.persist(animal);
21.    }
22.
23.   }

打包、部署 OpenJPA 應用

在 JBoss 中加入 OpenJPA 的 jar 文件

要在 JBoss 應用服務器上運行 OpenJPA 應用,需要將 OpenJPA 的 jar 文件 加入到 JBoss 的 CLASSPATH 中,我們需要拷貝 %OPENJPA_HOME%\openjpa-*.jar 文件到 %JBOSS_HOME%\server\default\lib,另外還需要拷貝 %OPENJPA_HOME% \lib 下 common-*.jar 文件和 serp-*.jar 文件到 %JBOSS_HOME% \server\default\lib 下。

[注]%OPENJPA_HOME% 表示 OpenJPA 的安裝目錄,%JBOSS_HOME% 表示 JBoss 服務器的安裝路徑。

打包、發布 OpenJPA 應用

OpenJPA 應用開發完成後,需要打包成 EJB jar 後才能發布,我們可以使用 ANT 工具幫助我們完成 OpenJPA 應用的打包過程。另外,得益於 JBoss 服務器 的熱部署功能,我們也可以將 OpenJPA 應用的發布過程也使用 ANT 來完成。

[注]ANT 是 APACHE 軟件基金會的一個開源項目,可以協助開發者自動完成項 目的構建、測試、發布等工作。如何使用 ANT 請參考 ANT 項目的在線幫助文檔 。

實例中我們利用 ANT 來完成實體和 SessionBEAN 的編譯、實體的 Enhance 工作、將實體和 SessionBean 打包成 EJB jar,並且將生成的 EJB jar 拷貝到 JBoss 服務器中對應目錄下,JBoss 的熱部署功能能夠及時將生成 EJB jar 發布 到服務器上。

用來打包、部署 OpenJPA 應用的 ANT 配置文件 build.xml 文件的全部內容 如下:

1.    <project name="ejb3demo" default="ejbjar"  basedir=".">
2.     <property name="src.dir"  value="${basedir}" />
3.     <!—設置 JBoss 服務器的安裝路徑à
4.     <property name="jboss.home" value="C:\jboss- 4.2.0.GA" />
5.     <property name="build.dir" value="${basedir}/build"  />
6.     <property name="build.classes.dir"  value="${build.dir}/classes" />
7.
8.     <path id="classpath">
9.       <fileset dir="${jboss.home}/lib">
10.        <include name="**/*.jar" />
11.      </fileset>
12.      <fileset  dir="${jboss.home}/server/default/lib">
13.        <include name="**/*.jar" />
14.      </fileset>
15.      <fileset  dir="${jboss.home}/server/default/deploy/ejb3.deployer">
16.        <include name="*.jar" />
17.      </fileset>
18.      <fileset  dir="${jboss.home}/server/default/deploy/jboss-aop- jdk50.deployer">
19.        <include name="*.jar" />
20.      </fileset>
21.      <pathelement  location="${build.classes.dir}" />
22.      <pathelement location="${basedir}" />
23.    </path>
24.
25.    <property name="build.classpath"  refid="classpath" />
26.    <target name="prepare">
27.      <mkdir dir="${build.dir}" />
28.      <mkdir dir="${build.classes.dir}" />
29.    </target>
30.    <target name="compile" depends="prepare">
31.      <javac srcdir="${src.dir}"  destdir="${build.classes.dir}"
         debug="on" deprecation="on" optimize="off"  includes="**">
32.        <classpath refid="classpath" />
33.      </javac>
34.    </target>
35.    <!—完成實體的 Enhance à
36.    <target name="enhance" depends="compile">
37.    <!—OpenJPA 提供的完成 Enhance 的 ANT 任務à
38.    <taskdef name="openjpac"  classname="org.apache.openjpa.ant.PCEnhancerTask">
39.     <classpath refid="classpath" />
40.    </taskdef>
41.
42.    <openjpac>
43.     <!—設置需要 Enhance 的實體類à
44.      <fileset dir="${build.classes.dir}">
45.      <include name="**/beans/*.class" />
46.     </fileset>
47.     <classpath refid="classpath" />
48.    </openjpac>
49.    </target>
50.    <!—打包、發布 EJB jar à
51.    <target name="ejbjar" depends="enhance">
52.      <jar jarfile="build/StatelessSample.jar">
53.        <fileset dir="${build.classes.dir}">
54.          <include name="**/*.*" />
55.        </fileset>
56.      </jar>
57.      <copy file="build/StatelessSample.jar"  todir="${jboss.home}/server/default/deploy" />
|-------10--------20--------30--------40--------50--------60-------- 70--------80--------9|
|-------- XML error: The previous line is longer than the  max of 90 characters ---------|
58.    </target>
59.
60.    <target name="run" depends="ejbjar">
61.      <java classname="com.kuaff.ejb3.stateless.Client"  fork="yes" dir=".">
62.        <classpath refid="classpath" />
63.      </java>
64.    </target>
65.
66.    <target name="clean.db">
67.      <delete  dir="${jboss.home}/server/default/data/hypersonic" />
68.    </target>
69.    <target name="clean">
70.      <delete dir="${build.dir}" />
71.      <delete  file="${jboss.home}/server/default/deploy/StatelessSample.ejb3" />< BR> 72.    </target>
73.  </project>

簡單的測試客戶端

現在,實體 Animal 和封裝實體操作的 SessionBean 都已經編譯好並且發布 到 JBoss 應用服務器上,我們可以編寫一個簡單的客戶端來訪問 SessionBean, 測試對實體 Animal 的操作是否成功。

實例中,我們開發一個簡單的 JSP 文件 Client.jsp,在 JSP 中,創建新的 Animal 對象,設置它的 name 屬性為”警犬卡爾”,然後調用 SessionBean 的 persistAnimal 方法將這個實體持久化到數據庫中。

Client.jsp 文件位於 %JBOSS_HOME%\server\default\deploy\jboss- web.deployer\ROOT.war 目錄下,Client.jsp 文件的全部內容如下:

1.     <%@ page import="javax.naming.InitialContext"  %>
2.     <%@ page import="javax.naming.NamingException" % >
3.     <%@ page  import="org.vivianj.jpademo.ILocalAnimalDAO" %>
4.     <%@ page import="org.vivianj.jpademo.beans.Animal"  %>
5.
6.     <%
7.        // 初始化 JNDI 上下文
8.      InitialContext ctx;
9.        ctx = new InitialContext();
10.    // 獲取 SessionBean 的本地接口 
11.      ILocalAnimalDAO animalDAO = (ILocalAnimalDAO)  ctx.lookup("AnimalDAO/local");
12.    // 創建新的 Animal 對象
13.      Animal animal = new Animal();
14.      animal.setName(" 警犬卡爾 ");
15.    調用 SessionBean 的業務方法將 Animal 對象持久化到數據 庫中
16.      animalDAO.persistAnimal(animal);
17.   %>

現在啟動數據庫服務器、JBoss 應用服務器,然後在浏覽器地址欄中輸入 http://localhost:8080/Client.jsp,然後查詢數據庫中的 Animal 表,裡面應 該有一條記錄,它的 name 列的數據是”警犬卡爾”。

圖 1. 運行 http://localhost:8080/Client.jsp 後 Animal 表的查詢結果

總結

OpenJPA 框架符合 EJB3.0 規范中的 JPA 部分,因此 OpenJPA 既能夠作為持 久層框架獨立運行,也能夠被其他支持 EJB3.0 的 Java EE 容器集成後作為持久 層框架。本文中以 JBoss 應用服務器為例,借助於一個簡單的例子,詳細地描述 了如何在 JBoss 應用服務器環境下使用 OpenJPA 開發實體 Bean、並且用 SessionBean 封裝實體 Bean 操作、在客戶端通過 Local 接口訪問的開發、部署 過程。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved