目录

EJB - 快速指南

EJB - Overview

EJB代表Enterprise Java Beans 。 EJB是J2EE平台的重要组成部分。 J2EE平台具有基于组件的体系结构,可为企业级应用程序提供多层,分布式和高度事务性的功能。

EJB提供了一种架构,用于开发和部署基于组件的企业应用程序,同时考虑到健壮性,高可伸缩性和高性能。 EJB应用程序可以部署在符合J2EE 1.3标准规范的任何应用程序服务器上。

我们将在本教程中详细讨论EJB 3.0。

类型 (Types)

EJB主要分为三类; 下表列出了他们的名字和简要说明 -

S.No 类型和描述
1

Session Bean

会话bean为单个会话存储特定用户的数据。 它可以是stateful ,也可以是stateless 。 与实体bean相比,它的资源密集程度较低。 一旦用户会话终止,会话bean就会被销毁。

2

Entity Bean

Entity beans表示持久数据存储。 用户数据可以通过实体bean保存到数据库中,以后可以从实体bean中的数据库中检索。

3

Message Driven Bean

Message driven beans用于JMS(Java消息传递服务)的上下文中。 消息驱动Bean可以使用来自外部实体的JMS消息并相应地执行操作。

好处 (Benefits)

以下是EJB的重要好处 -

  • 简化了大型企业级应用程序的开发。

  • Application Server/EJB容器提供了大多数系统级服务,如事务处理,日志记录,负载平衡,持久性机制,异常处理等。 开发人员必须只关注应用程序的业务逻辑。

  • EJB容器管理EJB实例的生命周期,因此开发人员无需担心何时创建/删除EJB对象。

EJB - Environment Setup

EJB是Java的框架,因此第一个要求是在您的机器中安装J ava D evelopment K it(JDK)。

系统需求 (System Requirement)

JDK 1.5或以上。
记忆 没有最低要求。
磁盘空间 没有最低要求。
操作系统 没有最低要求。

步骤1 - 验证系统中的Java安装

现在打开控制台并执行以下java命令。

OS 任务 命令
Windows 打开命令控制台 c:\> java -version
Linux 打开命令终端 $ java -version
Mac 开放式终端 机器:~joseph $ java -version

让我们验证所有操作系统的输出 -

OS Output
Windows

java版“1.6.0_21”

Java(TM)SE运行时环境(版本1.6.0_21-b11)

Java HotSpot(TM)64位服务器VM(内置23.21-b01,混合模式)

Linux

java版“1.6.0_21”

Java(TM)SE运行时环境(版本1.6.0_21-b11)

Java HotSpot(TM)64位服务器VM(内置23.21-b01,混合模式)

Mac

java版“1.6.0_21”

Java(TM)SE运行时环境(版本1.6.0_21-b11)

Java HotSpot(TM)64位服务器VM(内置23.21-b01,混合模式)

如果未安装Java,请从https://www.oracle.com/technetwork/java/javase/downloads/index.html安装Java软件开发工具包(SDK)。 我们假设Java 1.6.0_21是本教程的已安装版本。

第2步 - 设置JAVA环境

设置JAVA_HOME环境变量以指向系统上安装Java的基本目录位置。 例如,

OS Output
Windows 将环境变量JAVA_HOME设置为C:\Program Files\Java\jdk1.6.0_21
Linux export JAVA_HOME =/usr/local/java-current
Mac export JAVA_HOME =/Library/Java/Home

将Java编译器位置附加到系统路径。

OS Output
Windows 将字符串; C:\Program Files\Java\jdk1.6.0_21\bin附加到系统变量Path的末尾。
Linux export PATH = $ PATH:$ JAVA_HOME/bin/
Mac 不需要

使用上面解释的java -version命令验证Java安装。

步骤3 - 下载并安装NetBeans IDE

https://netbeans.org/downloads/index.html下载最新版本的NetBeans IDE。 在编写本教程时,我使用以下链接https://www.oracle.com/technetwork/java/javase/downloads/index.html下载了与JDK 1.7捆绑在一起的Netbeans 7.3

OS 安装程序名称
Windows Netbeans 7.3
Linux Netbeans 7.3
Mac Netbeans 7.3

第4步 - 安装JBoss Application Server

您可以从https://www.jboss.org/jbossas/downloads/下载最新版本的JBoss Server。 根据平台下载存档。 将Jboss解压缩到计算机上的任何位置。

OS 文件名
Windowsjboss-5.1.0.GA-jdk6.zip
Linuxjboss-5.1.0.GA-src.tar.gz
Macjboss-5.1.0.GA-src.tar.gz

步骤5 - 将JEE插件配置为Netbeans

使用工具>插件打开插件窗口。 打开“Available Plugin”选项卡,在“Java Web and EE”类别下选择“Java EE Base”和“EJB and EAR”。 单击安装按钮。 Netbeans将下载并安装相应的插件。 使用“已安装”选项卡验证插件安装(如下图所示)。

已安装的插件

步骤6 - 在Netbeans中配置JBoss服务器

转到“服务”选项卡,右键单击服务器以添加新服务器。

添加服务器

将打开“添加服务器实例”向导。 选择JBoss,然后在下一步中输入相关详细信息以在netbeans中配置服务器。

选择Server

配置完所有内容后,您将看到以下屏幕。

已安装的服务器

第7步 - 安装数据库服务器(PostGreSql)

https://www.postgresql.org/download/下载最新版本的PostGreSql数据库服务器。 在编写本教程时,我下载了PostGreSql 9.2

OS 安装程序名称
Windows PostGreSql 9.2
Linux PostGreSql 9.2
Mac PostGreSql 9.2

EJB - Create Application

要创建一个简单的EJB模块,我们将使用NetBeans“新建项目”向导。 在下面给出的示例中,我们将创建一个名为Component的EJB模块项目。

创建项目

在NetBeans IDE中,选择“ File 》 New Project 》 。 您将看到以下屏幕

新建项目向导第1步

在类别Java EE下选择项目类型,将项目类型选择为EJB Module 。 单击“ Next 》按钮。 您将看到以下屏幕。

新建项目向导第2步

输入项目名称和位置。 单击“ Next 》按钮。 您将看到以下屏幕。

新建项目向导第3步

选择Server作为JBoss Application Server 。 单击Finish按钮。 您将看到NetBeans创建的以下项目。

项目资源管理器

创建一个示例EJB

要创建一个简单的EJB,我们将使用NetBeans“新建”向导。 在下面给出的示例中,我们将在EjbComponent项目下创建名为librarySessionBean的无状态EJB类。

在项目资源管理器窗口中选择项目EjbComponent并右键单击它。 选择, New 》 Session Bean 。 您将看到New Session Bean向导。

新会话Bean向导

输入会话bean名称和包名称。 单击Finish按钮。 您将看到NetBeans创建的以下EJB类。

  • LibrarySessionBean - 无状态会话bean

  • LibrarySessionBeanLocal - 会话bean的本地接口

我正在将本地接口更改为远程接口,因为我们将在基于控制台的应用程序中访问我们的EJB。 远程/本地接口用于公开EJB必须实现的业务方法。

LibrarySessionBeanLocal重命名为LibrarySessionBeanRemote,LibrarySessionBean实现LibrarySessionBeanRemote接口。

LibrarySessionBeanRemote

package com.iowiki.stateless;
import java.util.List;
import javax.ejb.Remote;
@Remote
public interface LibrarySessionBeanRemote {
   void addBook(String bookName);
   List getBooks();
}

LibrarySessionBean

package com.iowiki.stateless;
import java.util.ArrayList;
import java.util.List;
import javax.ejb.Stateless;
@Stateless
public class LibrarySessionBean implements LibrarySessionBeanRemote {
   List<String> bookShelf;    
   public LibrarySessionBean(){
      bookShelf = new ArrayList<String>();
   }
   public void addBook(String bookName) {
      bookShelf.add(bookName);
   }    
   public List<String> getBooks() {
      return bookShelf;
   }
}

构建项目 (Build the Project)

  • 在Project Explorer窗口中选择EjbComponent项目。
  • 右键单击它以打开上下文菜单。
  • Select clean and build.

您将在NetBeans控制台输出中看到以下输出。

ant -f C:\\EJB\\EjbComponent clean dist
init:
undeploy-clean:
deps-clean:
Deleting directory C:\EJB\EjbComponent\build
Deleting directory C:\EJB\EjbComponent\dist
clean:
init:
deps-jar:
Created dir: C:\EJB\EjbComponent\build\classes
Copying 3 files to C:\EJB\EjbComponent\build\classes\META-INF
Created dir: C:\EJB\EjbComponent\build\empty
Created dir: C:\EJB\EjbComponent\build\generated-sources\ap-source-output
Compiling 2 source files to C:\EJB\EjbComponent\build\classes
warning: [options] bootstrap class path not set in conjunction with -source 1.6
Note: C:\EJB\EjbComponent\src\java\com\iowiki\stateless
\LibraryPersistentBean.java uses unchecked or unsafe operations.
Note: Recompile with -Xlint:unchecked for details.
1 warning
compile:
library-inclusion-in-archive:
Created dir: C:\EJB\EjbComponent\dist
Building jar: C:\EJB\EjbComponent\dist\EjbComponent.jar
dist:
BUILD SUCCESSFUL (total time: 3 seconds)

启动Application Server

  • 在Services in Services窗口中选择JBoss应用程序服务器。
  • 右键单击它以打开上下文菜单。
  • 选择开始。

您将在NetBeans中看到以下输出,在JBoss Application Server下输出。

Calling C:\jboss-5.1.0.GA\bin\run.conf.bat
=========================================================================
   JBoss Bootstrap Environment
   JBOSS_HOME: C:\jboss-5.1.0.GA
   JAVA: C:\Program Files (x86)\Java\jdk1.6.0_21\bin\java
   JAVA_OPTS: -Dprogram.name=run.bat -Xms128m -Xmx512m -server
   CLASSPATH: C:\jboss-5.1.0.GA\bin\run.jar
=========================================================================
16:25:50,062 INFO  [ServerImpl] Starting JBoss (Microcontainer)...
16:25:50,062 INFO  [ServerImpl] Release ID: JBoss 
   [The Oracle] 5.1.0.GA (build: SVNTag=JBoss_5_1_0_GA date=200905221634)
...
16:26:40,420 INFO  [TomcatDeployment] deploy, ctxPath=/admin-console
16:26:40,485 INFO  [config] Initializing Mojarra (1.2_12-b01-FCS) for context '/admin-console'
16:26:42,362 INFO  [TomcatDeployment] deploy, ctxPath=/
16:26:42,406 INFO  [TomcatDeployment] deploy, ctxPath=/jmx-console
16:26:42,471 INFO  [Http11Protocol] Starting Coyote HTTP/1.1 on http-127.0.0.1-8080
16:26:42,487 INFO  [AjpProtocol] Starting Coyote AJP/1.3 on ajp-127.0.0.1-8009
16:26:42,493 INFO  [ServerImpl] JBoss (Microcontainer) 
   [5.1.0.GA (build: SVNTag=JBoss_5_1_0_GA date=200905221634)] Started in 52s:427ms

部署项目

  • 在Project Explorer窗口中选择EjbComponent项目。
  • 右键单击它以打开上下文菜单。
  • 选择“部署”。

您将在NetBeans控制台输出中看到以下输出。

ant -f C:\\EJB\\EjbComponent -DforceRedeploy=true -Ddirectory.deployment.supported=false -Dnb.wait.for.caches=true run
init:
deps-jar:
compile:
library-inclusion-in-archive:
Building jar: C:\EJB\EjbComponent\dist\EjbComponent.jar
dist-directory-deploy:
pre-run-deploy:
Checking data source definitions for missing JDBC drivers...
Distributing C:\EJB\EjbComponent\dist\EjbComponent.jar to [org.jboss.deployment.spi.LocalhostTarget@1e4f84ee]
Deploying C:\EJB\EjbComponent\dist\EjbComponent.jar
Application Deployed
Operation start started
Operation start completed
post-run-deploy:
run-deploy:
run:
BUILD SUCCESSFUL (total time: 2 seconds)

JBoss应用服务器日志输出

16:30:00,963 INFO  [DeployHandler] Begin start, [EjbComponent.jar]
...
16:30:01,233 INFO  [Ejb3DependenciesDeployer] Encountered deployment AbstractVFSDeploymentContext@12038795{vfszip:/C:/jboss-5.1.0.GA/server/default/deploy/EjbComponent.jar/}
...
16:30:01,281 INFO  [JBossASKernel]    jndi:LibrarySessionBean/remote-com.iowiki.stateless.LibrarySessionBeanRemote
16:30:01,281 INFO  [JBossASKernel]    Class:com.iowiki.stateless.LibrarySessionBeanRemote
16:30:01,281 INFO  [JBossASKernel]    jndi:LibrarySessionBean/remote
16:30:01,281 INFO  [JBossASKernel]  Added bean(jboss.j2ee:jar=EjbComponent.jar,name=
LibrarySessionBean,service=EJB3) to KernelDeployment of: EjbComponent.jar
16:30:01,282 INFO  [JBossASKernel] installing bean: jboss.j2ee:jar=EjbComponent.jar,name=BookMessageHandler,service=EJB3
16:30:01,282 INFO  [JBossASKernel]   with dependencies:
16:30:01,282 INFO  [JBossASKernel]   and demands:
16:30:01,282 INFO  [JBossASKernel]    jboss.ejb:service=EJBTimerService
...
16:30:01,283 INFO  [EJB3EndpointDeployer] Deploy 
AbstractBeanMetaData@5497cb{name=jboss.j2ee:jar=EjbComponent.jar, 
name=LibrarySessionBean, service=EJB3_endpoint bean=org.jboss.ejb3.endpoint.deployers.impl.EndpointImpl properties=[container] constructor=null autowireCandidate=true}
...
16:30:01,394 INFO  [SessionSpecContainer] Starting jboss.j2ee:jar=EjbComponent.jar,name=LibrarySessionBean,service=EJB3
16:30:01,395 INFO  [EJBContainer] STARTED EJB: com.iowiki.stateless.LibrarySessionBean ejbName: LibrarySessionBean
16:30:01,401 INFO  [JndiSessionRegistrarBase] Binding the following Entries in Global JNDI:
   LibrarySessionBean/remote - EJB3.x Default Remote Business Interface
   LibrarySessionBean/remote-com.iowiki.stateless.LibrarySessionBeanRemote - EJB3.x Remote Business Interface
16:30:02,723 INFO  [SessionSpecContainer] Starting jboss.j2ee:jar=EjbComponent.jar,name=LibrarySessionBean,service=EJB3
16:30:02,723 INFO  [EJBContainer] STARTED EJB: com.iowiki.stateless.LibrarySessionBean ejbName: LibrarySessionBean
16:30:02,731 INFO  [JndiSessionRegistrarBase] Binding the following Entries in Global JNDI:
   LibrarySessionBean/remote - EJB3.x Default Remote Business Interface
   LibrarySessionBean/remote-com.iowiki.stateless.LibrarySessionBeanRemote - EJB3.x Remote Business Interface

创建客户端以访问EJB

  • 在NetBeans IDE中,选择“ File 》 New Project 》

  • Java类别下选择项目类型,将项目类型选择为Java Application 。 单击“下一步”按钮

  • 输入项目名称和位置。 单击“ Finish 》按钮。 我们选择了名字为EjbTester。

  • 在Project explorer窗口中右键单击项目名称。 选择properties

  • 使用compile选项卡中的“ Add Project按钮Add Project先前在库下创建的EJB组件项目

  • 使用compile选项卡中的Add jar/folder按钮添加jboss库。 Jboss库可以位于“jboss安装文件夹”“客户端文件夹中。

在项目下创建jndi.properties说EjbTester。

jndi.properties

java.naming.factory.initial=org.jnp.interfaces.NamingContextFactory
java.naming.factory.url.pkgs=org.jboss.naming:org.jnp.interfaces
java.naming.provider.url=localhost

在它下面创建包com.iowiki.test和EJBTester.java类。

EJBTester.java

package com.iowiki.test;
import com.iowiki.stateless.LibrarySessionBeanRemote;
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.List;
import java.util.Properties;
import javax.naming.InitialContext;
import javax.naming.NamingException;
public class EJBTester {
   BufferedReader brConsoleReader = null; 
   Properties props;
   InitialContext ctx;
   {
      props = new Properties();
      try {
         props.load(new FileInputStream("jndi.properties"));
      } catch (IOException ex) {
         ex.printStackTrace();
      }
      try {
         ctx = new InitialContext(props);            
      } catch (NamingException ex) {
         ex.printStackTrace();
      }
      brConsoleReader = 
      new BufferedReader(new InputStreamReader(System.in));
   }
   public static void main(String[] args) {
      EJBTester ejbTester = new EJBTester();
      ejbTester.testStatelessEjb();
   }
   private void showGUI(){
      System.out.println("**********************");
      System.out.println("Welcome to Book Store");
      System.out.println("**********************");
      System.out.print("Options \n1. Add Book\n2. Exit \nEnter Choice: ");
   }
   private void testStatelessEjb(){
      try {
         int choice = 1; 
         LibrarySessionBeanRemote libraryBean = 
         (LibrarySessionBeanRemote)ctx.lookup("LibrarySessionBean/remote");
         while (choice != 2) {
            String bookName;
            showGUI();
            String strChoice = brConsoleReader.readLine();
            choice = Integer.parseInt(strChoice);
            if (choice == 1) {
               System.out.print("Enter book name: ");
               bookName = brConsoleReader.readLine();                    
               libraryBean.addBook(bookName);          
            }else if (choice == 2) {
               break;
            }
         }
         List<String> booksList = libraryBean.getBooks();
         System.out.println("Book(s) entered so far: " + booksList.size());
         for (int i = 0; i < booksList.size(); ++i) {
            System.out.println((i+1)+". " + booksList.get(i));
         }
         LibrarySessionBeanRemote libraryBean1 = 
         (LibrarySessionBeanRemote)ctx.lookup("LibrarySessionBean/remote");
         List<String> booksList1 = libraryBean1.getBooks();
         System.out.println(
            "***Using second lookup to get library stateless object***");
         System.out.println(
            "Book(s) entered so far: " + booksList1.size());
         for (int i = 0; i < booksList1.size(); ++i) {
            System.out.println((i+1)+". " + booksList1.get(i));
         }
      } catch (Exception e) {
         System.out.println(e.getMessage());
         e.printStackTrace();
      }finally {
         try {
            if(brConsoleReader !=null){
               brConsoleReader.close();
            }
         } catch (IOException ex) {
            System.out.println(ex.getMessage());
         }
      }
   }  
}

运行客户端以访问EJB

在项目资源管理器中找到EJBTester.java。 右键单击EJBTester类并选择run file

在Netbeans控制台中验证以下输出。

run:
**********************
Welcome to Book Store
**********************
Options 
1. Add Book
2. Exit 
Enter Choice: 1
Enter book name: Learn Java
**********************
Welcome to Book Store
**********************
Options 
1. Add Book
2. Exit 
Enter Choice: 2
Book(s) entered so far: 1
1. Learn Java
***Using second lookup to get library stateless object***
Book(s) entered so far: 0
BUILD SUCCESSFUL (total time: 13 seconds)

在接下来的章节中,我们将介绍这个完整EJB应用程序的多个方面。

EJB - Stateless Bean

无状态会话bean是一种企业bean,通常用于执行独立操作。 无状态会话bean根据其名称没有任何关联的客户端状态,但它可以保留其实例状态。 EJB容器通常会创建一个包含少量无状态bean对象的池,并使用这些对象来处理客户端的请求。 由于池,在查找/方法调用中不保证实例变量值相同。

创建无状态EJB的步骤

以下是创建无状态EJB所需的步骤 -

  • 创建公开业务方法的远程/本地接口。

  • EJB客户端应用程序将使用此接口。

  • 如果EJB客户端位于要部署EJB会话bean的相同环境中,请使用@Local批注。

  • 如果EJB客户端位于要部署EJB会话bean的不同环境中,请使用@Remote注释。

  • 创建无状态会话bean,实现上述接口。

  • 使用@Stateless注释将其表示为无状态bean。 EJB容器通过在部署期间读取此批注来自动创建所需的相关配置或接口。

远程接口

import javax.ejb.Remote;
@Remote
public interface LibrarySessionBeanRemote {
   //add business method declarations
}

无状态EJB

@Stateless
public class LibrarySessionBean implements LibrarySessionBeanRemote {
   //implement business method 
}

例子 Example Application

让我们创建一个测试EJB应用程序来测试无状态EJB。

描述
1EJB - Create Application章节中解释,在com.iowiki.stateless包下创建一个名为EjbComponent的项目。 您还可以使用在EJB - Create Application的项目EJB - Create Application章节,以便本章了解无状态EJB概念。
2 按照EJB - Create Application章节中的说明创建LibrarySessionBean.javaLibrarySessionBeanRemote 。 保持其余文件不变。
3 清理并构建应用程序以确保业务逻辑按照要求运行。
4 最后,在JBoss Application Server上以jar文件的形式部署应用程序。 如果JBoss Application服务器尚未启动,它将自动启动。
5 现在创建EJB客户端,一个基于控制台的应用程序,其方式与EJB - Create Application章节中主题Create Client to access EJB

EJBComponent (EJB Module)

LibrarySessionBeanRemote.java

package com.iowiki.stateless;
import java.util.List;
import javax.ejb.Remote;
@Remote
public interface LibrarySessionBeanRemote {
   void addBook(String bookName);
   List getBooks();
}

LibrarySessionBean.java

 
package com.iowiki.stateless;
import java.util.ArrayList;
import java.util.List;
import javax.ejb.Stateless;
@Stateless
public class LibrarySessionBean implements LibrarySessionBeanRemote {
   List<String> bookShelf;    
   public LibrarySessionBean(){
      bookShelf = new ArrayList<String>();
   }
   public void addBook(String bookName) {
      bookShelf.add(bookName);
   }    
   public List<String> getBooks() {
      return bookShelf;
   }
}
  • 只要在JBOSS上部署EjbComponent项目,请注意jboss日志。

  • JBoss已自动为会话bean创建了一个JNDI条目 - LibrarySessionBean/remote

  • 我们将使用此查找字符串来获取类型的远程业务对象 - com.iowiki.stateless.LibrarySessionBeanRemote

JBoss应用服务器日志输出

...
16:30:01,401 INFO  [JndiSessionRegistrarBase] Binding the following Entries in Global JNDI:
   LibrarySessionBean/remote - EJB3.x Default Remote Business Interface
   LibrarySessionBean/remote-com.iowiki.stateless.LibrarySessionBeanRemote - EJB3.x Remote Business Interface
16:30:02,723 INFO  [SessionSpecContainer] Starting jboss.j2ee:jar=EjbComponent.jar,name=LibrarySessionBean,service=EJB3
16:30:02,723 INFO  [EJBContainer] STARTED EJB: com.iowiki.stateless.LibrarySessionBeanRemote ejbName: LibrarySessionBean
16:30:02,731 INFO  [JndiSessionRegistrarBase] Binding the following Entries in Global JNDI:
   LibrarySessionBean/remote - EJB3.x Default Remote Business Interface
   LibrarySessionBean/remote-com.iowiki.stateless.LibrarySessionBeanRemote - EJB3.x Remote Business Interface
...   

EJBTester (EJB Client)

jndi.properties

java.naming.factory.initial=org.jnp.interfaces.NamingContextFactory
java.naming.factory.url.pkgs=org.jboss.naming:org.jnp.interfaces
java.naming.provider.url=localhost
  • 这些属性用于初始化java命名服务的InitialContext对象。

  • InitialContext对象将用于查找无状态会话bean。

EJBTester.java

package com.iowiki.test;
import com.iowiki.stateful.LibrarySessionBeanRemote;
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.List;
import java.util.Properties;
import javax.naming.InitialContext;
import javax.naming.NamingException;
public class EJBTester {
   BufferedReader brConsoleReader = null; 
   Properties props;
   InitialContext ctx;
   {
      props = new Properties();
      try {
         props.load(new FileInputStream("jndi.properties"));
      } catch (IOException ex) {
         ex.printStackTrace();
      }
      try {
         ctx = new InitialContext(props);            
      } catch (NamingException ex) {
         ex.printStackTrace();
      }
      brConsoleReader = 
      new BufferedReader(new InputStreamReader(System.in));
   }
   public static void main(String[] args) {
      EJBTester ejbTester = new EJBTester();
      ejbTester.testStatelessEjb();
   }
   private void showGUI(){
      System.out.println("**********************");
      System.out.println("Welcome to Book Store");
      System.out.println("**********************");
      System.out.print("Options \n1. Add Book\n2. Exit \nEnter Choice: ");
   }
   private void testStatelessEjb(){
      try {
         int choice = 1; 
         LibrarySessionBeanRemote libraryBean =
         LibrarySessionBeanRemote)ctx.lookup("LibrarySessionBean/remote");
         while (choice != 2) {
            String bookName;
            showGUI();
            String strChoice = brConsoleReader.readLine();
            choice = Integer.parseInt(strChoice);
            if (choice == 1) {
               System.out.print("Enter book name: ");
               bookName = brConsoleReader.readLine();
               Book book = new Book();
               book.setName(bookName);
               libraryBean.addBook(book);          
            } else if (choice == 2) {
               break;
            }
         }
         List<Book> booksList = libraryBean.getBooks();
         System.out.println("Book(s) entered so far: " + booksList.size());
         int i = 0;
         for (Book book:booksList) {
            System.out.println((i+1)+". " + book.getName());
            i++;
         }       
         LibrarySessionBeanRemote libraryBean1 = 
            (LibrarySessionBeanRemote)ctx.lookup("LibrarySessionBean/remote");
         List<String> booksList1 = libraryBean1.getBooks();
         System.out.println(
            "***Using second lookup to get library stateless object***");
         System.out.println(
            "Book(s) entered so far: " + booksList1.size());
         for (int i = 0; i < booksList1.size(); ++i) {
            System.out.println((i+1)+". " + booksList1.get(i));
         }		 
      } catch (Exception e) {
         System.out.println(e.getMessage());
         e.printStackTrace();
      }finally {
         try {
            if(brConsoleReader !=null){
               brConsoleReader.close();
            }
         } catch (IOException ex) {
            System.out.println(ex.getMessage());
         }
      }
   }
}

EJBTester执行以下任务 -

  • 从jndi.properties加载属性并初始化InitialContext对象。

  • 在testStatelessEjb()方法中,使用名称 - “LibrarySessionBean/remote”完成jndi查找以获取远程业务对象(无状态ejb)。

  • 然后向用户显示库存储用户界面,并要求他/她输入选择。

  • 如果用户输入1,系统将询问书名并使用无状态会话bean addBook()方法保存书籍。 会话Bean将书存储在其实例变量中。

  • 如果用户输入2,系统将使用无状态会话bean getBooks()方法检索书籍并退出。

  • 然后使用名称“LibrarySessionBean/remote”完成另一个jndi查找,以再次获取远程业务对象(无状态EJB)并完成书籍列表。

运行客户端以访问EJB

在项目资源管理器中找到EJBTester.java。 右键单击EJBTester类并选择run file

在Netbeans控制台中验证以下输出。

run:
**********************
Welcome to Book Store
**********************
Options 
1. Add Book
2. Exit 
Enter Choice: 1
Enter book name: Learn Java
**********************
Welcome to Book Store
**********************
Options 
1. Add Book
2. Exit 
Enter Choice: 2
Book(s) entered so far: 1
1. Learn Java
***Using second lookup to get library stateless object***
Book(s) entered so far: 0
BUILD SUCCESSFUL (total time: 13 seconds)

再次运行客户端以访问EJB

在项目资源管理器中找到EJBTester.java。 右键单击EJBTester类并选择run file

在Netbeans控制台中验证以下输出。

run:
**********************
Welcome to Book Store
**********************
Options 
1. Add Book
2. Exit 
Enter Choice: 2
Book(s) entered so far: 0
***Using second lookup to get library stateless object***
Book(s) entered so far: 1
1. Learn Java
BUILD SUCCESSFUL (total time: 12 seconds)
  • 上面显示的输出可能会有所不同,具体取决于JBoss维护的无状态EJB对象的数量。

  • 如果维护单个无状态EJB对象,则每次查找后可能会看到相同的书籍列表。

  • EJB容器可以为每个查找返回相同的无状态EJB对象。

  • 无状态EJB bean保留实例变量的值,直到服务器未重新启动。

EJB - Stateful Bean

有状态会话bean是一种企业bean,它保留与客户端的会话状态。 有状态会话bean根据其名称在其实例变量中保持关联的客户端状态。 EJB容器创建一个单独的有状态会话bean来处理客户端的每个请求。 一旦请求范围结束,就会销毁statelful会话bean。

创建有状态EJB的步骤

以下是创建有状态EJB所需的步骤 -

  • 创建公开业务方法的远程/本地接口。

  • EJB客户端应用程序将使用此接口。

  • 如果EJB客户端位于需要部署EJB会话bean的相同环境中,请使用@Local批注。

  • 如果EJB客户端位于需要部署EJB会话bean的不同环境中,请使用@Remote注释。

  • 创建一个有状态会话bean,实现上面的接口。

  • 使用@Stateful注释将其表示为有状态bean。 EJB容器通过在部署期间读取此批注来自动创建所需的相关配置或接口。

远程接口

import javax.ejb.Remote;
@Remote
public interface LibraryStatefulSessionBeanRemote {
   //add business method declarations
}

有状态EJB

@Stateful
public class LibraryStatefulSessionBean implements LibraryStatefulSessionBeanRemote {
   //implement business method 
}

例子 Example Application

让我们创建一个测试EJB应用程序来测试有状态EJB。

描述
1EJB − Create Application章节中解释,在com.iowiki.stateful包下创建一个名为EjbComponent的项目。 您还可以使用在EJB - Create Application的项目EJB - Create Application章节,以便本章了解有状态EJB概念。
2 按照EJB − Create Application章节中的说明创建LibraryStatefulSessionBean.javaLibraryStatefulSessionBeanRemote 。 保持其余文件不变。
3 清理并构建应用程序以确保业务逻辑按照要求运行。
4 最后,在JBoss Application Server上以jar文件的形式部署应用程序。 如果JBoss Application服务器尚未启动,它将自动启动。
5 现在创建EJB客户端,一个基于控制台的应用程序,其方式与EJB - Create Application章节中主题Create Client to access EJB

EJBComponent (EJB Module)

LibraryStatefulSessionBeanRemote.java

package com.iowiki.stateful;
import java.util.List;
import javax.ejb.Remote;
@Remote
public interface LibraryStatefulSessionBeanRemote {
   void addBook(String bookName);
   List getBooks();
}

LibraryStatefulSessionBean.java

 
package com.iowiki.stateful;
import java.util.ArrayList;
import java.util.List;
import javax.ejb.Stateful;
@Stateful
public class LibraryStatefulSessionBean implements LibraryStatefulSessionBeanRemote {
   List<String> bookShelf;    
   public LibraryStatefulSessionBean(){
      bookShelf = new ArrayList<String>();
   }
   public void addBook(String bookName) {
      bookShelf.add(bookName);
   }    
   public List<String> getBooks() {
      return bookShelf;
   }
}
  • 只要在JBOSS上部署EjbComponent项目,请注意jboss日志。

  • JBoss已自动为会话bean创建了一个JNDI条目 - LibraryStatefulSessionBean/remote

  • 我们将使用此查找字符串来获取类型的远程业务对象 - com.iowiki.stateful.LibraryStatefulSessionBeanRemote

JBoss应用服务器日志输出

...
16:30:01,401 INFO  [JndiSessionRegistrarBase] Binding the following Entries in Global JNDI:
   LibraryStatefulSessionBean/remote - EJB3.x Default Remote Business Interface
   LibraryStatefulSessionBean/remote-com.iowiki.stateful.LibraryStatefulSessionBeanRemote - EJB3.x Remote Business Interface
16:30:02,723 INFO  [SessionSpecContainer] Starting jboss.j2ee:jar=EjbComponent.jar,name=LibraryStatefulSessionBean,service=EJB3
16:30:02,723 INFO  [EJBContainer] STARTED EJB: com.iowiki.stateful.LibraryStatefulSessionBeanRemote ejbName: LibraryStatefulSessionBean
16:30:02,731 INFO  [JndiSessionRegistrarBase] Binding the following Entries in Global JNDI:
   LibraryStatefulSessionBean/remote - EJB3.x Default Remote Business Interface
   LibraryStatefulSessionBean/remote-com.iowiki.stateful.LibraryStatefulSessionBeanRemote - EJB3.x Remote Business Interface
...   

EJBTester (EJB Client)

jndi.properties

java.naming.factory.initial = org.jnp.interfaces.NamingContextFactory
java.naming.factory.url.pkgs = org.jboss.naming:org.jnp.interfaces
java.naming.provider.url = localhost
  • 这些属性用于初始化java命名服务的InitialContext对象。

  • InitialContext对象将用于查找有状态会话bean。

EJBTester.java

package com.iowiki.test;
import com.iowiki.stateful.LibraryStatefulSessionBeanRemote;
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.List;
import java.util.Properties;
import javax.naming.InitialContext;
import javax.naming.NamingException;
public class EJBTester {
   BufferedReader brConsoleReader = null; 
   Properties props;
   InitialContext ctx;
   {
      props = new Properties();
      try {
         props.load(new FileInputStream("jndi.properties"));
      } catch (IOException ex) {
         ex.printStackTrace();
      }
      try {
         ctx = new InitialContext(props);            
      } catch (NamingException ex) {
         ex.printStackTrace();
      }
      brConsoleReader = 
      new BufferedReader(new InputStreamReader(System.in));
   }
   public static void main(String[] args) {
      EJBTester ejbTester = new EJBTester();
      ejbTester.testStatelessEjb();
   }
   private void showGUI(){
      System.out.println("**********************");
      System.out.println("Welcome to Book Store");
      System.out.println("**********************");
      System.out.print("Options \n1. Add Book\n2. Exit \nEnter Choice: ");
   }
   private void testStatelessEjb(){
      try {
         int choice = 1; 
         LibraryStatefulSessionBeanRemote libraryBean =
         LibraryStatefulSessionBeanRemote)ctx.lookup("LibraryStatefulSessionBean/remote");
         while (choice != 2) {
            String bookName;
            showGUI();
            String strChoice = brConsoleReader.readLine();
            choice = Integer.parseInt(strChoice);
            if (choice == 1) {
               System.out.print("Enter book name: ");
               bookName = brConsoleReader.readLine();
               Book book = new Book();
               book.setName(bookName);
               libraryBean.addBook(book);          
            } else if (choice == 2) {
               break;
            }
         }
         List<Book> booksList = libraryBean.getBooks();
         System.out.println("Book(s) entered so far: " + booksList.size());
         int i = 0;
         for (Book book:booksList) {
            System.out.println((i+1)+". " + book.getName());
            i++;
         }       
         LibraryStatefulSessionBeanRemote libraryBean1 = 
            (LibraryStatefulSessionBeanRemote)ctx.lookup("LibraryStatefulSessionBean/remote");
         List<String> booksList1 = libraryBean1.getBooks();
         System.out.println(
            "***Using second lookup to get library stateful object***");
         System.out.println(
            "Book(s) entered so far: " + booksList1.size());
         for (int i = 0; i < booksList1.size(); ++i) {
            System.out.println((i+1)+". " + booksList1.get(i));
         }		 
      } catch (Exception e) {
         System.out.println(e.getMessage());
         e.printStackTrace();
      }finally {
         try {
            if(brConsoleReader !=null){
               brConsoleReader.close();
            }
         } catch (IOException ex) {
            System.out.println(ex.getMessage());
         }
      }
   }
}

EJBTester执行以下任务 -

  • 从jndi.properties加载属性并初始化InitialContext对象。

  • 在testStatefulEjb()方法中,使用name - “LibraryStatefulSessionBean/remote”完成jndi查找以获取远程业务对象(有状态ejb)。

  • 然后向用户显示库存储用户界面,并要求他/她输入选项。

  • 如果用户输入1,系统会询问书名并使用有状态会话bean addBook()方法保存书籍。 会话Bean将书存储在其实例变量中。

  • 如果用户输入2,系统将使用有状态会话bean getBooks()方法检索书籍并退出。

  • 然后使用名称“LibraryStatefulSessionBean/remote”完成另一个jndi查找,以再次获取远程业务对象(有状态EJB)并完成书籍列表。

运行客户端以访问EJB

在项目资源管理器中找到EJBTester.java。 右键单击EJBTester类并选择run file

在Netbeans控制台中验证以下输出 -

run:
**********************
Welcome to Book Store
**********************
Options 
1. Add Book
2. Exit 
Enter Choice: 1
Enter book name: Learn Java
**********************
Welcome to Book Store
**********************
Options 
1. Add Book
2. Exit 
Enter Choice: 2
Book(s) entered so far: 1
1. Learn Java
***Using second lookup to get library stateful object***
Book(s) entered so far: 0
BUILD SUCCESSFUL (total time: 13 seconds)

再次运行客户端以访问EJB

在项目资源管理器中找到EJBTester.java。 右键单击EJBTester类并选择run file

在Netbeans控制台中验证以下输出。

run:
**********************
Welcome to Book Store
**********************
Options 
1. Add Book
2. Exit 
Enter Choice: 2
Book(s) entered so far: 0
***Using second lookup to get library stateful object***
Book(s) entered so far: 0
BUILD SUCCESSFUL (total time: 12 seconds)
  • 上面显示的输出表明,对于每次查找,都会返回不同的有状态EJB实例。

  • 有状态EJB对象仅保留单个会话的值。 与第二轮一样,我们没有获得任何书籍价值。

EJB - Persistence

EJB 3.0,EJB 2.0中使用的实体bean在很大程度上被持久性机制所取代。 现在,实体bean是一个简单的POJO,它具有与表的映射。

以下是持久性API中的关键角色 -

  • Entity - 表示数据存储记录的持久对象。 可序列化是件好事。

  • EntityManager - 持久性接口,用于对持久对象(实体)执行添加/删除/更新/查找等数据操作。 它还有助于使用Query接口执行查询。

  • Persistence unit (persistence.xml) - 持久性单元描述持久性机制的属性。

  • Data Source (*ds.xml) - 数据源描述与数据存储相关的属性,如连接URL。 用户名,密码等

为了演示EJB持久性机制,我们需要执行以下任务 -

  • Step 1 - 在数据库中创建表。

  • Step 2 - 创建与表对应的实体类。

  • Step 3 - 创建数据源和持久性单元。

  • Step 4 - 创建具有EntityManager实例的无状态EJB。

  • Step 5 - 更新无状态EJB。 添加方法以通过实体管理器添加记录并从数据库中获取记录。

  • Step 6 - 基于控制台的应用程序客户端将访问无状态EJB以在数据库中保留数据。

Create Table

在默认数据库postgres创建一个表。

CREATE TABLE books (
   id     integer PRIMARY KEY,
   name   varchar(50)
);

创建实体类

//mark it entity using Entity annotation 
//map table name using Table annotation
@Entity
@Table(name="books")
public class Book implements Serializable{
   private int id;
   private String name;
   public Book(){        
   }
   //mark id as primary key with autogenerated value
   //map database column id with id field
   @Id
   @GeneratedValue(strategy= GenerationType.IDENTITY)
   @Column(name="id")
   public int getId() {
      return id;
   }
   ...
}

创建数据源和持久性单元

DataSource (jboss-ds.xml)

<?xml version = "1.0" encoding = "UTF-8"?>
<datasources>
   <local-tx-datasource>
      <jndi-name>PostgresDS</jndi-name>
      <connection-url>jdbc:postgresql://localhost:5432/postgres</connection-url>
      <driver-class>org.postgresql.driver</driver-class>
      <user-name>sa</user-name>
      <password>sa</password>
      <min-pool-size>5</min-pool-size>
      <max-pool-size>20</max-pool-size>
      <idle-timeout-minutes>5</idle-timeout-minutes>
   </local-tx-datasource>
</datasources>

Persistence Unit (persistence.xml)

<persistence version = "1.0" xmlns = "http://java.sun.com/xml/ns/persistence" xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd">
   <persistence-unit name = "EjbComponentPU" transaction-type = "JTA">
      <jta-data-source>java:/PostgresDS</jta-data-source>
      <exclude-unlisted-classes>false</exclude-unlisted-classes>
      <properties/>
   </persistence-unit>
   <persistence-unit name = "EjbComponentPU2" transaction-type = "JTA">
      <provider>org.hibernate.ejb.HibernatePersistence</provider>
      <jta-data-source>java:/PostgresDS</jta-data-source>
      <exclude-unlisted-classes>false</exclude-unlisted-classes>
      <properties>
         <property name="hibernate.hbm2ddl.auto" value="update"/>
      </properties>
   </persistence-unit>
</persistence>

创建具有EntityManager实例的无状态EJB

@Stateless
public class LibraryPersistentBean implements LibraryPersistentBeanRemote {
   //pass persistence unit to entityManager.
   @PersistenceContext(unitName="EjbComponentPU")
   private EntityManager entityManager;         
   public void addBook(Book book) {
      entityManager.persist(book);
   }    
   public List<Book> getBooks() {        
      return entityManager.createQuery("From Books").getResultList();
   }
   ...
}

在构建EJB模块之后,我们需要一个客户端来访问无状态bean,我们将在下一节中创建它。

例子 Example Application

让我们创建一个测试EJB应用程序来测试EJB持久性机制。

描述
1EJB - Create Application章节中解释,在com.iowiki.entity包下创建一个名为EjbComponent的项目。 您还可以使用在EJB - Create Application的项目EJB - Create Application章节,以便本章了解EJB持久性概念。
2Book.java包下创建Book.java com.iowiki.entity如下所示进行修改。
3 按照EJB - Create Application章节中的说明创建LibraryPersistentBean.javaLibraryPersistentBeanRemote ,并按如下所示进行修改。
4EjbComponent > setup文件夹中创建jboss-ds.xml ,在EjbComponent > src > conf文件夹中创建persistence.xml 。 这些文件夹可以在Netbeans的文件选项卡中看到。 修改这些文件,如上所示。
5 清理并构建应用程序以确保业务逻辑按照要求运行。
6 最后,在JBoss Application Server上以jar文件的形式部署应用程序。 如果JBoss Application服务器尚未启动,它将自动启动。
7 现在创建EJB客户端,一个基于控制台的应用程序,其方式与EJB - Create Application章节中主题Create Client to access EJB 。 修改它,如下所示。

EJBComponent (EJB Module)

Book.java

package com.iowiki.entity;
import java.io.Serializable;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.EntityListeners;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
@Entity
@Table(name="books")
public class Book implements Serializable{
   private int id;
   private String name;
   public Book(){        
   }
   @Id
   @GeneratedValue(strategy= GenerationType.IDENTITY)
   @Column(name="id")
   public int getId() {
      return id;
   }
   public void setId(int id) {
      this.id = id;
   }
   public String getName() {
      return name;
   }
   public void setName(String name) {
      this.name = name;
   }    
}

LibraryPersistentBeanRemote.java

package com.iowiki.stateless;
import com.iowiki.entity.Book;
import java.util.List;
import javax.ejb.Remote;
@Remote
public interface LibraryPersistentBeanRemote {
   void addBook(Book bookName);
   List<Book> getBooks();
}

LibraryPersistentBean.java

package com.iowiki.stateless;
import com.iowiki.entity.Book;
import java.util.List;
import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
@Stateless
public class LibraryPersistentBean implements LibraryPersistentBeanRemote {
   public LibraryPersistentBean(){
   }
   @PersistenceContext(unitName="EjbComponentPU")
   private EntityManager entityManager;         
   public void addBook(Book book) {
      entityManager.persist(book);
   }    
   public List<Book> getBooks() {
      return entityManager.createQuery("From Book").getResultList();
   }
}
  • 只要在JBOSS上部署EjbComponent项目,请注意jboss日志。

  • JBoss已自动为会话bean创建了一个JNDI条目 - LibraryPersistentBean/remote

  • 我们将使用此查找字符串来获取类型的远程业务对象 - com.iowiki.stateless.LibraryPersistentBeanRemote

JBoss应用服务器日志输出

...
16:30:01,401 INFO  [JndiSessionRegistrarBase] Binding the following Entries in Global JNDI:
   LibraryPersistentBean/remote - EJB3.x Default Remote Business Interface
   LibraryPersistentBean/remote-com.iowiki.stateless.LibraryPersistentBeanRemote - EJB3.x Remote Business Interface
16:30:02,723 INFO  [SessionSpecContainer] Starting jboss.j2ee:jar=EjbComponent.jar,name=LibraryPersistentBeanRemote,service=EJB3
16:30:02,723 INFO  [EJBContainer] STARTED EJB: com.iowiki.stateless.LibraryPersistentBeanRemote ejbName: LibraryPersistentBean
16:30:02,731 INFO  [JndiSessionRegistrarBase] Binding the following Entries in Global JNDI:
   LibraryPersistentBean/remote - EJB3.x Default Remote Business Interface
   LibraryPersistentBean/remote-com.iowiki.stateless.LibraryPersistentBeanRemote - EJB3.x Remote Business Interface
...   

EJBTester (EJB Client)

jndi.properties

java.naming.factory.initial=org.jnp.interfaces.NamingContextFactory
java.naming.factory.url.pkgs=org.jboss.naming:org.jnp.interfaces
java.naming.provider.url=localhost
  • 这些属性用于初始化java命名服务的InitialContext对象。

  • InitialContext对象将用于查找无状态会话bean。

EJBTester.java

package com.iowiki.test;
import com.iowiki.stateless.LibraryPersistentBeanRemote;
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.List;
import java.util.Properties;
import javax.naming.InitialContext;
import javax.naming.NamingException;
public class EJBTester {
   BufferedReader brConsoleReader = null; 
   Properties props;
   InitialContext ctx;
   {
      props = new Properties();
      try {
         props.load(new FileInputStream("jndi.properties"));
      } catch (IOException ex) {
         ex.printStackTrace();
      }
      try {
         ctx = new InitialContext(props);            
      } catch (NamingException ex) {
         ex.printStackTrace();
      }
      brConsoleReader = 
      new BufferedReader(new InputStreamReader(System.in));
   }
   public static void main(String[] args) {
      EJBTester ejbTester = new EJBTester();
      ejbTester.testEntityEjb();
   }
   private void showGUI(){
      System.out.println("**********************");
      System.out.println("Welcome to Book Store");
      System.out.println("**********************");
      System.out.print("Options \n1. Add Book\n2. Exit \nEnter Choice: ");
   }
   private void testEntityEjb(){
      try {
         int choice = 1; 
         LibraryPersistentBeanRemote libraryBean =
         LibraryPersistentBeanRemote)ctx.lookup("LibraryPersistentBean/remote");
         while (choice != 2) {
            String bookName;
            showGUI();
            String strChoice = brConsoleReader.readLine();
            choice = Integer.parseInt(strChoice);
            if (choice == 1) {
               System.out.print("Enter book name: ");
               bookName = brConsoleReader.readLine();
               Book book = new Book();
               book.setName(bookName);
               libraryBean.addBook(book);          
            } else if (choice == 2) {
               break;
            }
         }
         List<Book> booksList = libraryBean.getBooks();
         System.out.println("Book(s) entered so far: " + booksList.size());
         int i = 0;
         for (Book book:booksList) {
            System.out.println((i+1)+". " + book.getName());
            i++;
         }           
      } catch (Exception e) {
         System.out.println(e.getMessage());
         e.printStackTrace();
      }finally {
         try {
            if(brConsoleReader !=null){
               brConsoleReader.close();
            }
         } catch (IOException ex) {
            System.out.println(ex.getMessage());
         }
      }
   }
}

EJBTester执行以下任务。

  • 从jndi.properties加载属性并初始化InitialContext对象。

  • 在testStatefulEjb()方法中,使用name - “LibraryStatefulSessionBean/remote”完成jndi查找以获取远程业务对象(有状态ejb)。

  • 然后向用户显示库存储用户界面,并要求他/她输入选择。

  • 如果用户输入1,系统将询问书名并使用无状态会话bean addBook()方法保存书籍。 会话Bean通过EntityManager调用将数据库保存在数据库中。

  • 如果用户输入2,系统将使用有状态会话bean getBooks()方法检索书籍并退出。

  • 然后使用名称“LibraryStatelessSessionBean/remote”完成另一个jndi查找,以再次获取远程业务对象(无状态EJB)并完成书籍列表。

运行客户端以访问EJB

在项目资源管理器中找到EJBTester.java。 右键单击EJBTester类并选择run file

在Netbeans控制台中验证以下输出 -

run:
**********************
Welcome to Book Store
**********************
Options 
1. Add Book
2. Exit 
Enter Choice: 1
Enter book name: Learn Java
**********************
Welcome to Book Store
**********************
Options 
1. Add Book
2. Exit 
Enter Choice: 2
Book(s) entered so far: 1
1. learn java
BUILD SUCCESSFUL (total time: 15 seconds)

再次运行客户端以访问EJB

在访问EJB之前重新启动JBoss。

在项目资源管理器中找到EJBTester.java。 右键单击EJBTester类并选择run file

在Netbeans控制台中验证以下输出。

run:
**********************
Welcome to Book Store
**********************
Options 
1. Add Book
2. Exit 
Enter Choice: 1
Enter book name: Learn Spring
**********************
Welcome to Book Store
**********************
Options 
1. Add Book
2. Exit 
Enter Choice: 2
Book(s) entered so far: 2
1. learn java
2. Learn Spring
BUILD SUCCESSFUL (total time: 15 seconds)

上面显示的输出表明书籍存储在持久存储中并从数据库中检索。

EJB - Message Driven Beans

消息驱动Bean是一种企业bean,当EJB容器从队列或主题接收消息时由EJB容器调用。 消息驱动的bean是一个无状态bean,用于异步执行任务。

为了演示消息驱动bean的使用,我们将使用EJB-persistence章节,我们需要执行以下任务 -

  • Step 1 - 在数据库中创建表(请参阅EJB-Persistence章节)。

  • Step 2 - 创建与表对应的实体类(请参阅EJB-Persistence章节)。

  • Step 3 - 创建数据源和持久性单元(请参阅EJB-Persistence章节)。

  • Step 4 - 创建具有EntityManager实例的无状态EJB(请参阅EJB-Persistence章节)。

  • Step 5 - 更新无状态ejb.Add方法以通过实体管理器添加记录并从数据库获取记录(请参阅EJB-Persistence章节)。

  • Step 6 - 在JBoss default应用程序目录中创建一个名为BookQueue的队列。

  • Step 7 - 基于控制台的应用程序客户端将向此队列发送消息。

  • Step 8 - 创建一个消息驱动的bean,它将使用无状态bean来持久保存客户端数据。

  • Step 9 - jboss的EJB容器将调用上面的消息驱动bean并将其传递给客户端将发送到的消息。

创建队列

如果《JBoss Installation Folder》 》 server 》 default 》 deploy文件《JBoss Installation Folder》 》 server 》 default 》 deploy不存在,则创建名为jbossmq-destinations-service.xml的文件。

这里我们创建一个名为BookQueue的队列 -

的JBossMQ - 目的地 - service.xml中

<mbean code="org.jboss.mq.server.jmx.Queue"  
   name="jboss.mq.destination:service=Queue,name=BookQueue">  
   <depends optional-attribute-name="DestinationManager">
      jboss.mq:service=DestinationManager
   </depends>  
</mbean>  

当你启动JBoss时,你会在jboss日志中看到类似的条目。

...
10:37:06,167 INFO  [QueueService] Queue[/queue/BookQueue] started, fullSize=200000, pageSize=2000, downCacheSize=2000
...

创建消息驱动Bean

@MessageDriven(
   name = "BookMessageHandler",
   activationConfig = {
      @ActivationConfigProperty( propertyName = "destinationType", 
                                 propertyValue = "javax.jms.Queue"),
      @ActivationConfigProperty( propertyName = "destination", 
                                 propertyValue ="/queue/BookQueue")
   }
)
public class LibraryMessageBean implements MessageListener {
   @Resource
   private MessageDrivenContext mdctx;  
   @EJB
   LibraryPersistentBeanRemote libraryBean;
   public LibraryMessageBean(){        
   }
   public void onMessage(Message message) {
   }
}
  • LibraryMessageBean使用@MessageDriven批注进行批注,以将其标记为消息驱动bean。

  • 其属性定义为destinationType - Queue和destination - /queue/BookQueue。

  • 它实现了MessageListener接口,它公开了onMessage方法。

  • 它有MessgeDrivenContext作为资源。

  • 为了持久性目的,在此bean中注入了LibraryPersistentBeanRemote无状态bean。

构建EjbComponent项目并将其部署在JBoss上。 在构建和部署EJB模块之后,我们需要一个客户端向jboss队列发送消息。

例子 Example Application

让我们创建一个测试EJB应用程序来测试Message Driven Bean。

描述
1EJB - Create Application章节中解释,在com.iowiki.entity包下创建一个名为EjbComponent的项目。 您还可以使用在EJB - Create Application的项目EJB - Create Application章节,以便本章了解EJB持久性概念。
2EJB-Persistence章节中创建的包Book.java下创建Book.java
3 创建在EJB-Persistence章节中创建的LibraryPersistentBean.javaLibraryPersistentBeanRemote
4EjbComponent > setup文件夹中创建jboss-ds.xml ,在EjbComponent > src > conf文件夹中创建persistence.xml 。 这些文件夹可以在EJB-Persistence章节中创建的Netbeans文件选项卡中看到。
5com.iowiki.messagebean包下创建LibraryMessageBean.java com.iowiki.messagebean如下所示进行修改。
6 BookQueue在Jboss中创建BookQueue队列。
7 清理并构建应用程序以确保业务逻辑按照要求运行。
8 最后,在JBoss Application Server上以jar文件的形式部署应用程序。 如果JBoss Application服务器尚未启动,它将自动启动。
9 现在创建EJB客户端,一个基于控制台的应用程序,其方式与EJB - Create Application章节中主题Create Client to access EJB 。 修改它,如下所示。

EJBComponent (EJB Module)

LibraryMessageBean.java

package com.iowiki.messagebean;
import com.iowiki.entity.Book;
import com.iowiki.stateless.LibraryPersistentBeanRemote;
import javax.annotation.Resource;
import javax.ejb.ActivationConfigProperty;
import javax.ejb.EJB;
import javax.ejb.MessageDriven;
import javax.ejb.MessageDrivenContext;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.MessageListener;
import javax.jms.ObjectMessage;
@MessageDriven(
   name = "BookMessageHandler",
   activationConfig = {
      @ActivationConfigProperty( propertyName = "destinationType", 
                                 propertyValue = "javax.jms.Queue"),
      @ActivationConfigProperty( propertyName = "destination", 
                                 propertyValue ="/queue/BookQueue")
   }
)
public class LibraryMessageBean implements MessageListener {
   @Resource
   private MessageDrivenContext mdctx;  
   @EJB
   LibraryPersistentBeanRemote libraryBean;
   public LibraryMessageBean(){        
   }
   public void onMessage(Message message) {
      ObjectMessage objectMessage = null;
      try {
         objectMessage = (ObjectMessage) message;
         Book book = (Book) objectMessage.getObject(); 
         libraryBean.addBook(book);
      } catch (JMSException ex) {
         mdctx.setRollbackOnly();
      }       
   }   
}

EJBTester (EJB Client)

EJBTester.java

package com.iowiki.test;
import com.iowiki.entity.Book;
import com.iowiki.stateless.LibraryPersistentBeanRemote;
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.List;
import java.util.Properties;
import javax.jms.ObjectMessage;
import javax.jms.Queue;
import javax.jms.QueueConnection;
import javax.jms.QueueConnectionFactory;
import javax.jms.QueueSender;
import javax.jms.QueueSession;
import javax.naming.InitialContext;
import javax.naming.NamingException;
public class EJBTester {
   BufferedReader brConsoleReader = null; 
   Properties props;
   InitialContext ctx;
   {
      props = new Properties();
      try {
         props.load(new FileInputStream("jndi.properties"));
      } catch (IOException ex) {
         ex.printStackTrace();
      }
      try {
         ctx = new InitialContext(props);            
      } catch (NamingException ex) {
         ex.printStackTrace();
      }
      brConsoleReader = 
      new BufferedReader(new InputStreamReader(System.in));
   }
   public static void main(String[] args) {
      EJBTester ejbTester = new EJBTester();
      ejbTester.testMessageBeanEjb();
   }
   private void showGUI(){
      System.out.println("**********************");
      System.out.println("Welcome to Book Store");
      System.out.println("**********************");
      System.out.print("Options \n1. Add Book\n2. Exit \nEnter Choice: ");
   }
   private void testMessageBeanEjb(){
      try {
         int choice = 1; 
         Queue queue = (Queue) ctx.lookup("/queue/BookQueue");
         QueueConnectionFactory factory =
         (QueueConnectionFactory) ctx.lookup("ConnectionFactory");
         QueueConnection connection =  factory.createQueueConnection();
         QueueSession session = 
         connection.createQueueSession(false, QueueSession.AUTO_ACKNOWLEDGE);
         QueueSender sender = session.createSender(queue);
         while (choice != 2) {
            String bookName;
            showGUI();
            String strChoice = brConsoleReader.readLine();
            choice = Integer.parseInt(strChoice);
            if (choice == 1) {
               System.out.print("Enter book name: ");
               bookName = brConsoleReader.readLine();
               Book book = new Book();
               book.setName(bookName);
               ObjectMessage objectMessage = 
                  session.createObjectMessage(book);
               sender.send(objectMessage); 
            } else if (choice == 2) {
               break;
            }
         }
         LibraryPersistentBeanRemote libraryBean = 
         (LibraryPersistentBeanRemote)
         ctx.lookup("LibraryPersistentBean/remote");
         List<Book> booksList = libraryBean.getBooks();
         System.out.println("Book(s) entered so far: " + booksList.size());
         int i = 0;
         for (Book book:booksList) {
            System.out.println((i+1)+". " + book.getName());
            i++;
         }           
      } catch (Exception e) {
         System.out.println(e.getMessage());
         e.printStackTrace();
      }finally {
         try {
            if(brConsoleReader !=null){
               brConsoleReader.close();
            }
         } catch (IOException ex) {
            System.out.println(ex.getMessage());
         }
      }
   }   
}

EJBTester执行以下任务 -

  • 从jndi.properties加载属性并初始化InitialContext对象。

  • 在testStatefulEjb()方法中,使用名称“/ queue/BookQueue”完成jndi查找,以获取Jboss中可用队列的干扰。 然后使用队列会话创建发件人。

  • 然后向用户显示库存储用户界面,并要求他/她输入选择。

  • 如果用户输入1,系统将要求输入书名,发件人将书名发送到队列。 当JBoss容器在队列中收到此消息时,它会调用消息驱动bean的onMessage方法。 我们的消息驱动bean然后使用有状态会话bean addBook()方法保存书。 会话Bean通过EntityManager调用将数据库保存在数据库中。

  • 如果用户输入2,则使用名称“LibraryStatefulSessionBean/remote”完成另一个jndi查找,以再次获取远程业务对象(有状态EJB)并完成书籍列表。

运行客户端以访问EJB

在项目资源管理器中找到EJBTester.java。 右键单击EJBTester类并选择run file

在Netbeans控制台中验证以下输出 -

run:
**********************
Welcome to Book Store
**********************
Options 
1. Add Book
2. Exit 
Enter Choice: 1
Enter book name: Learn EJB
**********************
Welcome to Book Store
**********************
Options 
1. Add Book
2. Exit 
Enter Choice: 2
Book(s) entered so far: 2
1. learn java
1. learn EJB
BUILD SUCCESSFUL (total time: 15 seconds)

上面显示的输出表明我们的消息驱动bean正在接收消息并将该书存储在持久存储中,并从数据库中检索书籍。

EJB - Annotations

Java 5.0中引入了注释。 注释的目的是在类中附加其他信息或在其源代码中附加类的元数据。 在EJB 3.0中,注释用于描述EJB类中的配置元数据。 通过这种方式,EJB 3.0消除了在配置XML文件中描述配置数据的需要。

EJB容器使用编译器工具通过读取这些注释来生成所需的工件,如接口,部署描述符。 以下是常用注释的列表。

Sr.no 名称 描述
1

javax.ejb.Stateless

指定给定的EJB类是无状态会话Bean。

Attributes

  • name - 用于指定会话bean的名称。

  • mappedName - 用于指定会话bean的JNDI名称。

  • description - 用于提供会话bean的描述。

2

javax.ejb.Stateful

指定给定的EJB类是有状态会话Bean。

Attributes

  • name - 用于指定会话bean的名称。

  • mappedName - 用于指定会话bean的JNDI名称。

  • description - 用于提供会话bean的描述。

3

javax.ejb.MessageDrivenBean

指定给定的EJB类是消息驱动的bean。

Attributes

  • name - 用于指定消息驱动Bean的名称。

  • messageListenerInterface - 用于为消息驱动Bean指定消息侦听器接口。

  • activationConfig - 用于在消息驱动Bean的操作环境中指定消息驱动Bean的配置详细信息。

  • mappedName - 用于指定会话bean的JNDI名称。

  • description - 用于提供会话bean的描述。

4

javax.ejb.EJB

用于将依赖项指定或注入到另一个EJB中作为EJB实例。

Attributes

  • name - 用于指定name,该名称将用于在环境中查找引用的bean。

  • beanInterface - 用于指定引用bean的接口类型。

  • beanName - 用于提供引用bean的名称。

  • mappedName - 用于指定引用bean的JNDI名称。

  • description - 用于提供引用bean的描述。

5

javax.ejb.Local

用于指定会话bean的本地接口。 此本地接口声明会话bean的业务方法(可以是无状态或有状态的)。

此接口用于将业务方法公开给本地客户端,本地客户端在与EJB相同的部署/应用程序中运行。

Attributes

  • value - 用于将本地接口列表指定为接口数组。

6

javax.ejb.Remote

用于指定会话bean的远程接口。 此远程接口说明会话bean的业务方法(可以是无状态或有状态的)。

此接口用于将业务方法公开给远程客户端,这些客户端作为EJB在不同的部署/应用程序中运行。

Attributes

  • value - 用于将远程接口列表指定为接口数组。

7

javax.ejb.Activation ConfigProperty

用于指定消息驱动Bean所需的属性。 例如,终点,目的地,消息选择器等。

此批注作为参数传递给javax.ejb.MessageDrivenBean批注的activationConfig属性。

Attributes

  • propertyName - propertyName名称。

  • propertyValue - propertyValue值。

8

javax.ejb.PostActivate

用于指定EJB生命周期的回调方法。 当EJB容器刚刚激活/重新激活bean实例时,将调用此方法。

此接口用于将业务方法公开给本地客户端,本地客户端在与EJB相同的部署/应用程序中运行。

EJB - Callbacks

回调是一种机制,通过该机制可以拦截企业bean的生命周期。 EJB 3.0规范已指定了为其创建回调处理程序方法的回调。 EJB容器调用这些回调。 我们可以在EJB类本身或单独的类中定义回调方法。 EJB 3.0为回调提供了许多注释。

以下是无状态bean的回调注释列表 -

注解 描述
@PostConstruct 第一次创建bean时调用。
@PreDestroy 从bean池中删除bean或将其销毁时调用。

以下是有状态bean的回调注释列表 -

注解 描述
@PostConstruct 第一次创建bean时调用。
@PreDestroy 从bean池中删除bean或将其销毁时调用。
@PostActivate 加载bean以进行使用时调用。
@PrePassivate 将bean放回bean池时调用。

以下是消息驱动bean的回调注释列表 -

注解 描述
@PostConstruct 第一次创建bean时调用。
@PreDestroy 从bean池中删除bean或将其销毁时调用。

以下是实体bean的回调注释列表 -

注解 描述
@PrePersist 在数据库中创建实体时调用。
@PostPersist 在数据库中创建实体后调用。
@PreRemove 从数据库中删除实体时调用。
@PostRemove 从数据库中删除实体后调用。
@PreUpdate 在数据库中更新实体之前调用。
@PostLoad 从数据库中提取记录并加载到实体中时调用。

例子 Example Application

让我们创建一个测试EJB应用程序来测试EJB中的各种回调。

描述
1EJB - Create Application章节中解释,在com.iowiki.stateless包下创建一个名为EjbComponent的项目。 您还可以使用在EJB - Persistence章节中创建的项目,如本章所述,向EJB添加各种回调。
2 按照EJB - Create Application章节中的说明创建LibrarySessionBean.javaLibrarySessionBeanRemote 。 保持其余文件不变。
3 使用在EJB - Persistence章节中创建的Bean。 添加回调方法,如下所示。 保持其余文件不变。
4 在包com.iowiki.callback下创建一个java类com.iowiki.callback 。 该类将演示回调方法的分离。
5 清理并构建应用程序以确保业务逻辑按照要求运行。
6 最后,在JBoss Application Server上以jar文件的形式部署应用程序。 如果JBoss Application服务器尚未启动,它将自动启动。
7 现在创建EJB客户端,一个基于控制台的应用程序,其方式与EJB - Create Application章节中主题Create Client to access EJB

EJBComponent (EJB Module)

BookCallbackListener.java

package com.iowiki.callback;
import javax.persistence.PrePersist;
import javax.persistence.PostLoad;
import javax.persistence.PostPersist;
import javax.persistence.PostRemove;
import javax.persistence.PostUpdate;
import javax.persistence.PreRemove;
import javax.persistence.PreUpdate;
import com.iowiki.entity.Book;
public class BookCallbackListener {
   @PrePersist
   public void prePersist(Book book){
      System.out.println("BookCallbackListener.prePersist:" 
         + "Book to be created with book id: "+book.getId());
   }
   @PostPersist
   public void postPersist(Object book){
      System.out.println("BookCallbackListener.postPersist::"
         + "Book created with book id: "+((Book)book).getId());
   }
   @PreRemove
   public void preRemove(Book book){
      System.out.println("BookCallbackListener.preRemove:"
         + " About to delete Book: " + book.getId());
   }
   @PostRemove
   public void postRemove(Book book){
      System.out.println("BookCallbackListener.postRemove::"
         + " Deleted Book: " + book.getId());
   }
   @PreUpdate
   public void preUpdate(Book book){
      System.out.println("BookCallbackListener.preUpdate::"
         + " About to update Book: " + book.getId());
   }
   @PostUpdate
   public void postUpdate(Book book){
      System.out.println("BookCallbackListener.postUpdate::"
         + " Updated Book: " + book.getId());
   }
   @PostLoad
   public void postLoad(Book book){
      System.out.println("BookCallbackListener.postLoad::"
         + " Loaded Book: " + book.getId());
   }
}

Book.java

package com.iowiki.entity;
import java.io.Serializable;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.EntityListeners;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
@Entity
@Table(name="books")
public class Book implements Serializable{
   private int id;
   private String name;
   public Book(){        
   }
   @Id
   @GeneratedValue(strategy= GenerationType.IDENTITY)
   @Column(name="id")
   public int getId() {
      return id;
   }
   public void setId(int id) {
      this.id = id;
   }
   public String getName() {
      return name;
   }
   public void setName(String name) {
      this.name = name;
   }    
}

LibraryStatefulSessionBean.java

package com.iowiki.stateful;
import java.util.ArrayList;
import java.util.List;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.ejb.PostActivate;
import javax.ejb.PrePassivate;
import javax.ejb.Stateful;
@Stateful
public class LibraryStatefulSessionBean 
   implements LibraryStatefulSessionBeanRemote {
   List<String> bookShelf;    
   public LibraryStatefulSessionBean(){
      bookShelf = new ArrayList<String>();
   }
   public void addBook(String bookName) {
      bookShelf.add(bookName);
   }    
   public List<String> getBooks() {
      return bookShelf;
   }
   @PostConstruct
   public void postConstruct(){
      System.out.println("LibraryStatefulSessionBean.postConstruct::"
         + " bean created.");
   }
   @PreDestroy
   public void preDestroy(){
      System.out.println("LibraryStatefulSessionBean.preDestroy:"
         + " bean removed.");
   }
   @PostActivate
   public void postActivate(){
      System.out.println("LibraryStatefulSessionBean.postActivate:"
         + " bean activated.");
   }
   @PrePassivate
   public void prePassivate(){
      System.out.println("LibraryStatefulSessionBean.prePassivate:"
         + " bean passivated.");
   }    
}

LibraryStatefulSessionBeanRemote.java

package com.iowiki.stateful;
import java.util.List;
import javax.ejb.Remote;
@Remote
public interface LibraryStatefulSessionBeanRemote {
   void addBook(String bookName);
   List getBooks();
}

LibraryPersistentBean.java

package com.iowiki.stateless;
import com.iowiki.entity.Book;
import java.util.List;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
@Stateless
public class LibraryPersistentBean 
   implements LibraryPersistentBeanRemote {
   public LibraryPersistentBean(){}
   @PersistenceContext(unitName="EntityEjbPU")
   private EntityManager entityManager;         
   public void addBook(Book book) {
      entityManager.persist(book);
   }    
   public List<Book> getBooks() {     
      return entityManager.createQuery("From Book")
         .getResultList();
   }
   @PostConstruct
   public void postConstruct(){
      System.out.println("postConstruct:: LibraryPersistentBean session bean"
         + " created with entity Manager object: ");
   }
   @PreDestroy
   public void preDestroy(){
      System.out.println("preDestroy: LibraryPersistentBean session"
      + " bean is removed ");
   }
}

LibraryPersistentBeanRemote.java

package com.iowiki.stateless;
import com.iowiki.entity.Book;
import java.util.List;
import javax.ejb.Remote;
@Remote
public interface LibraryPersistentBeanRemote {
   void addBook(Book bookName);
   List<Book> getBooks();
}
  • 只要在JBOSS上部署EjbComponent项目,请注意jboss日志。

  • JBoss已自动为会话bean创建了一个JNDI条目 - LibraryPersistentBean/remote

  • 我们将使用此查找字符串来获取类型的远程业务对象 - com.iowiki.stateless.LibraryPersistentBeanRemote

JBoss应用服务器日志输出

...
16:30:01,401 INFO  [JndiSessionRegistrarBase] Binding the following Entries in Global JNDI:
   LibraryPersistentBean/remote - EJB3.x Default Remote Business Interface
   LibraryPersistentBean/remote-com.iowiki.stateless.LibraryPersistentBeanRemote - EJB3.x Remote Business Interface
16:30:02,723 INFO  [SessionSpecContainer] Starting jboss.j2ee:jar=EjbComponent.jar,name=LibraryPersistentBean,service=EJB3
16:30:02,723 INFO  [EJBContainer] STARTED EJB: com.iowiki.stateless.LibrarySessionBeanRemote ejbName: LibraryPersistentBean
...   

EJBTester (EJB Client)

jndi.properties

java.naming.factory.initial=org.jnp.interfaces.NamingContextFactory
java.naming.factory.url.pkgs=org.jboss.naming:org.jnp.interfaces
java.naming.provider.url=localhost
  • 这些属性用于初始化java命名服务的InitialContext对象。

  • InitialContext对象将用于查找无状态会话bean。

EJBTester.java

package com.iowiki.test;
import com.iowiki.stateful.LibrarySessionBeanRemote;
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.List;
import java.util.Properties;
import javax.naming.InitialContext;
import javax.naming.NamingException;
public class EJBTester {
   BufferedReader brConsoleReader = null; 
   Properties props;
   InitialContext ctx;
   {
      props = new Properties();
      try {
         props.load(new FileInputStream("jndi.properties"));
      } catch (IOException ex) {
         ex.printStackTrace();
      }
      try {
         ctx = new InitialContext(props);            
      } catch (NamingException ex) {
         ex.printStackTrace();
      }
      brConsoleReader = 
      new BufferedReader(new InputStreamReader(System.in));
   }
   public static void main(String[] args) {
      EJBTester ejbTester = new EJBTester();
      ejbTester.testEntityEjb();
   }
   private void showGUI(){
      System.out.println("**********************");
      System.out.println("Welcome to Book Store");
      System.out.println("**********************");
      System.out.print("Options \n1. Add Book\n2. Exit \nEnter Choice: ");
   }
   private void testEntityEjb(){    
      try {
      int choice = 1; 
      LibraryPersistentBeanRemote libraryBean = 
      (LibraryPersistentBeanRemote)
      ctx.lookup("LibraryPersistentBean/remote");
      while (choice != 2) {
         String bookName;
         showGUI();
         String strChoice = brConsoleReader.readLine();
         choice = Integer.parseInt(strChoice);
         if (choice == 1) {
            System.out.print("Enter book name: ");
            bookName = brConsoleReader.readLine();
            Book book = new Book();
            book.setName(bookName);
            libraryBean.addBook(book);          
         } else if (choice == 2) {
            break;
         }
      }
      List<Book> booksList = libraryBean.getBooks();
      System.out.println("Book(s) entered so far: " + booksList.size());
      int i = 0;
      for (Book book:booksList) {
         System.out.println((i+1)+". " + book.getName());
         i++;
      }           
      } catch (Exception e) {
         System.out.println(e.getMessage());
         e.printStackTrace();
      }finally {
         try {
            if(brConsoleReader !=null){
               brConsoleReader.close();
            }
         } catch (IOException ex) {
            System.out.println(ex.getMessage());
         }
      }    
   }    
}

EJBTester执行以下任务 -

  • 从jndi.properties加载属性并初始化InitialContext对象。

  • 在testStatelessEjb()方法中,使用名称“LibrarySessionBean/remote”完成jndi查找以获取远程业务对象(无状态EJB)。

  • 然后向用户显示库存储用户界面,并要求他/她输入选项。

  • 如果用户输入1,系统将询问书名并使用无状态会话bean addBook()方法保存书籍。 会话Bean将书籍存储在数据库中。

  • 如果用户输入2,系统将使用无状态会话bean getBooks()方法检索书籍并退出。

运行客户端以访问EJB

在项目资源管理器中找到EJBTester.java。 右键单击EJBTester类并选择run file

在Netbeans控制台中验证以下输出。

run:
**********************
Welcome to Book Store
**********************
Options 
1. Add Book
2. Exit 
Enter Choice: 1
Enter book name: Learn Java
**********************
Welcome to Book Store
**********************
Options 
1. Add Book
2. Exit 
Enter Choice: 2
Book(s) entered so far: 1
1. Learn Java
BUILD SUCCESSFUL (total time: 13 seconds)

JBoss应用服务器日志输出

您可以在JBoss日志中找到以下回调条目

14:08:34,293 INFO  [STDOUT] postConstruct:: LibraryPersistentBean session bean created with entity Manager object
...
16:39:09,484 INFO  [STDOUT] BookCallbackListener.prePersist:: Book to be created with book id: 0
16:39:09,531 INFO  [STDOUT] BookCallbackListener.postPersist:: Book created with book id: 1
16:39:09,900 INFO  [STDOUT] BookCallbackListener.postLoad:: Loaded Book: 1
...

EJB - Timer Service

定时服务是一种可以构建预定应用程序的机制。 例如,每个月1日的工资单生成。 EJB 3.0规范指定了@Timeout注释,这有助于在无状态或消息驱动的bean中编写EJB服务。 EJB容器调用该方法,该方法由@Timeout注释。

EJB Timer Service是EJB容器提供的服务,它有助于创建计时器并在计时器到期时安排回调。

创建计时器的步骤

使用@Resource注释在bean中注入SessionContext -

@Stateless
public class TimerSessionBean {
   @Resource
   private SessionContext context;
   ...
}

使用SessionContext对象获取TimerService并创建计时器。 以毫秒为单位传递时间和消息。

public void createTimer(long duration) {
   context.getTimerService().createTimer(duration, "Hello World!");
}

使用计时器的步骤

将@Timeout注释用于方法。 返回类型应为void并传递Timer类型的参数。 我们在首次执行后取消定时器,否则它将在修复间隔后继续运行。

@Timeout
public void timeOutHandler(Timer timer){
   System.out.println("timeoutHandler : " + timer.getInfo());        
   timer.cancel();
}

例子 Example Application

让我们创建一个测试EJB应用程序来测试EJB中的Timer Service。

描述
1EJB - Create Application章节中解释,在com.iowiki.timer包下创建一个名为EjbComponent的项目。
2 按照EJB - Create Application章节中的说明创建TimerSessionBean.javaTimerSessionBeanRemote 。 保持其余文件不变。
3 清理并构建应用程序以确保业务逻辑按照要求运行。
4 最后,在JBoss Application Server上以jar文件的形式部署应用程序。 如果JBoss Application服务器尚未启动,它将自动启动。
5 现在创建EJB客户端,一个基于控制台的应用程序,其方式与EJB - Create Application章节中主题Create Client to access EJB

EJBComponent (EJB Module)

TimerSessionBean.java

package com.iowiki.timer;
import javax.annotation.Resource;
import javax.ejb.SessionContext;
import javax.ejb.Timer;
import javax.ejb.Stateless;
import javax.ejb.Timeout;
@Stateless
public class TimerSessionBean implements TimerSessionBeanRemote {
   @Resource
   private SessionContext context;
   public void createTimer(long duration) {
      context.getTimerService().createTimer(duration, "Hello World!");
   }
   @Timeout
   public void timeOutHandler(Timer timer){
      System.out.println("timeoutHandler : " + timer.getInfo());        
      timer.cancel();
   }
}

TimerSessionBeanRemote.java

package com.iowiki.timer;
import javax.ejb.Remote;
@Remote
public interface TimerSessionBeanRemote {
   public void createTimer(long milliseconds);
}
  • 只要在JBOSS上部署EjbComponent项目,请注意jboss日志。

  • JBoss已自动为会话bean创建了一个JNDI条目TimerSessionBean/remote

  • 我们将使用此查找字符串来获取类型的远程业务对象 - com.iowiki.timer.TimerSessionBeanRemote

JBoss应用服务器日志输出

...
16:30:01,401 INFO  [JndiSessionRegistrarBase] Binding the following Entries in Global JNDI:
   TimerSessionBean/remote - EJB3.x Default Remote Business Interface
   TimerSessionBean/remote-com.iowiki.timer.TimerSessionBeanRemote - EJB3.x Remote Business Interface
16:30:02,723 INFO  [SessionSpecContainer] Starting jboss.j2ee:jar=EjbComponent.jar,name=TimerSessionBean,service=EJB3
16:30:02,723 INFO  [EJBContainer] STARTED EJB: com.iowiki.timer.TimerSessionBeanRemote ejbName: TimerSessionBean
...   

EJBTester (EJB Client)

jndi.properties

java.naming.factory.initial=org.jnp.interfaces.NamingContextFactory
java.naming.factory.url.pkgs=org.jboss.naming:org.jnp.interfaces
java.naming.provider.url=localhost
  • 这些属性用于初始化java命名服务的InitialContext对象。

  • InitialContext对象将用于查找无状态会话bean。

EJBTester.java

package com.iowiki.test;
import com.iowiki.stateful.TimerSessionBeanRemote;
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.List;
import java.util.Properties;
import javax.naming.InitialContext;
import javax.naming.NamingException;
public class EJBTester {
   BufferedReader brConsoleReader = null; 
   Properties props;
   InitialContext ctx;
   {
      props = new Properties();
      try {
         props.load(new FileInputStream("jndi.properties"));
      } catch (IOException ex) {
         ex.printStackTrace();
      }
      try {
         ctx = new InitialContext(props);            
      } catch (NamingException ex) {
         ex.printStackTrace();
      }
      brConsoleReader = 
      new BufferedReader(new InputStreamReader(System.in));
   }
   public static void main(String[] args) {
      EJBTester ejbTester = new EJBTester();
      ejbTester.testTimerService();
   }
   private void showGUI(){
      System.out.println("**********************");
      System.out.println("Welcome to Book Store");
      System.out.println("**********************");
      System.out.print("Options \n1. Add Book\n2. Exit \nEnter Choice: ");
   }
   private void testTimerService(){
      try {
         TimerSessionBeanRemote timerServiceBean = (TimerSessionBeanRemote)ctx.lookup("TimerSessionBean/remote");
         System.out.println("["+(new Date()).toString()+ "]" + "timer created.");
         timerServiceBean.createTimer(2000);            
      } catch (NamingException ex) {
         ex.printStackTrace();
      }
   }
}

EJBTester正在执行以下任务。

  • 从jndi.properties加载属性并初始化InitialContext对象。

  • 在testTimerService()方法中,使用名称“TimerSessionBean/remote”完成jndi查找以获取远程业务对象(timer statelessless EJB)。

  • 然后调用createTimer作为调度时间传递2000毫秒。

  • EJB容器在2秒后调用timeoutHandler方法。

运行客户端以访问EJB

在项目资源管理器中找到EJBTester.java。 右键单击EJBTester类并选择run file

在Netbeans控制台中验证以下输出。

run:
[Wed Jun 19 11:35:47 IST 2013]timer created.
BUILD SUCCESSFUL (total time: 0 seconds)

JBoss应用服务器日志输出

您可以在JBoss日志中找到以下回调条目

...
11:35:49,555 INFO  [STDOUT] timeoutHandler : Hello World!
...

EJB - Dependency Injection

EJB 3.0规范提供了注释,可以应用于字段或setter方法以注入依赖项。 EJB容器使用全局JNDI注册表来定位依赖项。 以下注释在EJB 3.0中用于依赖注入。

  • @EJB - 用于注入其他EJB引用。

  • @Resource - 用于注入sessionContext,timerService等数据源或单例服务。

使用@EJB的步骤

@EJB可以按以下方式用于字段或方法 -

public class LibraryMessageBean implements MessageListener {
   //dependency injection on field. 
   @EJB
   LibraryPersistentBeanRemote libraryBean;
   ...
}
public class LibraryMessageBean implements MessageListener {
   LibraryPersistentBeanRemote libraryBean;
   //dependency injection on method. 
   @EJB(beanName="com.iowiki.stateless.LibraryPersistentBean")
   public void setLibraryPersistentBean(
   LibraryPersistentBeanRemote libraryBean)
   {
      this.libraryBean = libraryBean;
   }
   ...
}

使用@Resource的步骤

@Resource通常用于注入EJB容器提供的单例。

public class LibraryMessageBean implements MessageListener {
   @Resource
   private MessageDrivenContext mdctx;  
   ...
}

例子 Example Application

让我们创建一个测试EJB应用程序来测试EJB中的依赖注入服务。

描述
1EJB - Create Application章节中解释,在com.iowiki.timer包下创建一个名为EjbComponent的项目。
3 使用在EJB - Message Driven Bean章节中创建的EJB - Message Driven Bean 。 保持其余文件不变。
5 清理并构建应用程序以确保业务逻辑按照要求运行。
6 最后,在JBoss Application Server上以jar文件的形式部署应用程序。 如果JBoss Application服务器尚未启动,它将自动启动。
7 现在创建EJB客户端,一个基于控制台的应用程序,其方式与EJB - Create Application章节中主题Create Client to access EJB

EJBComponent (EJB Module)

LibraryMessageBean.java

package com.iowiki.messagebean;
import com.iowiki.entity.Book;
import com.iowiki.stateless.LibraryPersistentBeanRemote;
import javax.annotation.Resource;
import javax.ejb.ActivationConfigProperty;
import javax.ejb.EJB;
import javax.ejb.MessageDriven;
import javax.ejb.MessageDrivenContext;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.MessageListener;
import javax.jms.ObjectMessage;
@MessageDriven(
   name = "BookMessageHandler",
   activationConfig = {
      @ActivationConfigProperty( propertyName = "destinationType", 
                                 propertyValue = "javax.jms.Queue"),
      @ActivationConfigProperty( propertyName = "destination", 
                                 propertyValue ="/queue/BookQueue")
   }
)
public class LibraryMessageBean implements MessageListener {
   @Resource
   private MessageDrivenContext mdctx;  
   @EJB
   LibraryPersistentBeanRemote libraryBean;
   public LibraryMessageBean(){        
   }
   public void onMessage(Message message) {
      ObjectMessage objectMessage = null;
      try {
         objectMessage = (ObjectMessage) message;
         Book book = (Book) objectMessage.getObject(); 
         libraryBean.addBook(book);
      }catch (JMSException ex) {
         mdctx.setRollbackOnly();
      }       
   }   
}

EJBTester (EJB Client)

EJBTester.java

package com.iowiki.test;
import com.iowiki.entity.Book;
import com.iowiki.stateless.LibraryPersistentBeanRemote;
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.List;
import java.util.Properties;
import javax.jms.ObjectMessage;
import javax.jms.Queue;
import javax.jms.QueueConnection;
import javax.jms.QueueConnectionFactory;
import javax.jms.QueueSender;
import javax.jms.QueueSession;
import javax.naming.InitialContext;
import javax.naming.NamingException;
public class EJBTester {
   BufferedReader brConsoleReader = null; 
   Properties props;
   InitialContext ctx;
   {
      props = new Properties();
      try {
         props.load(new FileInputStream("jndi.properties"));
      } catch (IOException ex) {
         ex.printStackTrace();
      }
      try {
         ctx = new InitialContext(props);            
      } catch (NamingException ex) {
         ex.printStackTrace();
      }
      brConsoleReader = 
      new BufferedReader(new InputStreamReader(System.in));
   }
   public static void main(String[] args) {
      EJBTester ejbTester = new EJBTester();
      ejbTester.testMessageBeanEjb();
   }
   private void showGUI(){
      System.out.println("**********************");
      System.out.println("Welcome to Book Store");
      System.out.println("**********************");
      System.out.print("Options \n1. Add Book\n2. Exit \nEnter Choice: ");
   }
   private void testMessageBeanEjb(){
      try {
         int choice = 1; 
         Queue queue = (Queue) ctx.lookup("/queue/BookQueue");
         QueueConnectionFactory factory =
         (QueueConnectionFactory) ctx.lookup("ConnectionFactory");
         QueueConnection connection =  factory.createQueueConnection();
         QueueSession session = connection.createQueueSession( 
         false, QueueSession.AUTO_ACKNOWLEDGE);
         QueueSender sender = session.createSender(queue);
         while (choice != 2) {
            String bookName;
            showGUI();
            String strChoice = brConsoleReader.readLine();
            choice = Integer.parseInt(strChoice);
            if (choice == 1) {
               System.out.print("Enter book name: ");
               bookName = brConsoleReader.readLine();
               Book book = new Book();
               book.setName(bookName);
               ObjectMessage objectMessage = 
               session.createObjectMessage(book);
               sender.send(objectMessage); 
            } else if (choice == 2) {
               break;
            }
         }
         LibraryPersistentBeanRemote libraryBean = 
            (LibraryPersistentBeanRemote)
            ctx.lookup("LibraryPersistentBean/remote");
         List<Book> booksList = libraryBean.getBooks();
         System.out.println("Book(s) entered so far: " 
         + booksList.size());
         int i = 0;
         for (Book book:booksList) {
            System.out.println((i+1)+". " + book.getName());
            i++;
         }           
      } catch (Exception e) {
         System.out.println(e.getMessage());
         e.printStackTrace();
      }finally {
         try {
            if(brConsoleReader !=null){
               brConsoleReader.close();
            }
         } catch (IOException ex) {
            System.out.println(ex.getMessage());
         }
      }
   }   
}

EJBTester执行以下任务 -

  • 从jndi.properties加载属性并初始化InitialContext对象。

  • 在testStatefulEjb()方法中,使用名称“/ queue/BookQueue”完成jndi查找,以获取Jboss中可用队列的引用。 然后使用队列会话创建发件人。

  • 然后向用户显示库存储用户界面,并要求他/她输入选项。

  • 如果用户输入1,系统将要求输入书名,发件人将书名发送到队列。 当JBoss容器在队列中收到此消息时,它会调用消息驱动bean的onMessage方法。 我们的消息驱动bean然后使用有状态会话bean addBook()方法保存书。 会话Bean通过EntityManager调用将数据库保存在数据库中。

  • 如果用户输入2,则使用名称“LibraryStatefulSessionBean/remote”完成另一个jndi查找,以再次获取远程业务对象(有状态EJB)并完成书籍列表。

运行客户端以访问EJB

在项目资源管理器中找到EJBTester.java。 右键单击EJBTester类并选择run file

在Netbeans控制台中验证以下输出。

run:
**********************
Welcome to Book Store
**********************
Options 
1. Add Book
2. Exit 
Enter Choice: 1
Enter book name: Learn EJB
**********************
Welcome to Book Store
**********************
Options 
1. Add Book
2. Exit 
Enter Choice: 2
Book(s) entered so far: 2
1. learn java
1. learn EJB
BUILD SUCCESSFUL (total time: 15 seconds)
  • 上面显示的输出表明我们的消息驱动bean正在接收消息并将书存储在持久存储中,并从数据库中检索书籍。

  • 我们的消息驱动bean使用了使用@EJB注释注入其中的LibraryPersistentBean,并且在异常的情况下,MessageDrivenContext,object用于回滚事务。

EJB - Interceptors

EJB 3.0提供了使用@AroundInvoke批注注释的方法来拦截业务方法调用的规范。 在业务方法调用它被拦截之前,ejbContainer会调用一个拦截器方法。 以下是拦截器方法的示例签名

@AroundInvoke
public Object methodInterceptor(InvocationContext ctx) throws Exception{
   System.out.println("*** Intercepting call to LibraryBean method: " 
   + ctx.getMethod().getName());
   return ctx.proceed();
}

拦截器方法可以在三个级别应用或绑定。

  • Default - 为部署中的每个bean调用默认拦截器。默认拦截器只能通过xml(ejb-jar.xml)应用。

  • Class - 为bean的每个方法调用类级别拦截器。 可以通过via xml(ejb-jar.xml)的注释来应用类级拦截器。

  • Method - 为bean的特定方法调用方法级别拦截器。 方法级拦截器可以通过via xml(ejb-jar.xml)的注释来应用。

我们在这里讨论类级拦截器。

拦截器类

package com.iowiki.interceptor;
import javax.interceptor.AroundInvoke;
import javax.interceptor.InvocationContext;
public class BusinessInterceptor {
   @AroundInvoke
   public Object methodInterceptor(InvocationContext ctx) throws Exception{
      System.out.println("*** Intercepting call to LibraryBean method: " 
      + ctx.getMethod().getName());
      return ctx.proceed();
   }
}

远程接口

import javax.ejb.Remote;
@Remote
public interface LibraryBeanRemote {
   //add business method declarations
}

拦截无状态EJB

@Interceptors ({BusinessInterceptor.class})
@Stateless
public class LibraryBean implements LibraryBeanRemote {
   //implement business method 
}

例子 Example Application

让我们创建一个测试EJB应用程序来测试截获的无状态EJB。

描述
1EJB - Create Application章节中解释,在com.iowiki.interceptor包下创建一个名为EjbComponent的项目。 您还可以使用在EJB - Create Application的项目EJB - Create Application本章的EJB - Create Application章节来理解截获的EJB概念。
2EJB - Create Application章节中解释,在com.iowiki.interceptor包下创建LibraryBean.javaLibraryBeanRemote 。 保持其余文件不变。
3 清理并构建应用程序以确保业务逻辑按照要求运行。
4 最后,在JBoss Application Server上以jar文件的形式部署应用程序。 如果JBoss Application服务器尚未启动,它将自动启动。
5 现在创建ejb客户端,一个基于控制台的应用程序,其方式与在Create Client to access EJB主题Create Client to access EJB下的EJB - Create Application章节中所述的相同。

EJBComponent (EJB Module)

LibraryBeanRemote.java

package com.iowiki.interceptor;
import java.util.List;
import javax.ejb.Remote;
@Remote
public interface LibraryBeanRemote {
   void addBook(String bookName);
   List getBooks();
}

LibraryBean.java

package com.iowiki.interceptor;
import java.util.ArrayList;
import java.util.List;
import javax.ejb.Stateless;
import javax.interceptor.Interceptors;
@Interceptors ({BusinessInterceptor.class})
@Stateless
public class LibraryBean implements LibraryBeanRemote {
   List<String> bookShelf;    
   public LibraryBean(){
      bookShelf = new ArrayList<String>();
   }
   public void addBook(String bookName) {
      bookShelf.add(bookName);
   }    
   public List<String> getBooks() {
      return bookShelf;
   }   
}
  • 只要在JBOSS上部署EjbComponent项目,请注意jboss日志。

  • JBoss已自动为会话bean创建了一个JNDI条目 - LibraryBean/remote

  • 我们将使用此查找字符串来获取类型的远程业务对象 - com.iowiki.interceptor.LibraryBeanRemote

JBoss应用服务器日志输出

...
16:30:01,401 INFO  [JndiSessionRegistrarBase] Binding the following Entries in Global JNDI:
   LibraryBean/remote - EJB3.x Default Remote Business Interface
   LibraryBean/remote-com.iowiki.interceptor.LibraryBeanRemote - EJB3.x Remote Business Interface
16:30:02,723 INFO  [SessionSpecContainer] Starting jboss.j2ee:jar=EjbComponent.jar,name=LibraryBean,service=EJB3
16:30:02,723 INFO  [EJBContainer] STARTED EJB: com.iowiki.interceptor.LibraryBeanRemote ejbName: LibraryBean
16:30:02,731 INFO  [JndiSessionRegistrarBase] Binding the following Entries in Global JNDI:
   LibraryBean/remote - EJB3.x Default Remote Business Interface
   LibraryBean/remote-com.iowiki.interceptor.LibraryBeanRemote - EJB3.x Remote Business Interface
...   

EJBTester (EJB Client)

jndi.properties

java.naming.factory.initial=org.jnp.interfaces.NamingContextFactory
java.naming.factory.url.pkgs=org.jboss.naming:org.jnp.interfaces
java.naming.provider.url=localhost
  • 这些属性用于初始化java命名服务的InitialContext对象。

  • InitialContext对象将用于查找无状态会话bean。

EJBTester.java

package com.iowiki.test;
import com.iowiki.stateful.LibraryBeanRemote;
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.List;
import java.util.Properties;
import javax.naming.InitialContext;
import javax.naming.NamingException;
public class EJBTester {
   BufferedReader brConsoleReader = null; 
   Properties props;
   InitialContext ctx;
   {
      props = new Properties();
      try {
         props.load(new FileInputStream("jndi.properties"));
      } catch (IOException ex) {
         ex.printStackTrace();
      }
      try {
         ctx = new InitialContext(props);            
      } catch (NamingException ex) {
         ex.printStackTrace();
      }
      brConsoleReader = 
      new BufferedReader(new InputStreamReader(System.in));
   }
   public static void main(String[] args) {
      EJBTester ejbTester = new EJBTester();
      ejbTester.testInterceptedEjb();
   }
   private void showGUI(){
      System.out.println("**********************");
      System.out.println("Welcome to Book Store");
      System.out.println("**********************");
      System.out.print("Options \n1. Add Book\n2. Exit \nEnter Choice: ");
   }
   private void testInterceptedEjb(){
      try {
         int choice = 1; 
         LibraryBeanRemote libraryBean =
         LibraryBeanRemote)ctx.lookup("LibraryBean/remote");
         while (choice != 2) {
            String bookName;
            showGUI();
            String strChoice = brConsoleReader.readLine();
            choice = Integer.parseInt(strChoice);
            if (choice == 1) {
               System.out.print("Enter book name: ");
               bookName = brConsoleReader.readLine();
               Book book = new Book();
               book.setName(bookName);
               libraryBean.addBook(book);          
            } else if (choice == 2) {
               break;
            }
         }
         List<Book> booksList = libraryBean.getBooks();
         System.out.println("Book(s) entered so far: " + booksList.size());
         int i = 0;
         for (Book book:booksList) {
            System.out.println((i+1)+". " + book.getName());
            i++;
         }                
      } catch (Exception e) {
         System.out.println(e.getMessage());
         e.printStackTrace();
      }finally {
         try {
            if(brConsoleReader !=null){
               brConsoleReader.close();
            }
         } catch (IOException ex) {
            System.out.println(ex.getMessage());
         }
      }
   }
}

EJBTester执行以下任务 -

  • 从jndi.properties加载属性并初始化InitialContext对象。

  • 在testInterceptedEjb()方法中,使用名称“LibraryBean/remote”完成jndi查找以获取远程业务对象(无状态EJB)。

  • 然后向用户显示库存储用户界面,并要求他/她输入选项。

  • 如果用户输入1,系统将询问书名并使用无状态会话bean addBook()方法保存书籍。 会话Bean将书存储在其实例变量中。

  • 如果用户输入2,系统将使用无状态会话bean getBooks()方法检索书籍并退出。

运行客户端以访问EJB

在项目资源管理器中找到EJBTester.java。 右键单击EJBTester类并选择run file

在Netbeans控制台中验证以下输出。

run:
**********************
Welcome to Book Store
**********************
Options 
1. Add Book
2. Exit 
Enter Choice: 1
Enter book name: Learn Java
**********************
Welcome to Book Store
**********************
Options 
1. Add Book
2. Exit 
Enter Choice: 2
Book(s) entered so far: 1
1. Learn Java
BUILD SUCCESSFUL (total time: 13 seconds)

JBoss应用服务器日志输出

验证JBoss应用程序服务器日志输出中的以下输出。

....
09:55:40,741 INFO  [STDOUT] *** Intercepting call to LibraryBean method: addBook
09:55:43,661 INFO  [STDOUT] *** Intercepting call to LibraryBean method: getBooks

EJB - Embeddable Objects

EJB 3.0提供了将JAVA POJO(Plain Old Java Object)嵌入到实体bean中的选项,并允许使用嵌入式POJO类的方法映射列名。 要嵌入的Java POJO必须注释为@Embeddable。

@Embeddable
public class Publisher implements Serializable{
   private String name;
   private String address;
   ...
}

可以使用@Embedded批注嵌入上述类。

@Entity
public class Book implements Serializable{
   private int id;
   private String name;
   private Publisher publisher;
   ...
   @Embedded
   @AttributeOverrides({
      @AttributeOverride(name = "name", 
                      column = @Column(name = "PUBLISHER")),
      @AttributeOverride(name = "address", 
                      column = @Column(name = "PUBLISHER_ADDRESS"))
   })
   public Publisher getPublisher() {
      return publisher;
   }
   ...
}

例子 Example Application

让我们创建一个测试EJB应用程序来测试EJB 3.0中的嵌入对象。

描述
1EJB - Create Application章节中解释,在com.iowiki.entity包下创建一个名为EjbComponent的项目。 请使用在EJB - Persistence章节中创建的项目本章来理解EJB概念中的嵌入对象。
2 按照EJB - Create Application章节中的说明,在com.iowiki.entity包下创建Publisher.java 。 保持其余文件不变。
3com.iowiki.entity包下创建com.iowiki.entity 。 使用EJB - Persistence章节作为参考。 保持其余文件不变。
4 清理并构建应用程序以确保业务逻辑按照要求运行。
5 最后,在JBoss Application Server上以jar文件的形式部署应用程序。 如果JBoss Application服务器尚未启动,它将自动启动。
6 现在创建EJB客户端,一个基于控制台的应用程序,其方式与EJB - Create Application章节中主题Create Client to access EJB

创建/更改书籍表

CREATE TABLE book (
   id     integer PRIMARY KEY,
   name   varchar(50)
);
Alter table book add publisher varchar(100);
Alter table book add publisher_address varchar(200);

EJBComponent (EJB Module)

Publisher.java

package com.iowiki.entity;
import java.io.Serializable;
import javax.persistence.Embeddable;
@Embeddable
public class Publisher implements Serializable{
   private String name;
   private String address;
   public Publisher(){}
   public Publisher(String name, String address){
      this.name = name;
      this.address = address;
   }
   public String getName() {
      return name;
   }
   public void setName(String name) {
      this.name = name;
   }
   public String getAddress() {
      return address;
   }
   public void setAddress(String address) {
      this.address = address;
   }
   public String toString(){
      return name + "," + address;
   }    
}

Book.java


package com.iowiki.entity;
import com.iowiki.callback.BookCallbackListener;
import java.io.Serializable;
import javax.persistence.AttributeOverride;
import javax.persistence.AttributeOverrides;
import javax.persistence.Column;
import javax.persistence.Embedded;
import javax.persistence.Entity;
import javax.persistence.EntityListeners;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
@Entity
@Table(name="book")
public class Book implements Serializable{
   private int id;
   private String name;
   private Publisher publisher;
   public Book(){        
   }
   @Id
   @GeneratedValue(strategy= GenerationType.IDENTITY)
   @Column(name="id")
   public int getId() {
      return id;
   }
   public void setId(int id) {
      this.id = id;
   }
   public String getName() {
      return name;
   }
   public void setName(String name) {
      this.name = name;
   }
   @Embedded
   @AttributeOverrides({
      @AttributeOverride(name = "name", 
         column = @Column(name = "PUBLISHER")),
      @AttributeOverride(name = "address", 
         column = @Column(name = "PUBLISHER_ADDRESS"))
   })
   public Publisher getPublisher() {
      return publisher;
   }
   public void setPublisher(Publisher publisher) {
      this.publisher = publisher;
   }    
}

LibraryPersistentBeanRemote.java

package com.iowiki.stateless;
import com.iowiki.entity.Book;
import java.util.List;
import javax.ejb.Remote;
@Remote
public interface LibraryPersistentBeanRemote {
   void addBook(Book bookName);
   List<Book> getBooks();
}

LibraryPersistentBean.java

package com.iowiki.stateless;
import com.iowiki.entity.Book;
import java.util.List;
import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
@Stateless
public class LibraryPersistentBean implements LibraryPersistentBeanRemote {
   public LibraryPersistentBean(){
   }
   @PersistenceContext(unitName="EjbComponentPU")
   private EntityManager entityManager;         
   public void addBook(Book book) {
      entityManager.persist(book);
   }    
   public List<Book> getBooks() {
      return entityManager.createQuery("From Book").getResultList();
   }
}
  • 只要在JBOSS上部署EjbComponent项目,请注意jboss日志。

  • JBoss已自动为会话bean创建了一个JNDI条目 - LibraryPersistentBean/remote

  • 我们将使用此查找字符串来获取类型的远程业务对象 - com.iowiki.interceptor.LibraryPersistentBeanRemote

JBoss应用服务器日志输出

...
16:30:01,401 INFO  [JndiSessionRegistrarBase] Binding the following Entries in Global JNDI:
   LibraryPersistentBean/remote - EJB3.x Default Remote Business Interface
   LibraryPersistentBean/remote-com.iowiki.interceptor.LibraryPersistentBeanRemote - EJB3.x Remote Business Interface
16:30:02,723 INFO  [SessionSpecContainer] Starting jboss.j2ee:jar=EjbComponent.jar,name=LibraryPersistentBean,service=EJB3
16:30:02,723 INFO  [EJBContainer] STARTED EJB: com.iowiki.interceptor.LibraryPersistentBeanRemote ejbName: LibraryPersistentBean
16:30:02,731 INFO  [JndiSessionRegistrarBase] Binding the following Entries in Global JNDI:
   LibraryPersistentBean/remote - EJB3.x Default Remote Business Interface
   LibraryPersistentBean/remote-com.iowiki.interceptor.LibraryPersistentBeanRemote - EJB3.x Remote Business Interface
...   

EJBTester (EJB Client)

jndi.properties

java.naming.factory.initial=org.jnp.interfaces.NamingContextFactory
java.naming.factory.url.pkgs=org.jboss.naming:org.jnp.interfaces
java.naming.provider.url=localhost
  • 这些属性用于初始化java命名服务的InitialContext对象。

  • InitialContext对象将用于查找无状态会话bean。

EJBTester.java

package com.iowiki.test;
import com.iowiki.stateful.LibraryBeanRemote;
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.List;
import java.util.Properties;
import javax.naming.InitialContext;
import javax.naming.NamingException;
public class EJBTester {
   BufferedReader brConsoleReader = null; 
   Properties props;
   InitialContext ctx;
   {
      props = new Properties();
      try {
         props.load(new FileInputStream("jndi.properties"));
      } catch (IOException ex) {
         ex.printStackTrace();
      }
      try {
         ctx = new InitialContext(props);            
      } catch (NamingException ex) {
         ex.printStackTrace();
      }
      brConsoleReader = 
      new BufferedReader(new InputStreamReader(System.in));
   }
   public static void main(String[] args) {
      EJBTester ejbTester = new EJBTester();
      ejbTester.testEmbeddedObjects();
   }
   private void showGUI(){
      System.out.println("**********************");
      System.out.println("Welcome to Book Store");
      System.out.println("**********************");
      System.out.print("Options \n1. Add Book\n2. Exit \nEnter Choice: ");
   }
   private void testEmbeddedObjects(){
      try {
         int choice = 1; 
         LibraryPersistentBeanRemote libraryBean = 
        (LibraryPersistentBeanRemote)
         ctx.lookup("LibraryPersistentBean/remote");
         while (choice != 2) {
            String bookName;
            String publisherName;
            String publisherAddress;
            showGUI();
            String strChoice = brConsoleReader.readLine();
            choice = Integer.parseInt(strChoice);
            if (choice == 1) {
               System.out.print("Enter book name: ");
               bookName = brConsoleReader.readLine();
               System.out.print("Enter publisher name: ");
               publisherName = brConsoleReader.readLine();
               System.out.print("Enter publisher address: ");
               publisherAddress = brConsoleReader.readLine();
               Book book = new Book();
               book.setName(bookName);
               book.setPublisher
              (new Publisher(publisherName,publisherAddress));
               libraryBean.addBook(book);          
            } else if (choice == 2) {
               break;
            }
         }
         List<Book> booksList = libraryBean.getBooks();
         System.out.println("Book(s) entered so far: " + booksList.size());
         int i = 0;
         for (Book book:booksList) {
            System.out.println((i+1)+". " + book.getName());
            System.out.println("Publication: "+book.getPublisher());
            i++;
         }           
      } catch (Exception e) {
         System.out.println(e.getMessage());
         e.printStackTrace();
      }finally {
         try {
            if(brConsoleReader !=null){
               brConsoleReader.close();
            }
         } catch (IOException ex) {
            System.out.println(ex.getMessage());
         }
      }
   }
}

EJBTester执行以下任务 -

  • 从jndi.properties加载属性并初始化InitialContext对象。

  • 在testInterceptedEjb()方法中,使用名称“LibraryPersistenceBean/remote”完成jndi查找以获取远程业务对象(无状态EJB)。

  • 然后向用户显示库存储用户界面,并要求他/她输入选项。

  • 如果用户输入1,系统将询问书名并使用无状态会话bean addBook()方法保存书籍。 会话Bean将书存储在数据库中。

  • 如果用户输入2,系统将使用无状态会话bean getBooks()方法检索书籍并退出。

运行客户端以访问EJB

在项目资源管理器中找到EJBTester.java。 右键单击EJBTester类并选择run file

在Netbeans控制台中验证以下输出。

run:
**********************
Welcome to Book Store
**********************
Options 
1. Add Book
2. Exit 
Enter Choice: 1
Enter book name: learn html5
Enter publisher name: SAMS
Enter publisher address: DELHI
**********************
Welcome to Book Store
**********************
Options 
1. Add Book
2. Exit 
Enter Choice: 2
Book(s) entered so far: 1
1. learn html5
Publication: SAMS,DELHI
BUILD SUCCESSFUL (total time: 21 seconds)

EJB - Blobs/Clobs

EJB 3.0使用@Lob批注提供对Blob和Clob类型的支持。 可以使用@Lob注释映射以下java类型。

  • java.sql.Blob
  • java.sql.Clob
  • byte[]
  • String
  • 可序列化对象
@Entity
@Table(name="books")
@EntityListeners(BookCallbackListener.class)
public class Book implements Serializable{
   ...
   private byte[] image;    
   @Lob @Basic(fetch= FetchType.EAGER)
   public byte[] getImage() {
      return image;
   }
   ...
}

例子 Example Application

让我们创建一个测试EJB应用程序来测试EJB 3.0中的blob/clob支持。

描述
1EJB - Create Application章节中解释,在com.iowiki.entity包下创建一个名为EjbComponent的项目。 请使用在EJB - Persistence章节中创建的项目本章来理解ejb概念中的clob/blob对象。
2com.iowiki.entity包下创建com.iowiki.entity 。 使用EJB - Persistence章节作为参考。 保持其余文件不变。
3 清理并构建应用程序以确保业务逻辑按照要求运行。
4 最后,在JBoss Application Server上以jar文件的形式部署应用程序。 如果JBoss Application服务器尚未启动,它将自动启动。
5 现在创建EJB客户端,一个基于控制台的应用程序,其方式与EJB - Create Application章节中主题Create Client to access EJB

创建/更改书籍表

CREATE TABLE book (
   id     integer PRIMARY KEY,
   name   varchar(50)
);
Alter table book add image bytea;
Alter table book add xml text;

EJBComponent (EJB Module)

Book.java

package com.iowiki.entity;
import com.iowiki.callback.BookCallbackListener;
import java.io.Serializable;
import javax.persistence.Basic;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.EntityListeners;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Lob;
import javax.persistence.Table;
@Entity
@Table(name="book")
public class Book implements Serializable{
   private int id;
   private String name;    
   private byte[] image;   
   private String xml;
   public Book(){        
   }
   @Id
   @GeneratedValue(strategy= GenerationType.IDENTITY)
   @Column(name="id")
   public int getId() {
      return id;
   }
   public void setId(int id) {
      this.id = id;
   }
   public String getName() {
      return name;
   }
   public void setName(String name) {
      this.name = name;
   }
   @Lob @Basic(fetch= FetchType.EAGER)
   public byte[] getImage() {
      return image;
   }
   public void setImage(byte[] image) {
      this.image = image;
   }
   @Lob @Basic(fetch= FetchType.EAGER)
   public String getXml() {
      return xml;
   }
   public void setXml(String xml) {
      this.xml = xml;
   }
}

LibraryPersistentBeanRemote.java

package com.iowiki.stateless;
import com.iowiki.entity.Book;
import java.util.List;
import javax.ejb.Remote;
@Remote
public interface LibraryPersistentBeanRemote {
   void addBook(Book bookName);
   List<Book> getBooks();
}

LibraryPersistentBean.java

package com.iowiki.stateless;
import com.iowiki.entity.Book;
import java.util.List;
import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
@Stateless
public class LibraryPersistentBean implements LibraryPersistentBeanRemote {
   public LibraryPersistentBean(){
   }
   @PersistenceContext(unitName="EjbComponentPU")
   private EntityManager entityManager;         
   public void addBook(Book book) {
      entityManager.persist(book);
   }    
   public List<Book> getBooks() {
      return entityManager.createQuery("From Book").getResultList();
   }
}
  • 只要在JBOSS上部署EjbComponent项目,请注意jboss日志。

  • JBoss已自动为会话bean创建了一个JNDI条目 - LibraryPersistentBean/remote

  • 我们将使用此查找字符串来获取类型的远程业务对象 - com.iowiki.interceptor.LibraryPersistentBeanRemote

JBoss应用服务器日志输出

...
16:30:01,401 INFO  [JndiSessionRegistrarBase] Binding the following Entries in Global JNDI:
   LibraryPersistentBean/remote - EJB3.x Default Remote Business Interface
   LibraryPersistentBean/remote-com.iowiki.interceptor.LibraryPersistentBeanRemote - EJB3.x Remote Business Interface
16:30:02,723 INFO  [SessionSpecContainer] Starting jboss.j2ee:jar=EjbComponent.jar,name=LibraryPersistentBean,service=EJB3
16:30:02,723 INFO  [EJBContainer] STARTED EJB: com.iowiki.interceptor.LibraryPersistentBeanRemote ejbName: LibraryPersistentBean
16:30:02,731 INFO  [JndiSessionRegistrarBase] Binding the following Entries in Global JNDI:
   LibraryPersistentBean/remote - EJB3.x Default Remote Business Interface
   LibraryPersistentBean/remote-com.iowiki.interceptor.LibraryPersistentBeanRemote - EJB3.x Remote Business Interface
...   

EJBTester (EJB Client)

jndi.properties

java.naming.factory.initial=org.jnp.interfaces.NamingContextFactory
java.naming.factory.url.pkgs=org.jboss.naming:org.jnp.interfaces
java.naming.provider.url=localhost
  • 这些属性用于初始化java命名服务的InitialContext对象。

  • InitialContext对象将用于查找无状态会话bean。

EJBTester.java

package com.iowiki.test;
import com.iowiki.stateful.LibraryBeanRemote;
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.List;
import java.util.Properties;
import javax.naming.InitialContext;
import javax.naming.NamingException;
public class EJBTester {
   BufferedReader brConsoleReader = null; 
   Properties props;
   InitialContext ctx;
   {
      props = new Properties();
      try {
         props.load(new FileInputStream("jndi.properties"));
      } catch (IOException ex) {
         ex.printStackTrace();
      }
      try {
         ctx = new InitialContext(props);            
      } catch (NamingException ex) {
         ex.printStackTrace();
      }
      brConsoleReader = 
      new BufferedReader(new InputStreamReader(System.in));
   }
   public static void main(String[] args) {
      EJBTester ejbTester = new EJBTester();
      ejbTester.testBlobClob();
   }
   private void showGUI(){
      System.out.println("**********************");
      System.out.println("Welcome to Book Store");
      System.out.println("**********************");
      System.out.print("Options \n1. Add Book\n2. Exit \nEnter Choice: ");
   }
   private void testBlobClob(){
      try {
         int choice = 1; 
         LibraryPersistentBeanRemote libraryBean = 
        (LibraryPersistentBeanRemote)
         ctx.lookup("LibraryPersistentBean/remote");
         while (choice != 2) {
            String bookName;
            String publisherName;
            String publisherAddress;
            showGUI();
            String strChoice = brConsoleReader.readLine();
            choice = Integer.parseInt(strChoice);
            if (choice == 1) {
               System.out.print("Enter book name: ");
               bookName = brConsoleReader.readLine();
               String xml = "<book><name>"+bookName+"</name></book>";
               Book book = new Book();
               book.setName(bookName);                                        
               byte[] imageBytes = {0x32, 0x32,0x32, 0x32,0x32,
               0x32,0x32, 0x32,
               0x32, 0x32,0x32, 0x32,0x32, 0x32,0x32, 0x32,
               0x32, 0x32,0x32, 0x32,0x32, 0x32,0x32, 0x32
               };
               book.setImage(imageBytes);
               book.setXml(xml);
               libraryBean.addBook(book);          
            } else if (choice == 2) {
               break;
            }
         }
         List<Book> booksList = libraryBean.getBooks();
         System.out.println("Book(s) entered so far: " + booksList.size());
         int i = 0;
         for (Book book:booksList) {
            System.out.println((i+1)+". " + book.getName());
            byte[] imageByts = book.getImage();
            if(imageByts != null){
               System.out.print("image bytes: [");
               for(int j = 0; j < imageByts.length ; j++){
                  System.out.print("0x" 
                  + String.format("%x", imageByts[j]) +" ");
               }            
               System.out.println("]");
            }        
            System.out.println(book.getXml());
            i++;
         }           
      } catch (Exception e) {
         System.out.println(e.getMessage());
         e.printStackTrace();
      }finally {
         try {
            if(brConsoleReader !=null){
               brConsoleReader.close();
            }
         } catch (IOException ex) {
            System.out.println(ex.getMessage());
         }
      }
   }
}

EJBTester执行以下任务。

  • 从jndi.properties加载属性并初始化InitialContext对象。

  • 在testInterceptedEjb()方法中,使用名称 - “LibraryPersistenceBean/remote”完成jndi查找以获取远程业务对象(无状态EJB)。

  • 然后向用户显示库存储用户界面,并要求他/她输入选项。

  • 如果用户输入1,系统将询问书名并使用无状态会话bean addBook()方法保存书籍。 会话Bean将书存储在数据库中。

  • 如果用户输入2,系统将使用无状态会话bean getBooks()方法检索书籍并退出。

运行客户端以访问EJB

在项目资源管理器中找到EJBTester.java。 右键单击EJBTester类并选择run file

在Netbeans控制台中验证以下输出。

run:
**********************
Welcome to Book Store
**********************
Options 
1. Add Book
2. Exit 
Enter Choice: 1
Enter book name: learn testing
**********************
Welcome to Book Store
**********************
Options 
1. Add Book
2. Exit 
Enter Choice: 2
Book(s) entered so far: 1
1. learn testing
image bytes: [
0x32 0x32 0x32 0x32 0x32 0x32 0x32 0x32 0x32 0x32 0x32 0x32 0x32 0x32 0x32 0x32 0x32 0x32 0x32 0x32 0x32 0x32 0x32 0x32 ]
<book><name>learn testing</name></book>
BUILD SUCCESSFUL (total time: 20 seconds)

EJB - Transactions

事务是单个工作项单元,它遵循ACID属性。 ACID代表Atomic,Consistent,Isolated和Durable。

  • Atomic - 如果任何工作项失败,整个单元将被视为失败。 成功意味着,所有项目都成功执行。

  • Consistent - 事务必须使系统保持一致状态。

  • Isolated - 每个事务独立于任何其他事务执行。

  • Durable - 如果已执行或已执行,则事务应在系统故障后继续存在。

EJB容器/服务器是事务服务器,处理事务上下文传播和分布式事务。 事务可以由容器管理,也可以通过bean代码中的自定义代码处理来管理。

  • Container Managed Transactions - 在此类型中,容器管理事务状态。

  • Bean Managed Transactions - 在此类型中,开发人员管理事务状态的生命周期。

容器管理事务

EJB 3.0指定了以下EJB事件容器实现的事务属性 -

  • REQUIRED - 表示必须在事务中执行业务方法,否则将为该方法启动新事务。

  • REQUIRES_NEW - 表示要为业务方法启动新事务。

  • SUPPORTS - 表示业务方法将作为事务的一部分执行。

  • NOT_SUPPORTED - 表示不应将业务方法作为事务的一部分执行。

  • MANDATORY - 表示业务方法将作为事务的一部分执行,否则将抛出异常。

  • NEVER - 指示业务方法是否作为事务的一部分执行,然后将引发异常。

例子 (Example)

package com.iowiki.txn.required;
import javax.ejb.*
@Stateless
@TransactionManagement(TransactionManagementType.CONTAINER)
public class UserDetailBean implements UserDetailRemote {
   private UserDetail;
   @TransactionAttribute(TransactionAttributeType.REQUIRED)
   public void createUserDetail() {
      //create user details object
   }
}

使用Required注释创建createUserDetail()业务方法。

package com.iowiki.txn.required;
import javax.ejb.*
@Stateless
public class UserSessionBean implements UserRemote {
   private User;
   @EJB
   private UserDetailRemote userDetail;
   public void createUser() {
      //create user 
      //...
      //create user details
      userDetail.createUserDetail();
   }
}

createUser()业务方法正在使用createUserDetail()。 如果在createUser()调用期间发生异常并且未创建User对象,则也不会创建UserDetail对象。

Bean管理事务

在Bean管理事务中,可以通过在应用程序级别处理异常来管理事务。

以下是要考虑的关键点 -

  • Start - 何时在业务方法中启动事务。

  • 成功 - 确定要提交事务时的成功方案。

  • Failed - 确定要回滚事务时的失败方案。

例子 (Example)

package com.iowiki.txn.bmt;
import javax.annotation.Resource;
import javax.ejb.Stateless;
import javax.ejb.TransactionManagement;
import javax.ejb.TransactionManagementType;
import javax.transaction.UserTransaction;
@Stateless
@TransactionManagement(value=TransactionManagementType.BEAN)
public class AccountBean implements AccountBeanLocal {
   @Resource
   private UserTransaction userTransaction;
   public void transferFund(Account fromAccount, double fund , 
      Account toAccount) throws Exception{
      try{
         userTransaction.begin();
         confirmAccountDetail(fromAccount);
         withdrawAmount(fromAccount,fund);
         confirmAccountDetail(toAccount);
         depositAmount(toAccount,fund);
         userTransaction.commit();
      }catch (InvalidAccountException exception){
         userTransaction.rollback();
      }catch (InsufficientFundException exception){
         userTransaction.rollback();
      }catch (PaymentException exception){
         userTransaction.rollback();
      }
   }
   private void confirmAccountDetail(Account account) 
      throws InvalidAccountException {
   }
   private void withdrawAmount() throws InsufficientFundException {
   }
   private void depositAmount() throws PaymentException{
   }
}

在此示例中,我们使用UserTransaction接口使用userTransaction.begin()方法调用来标记事务的开始。 我们使用userTransaction.commit()方法标记事务的完成,如果在事务期间发生任何异常,那么我们使用userTransaction.rollback()方法调用回滚整个事务。

EJB - Security

安全性是任何企业级应用程序的主要关注点。 它包括访问应用程序的用户或系统的标识。 基于标识,它允许或拒绝访问应用程序内的资源。 EJB容器管理标准安全问题,或者可以对其进行自定义以处理任何特定的安全问题。

重要的安全条款

  • Authentication - 这是确保访问系统或应用程序的用户被验证为可信的过程。

  • Authorization - 这是确保真实用户具有访问系统资源的权限级别的过程。

  • User - 用户代表访问应用程序的客户端或系统。

  • User Groups - 用户可能是具有特定权限的组的一部分例如管理员组。

  • User Roles - 角色定义权限级别,用户拥有或访问系统资源的权限。

容器管理安全

EJB 3.0已经指定了以下EJB容器实现的安全性属性/注释。

  • DeclareRoles - 表示该类将接受声明的角色。 注释在类级别应用。

  • RolesAllowed - 表示指定角色的用户可以访问方法。 可以在类级别应用,从而可以访问所有类的方法,购买指定角色的用户。

  • PermitAll - 表示所有人都可以访问业务方法。 它既可以在课堂上也可以在方法层面上应用。

  • DenyAll - 表示在类或方法级别指定的任何用户都无法访问业务方法。

例子 (Example)

package com.iowiki.security.required;
import javax.ejb.*
@Stateless
@DeclareRoles({"student" "librarian"})
public class LibraryBean implements LibraryRemote {
   @RolesAllowed({"librarian"})
   public void delete(Book book){
	  //delete book
   }
   @PermitAll
   public void viewBook(Book book){
      //view book
   }
   @DenyAll
   public void deleteAll(){
      //delete all books
   } 
}

安全配置

在配置文件中映射角色和用户分组。

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE sun-ejb-jar PUBLIC "-//Sun Microsystems, Inc.//DTD Application Server 9.0 EJB 3.0//EN" "http://www.sun.com/software/appserver/dtds/sun-ejb-jar_3_0-0.dtd">
<ejb-jar>
   <security-role-mapping>
      <role-name>student</role-name>
      <group-name>student-group</group-name>
   </security-role-mapping>
   <security-role-mapping>
      <role-name>librarian</role-name>
      <group-name>librarian-group</group-name>
   </security-role-mapping>  
   <enterprise-beans/>
</ejb-jar>

EJB - JNDI Bindings

JNDI代表Java命名和目录接口。 它是一组API和服务接口。 基于Java的应用程序使用JNDI进行命名和目录服务。 在EJB的上下文中,有两个术语。

  • Binding - 这是指为EJB对象分配名称,以后可以使用。

  • Lookup - 这是指查找并获取EJB的对象。

在Jboss中,会话bean默认以以下格式绑定在JNDI中。

  • local - EJB-name/local

  • remote - EJB-name/remote

如果EJB与 .ear文件捆绑在一起,则默认格式如下 -

  • local - application-name/ejb-name/local

  • remote - application-name/ejb-name/remote

默认绑定的示例

请参阅EJB - Create Application章节的JBoss控制台输出。

JBoss应用服务器日志输出

...
16:30:02,723 INFO  [SessionSpecContainer] Starting jboss.j2ee:jar=EjbComponent.jar,name=LibrarySessionBean,service=EJB3
16:30:02,723 INFO  [EJBContainer] STARTED EJB: com.iowiki.stateless.LibrarySessionBean ejbName: LibrarySessionBean
16:30:02,731 INFO  [JndiSessionRegistrarBase] Binding the following Entries in Global JNDI:
   LibrarySessionBean/remote - EJB3.x Default Remote Business Interface
   LibrarySessionBean/remote-com.iowiki.stateless.LibrarySessionBeanRemote - EJB3.x Remote Business Interface
...

自定义绑定

注释可用于自定义默认的JNDI绑定 -

  • local - org.jboss.ejb3.LocalBinding

  • remote - org.jboss.ejb3.RemoteBindings

更新LibrarySessionBean.java。 请参阅EJB - Create Application章节。

LibrarySessionBean

package com.iowiki.stateless;
import java.util.ArrayList;
import java.util.List;
import javax.ejb.Stateless;
@Stateless
@LocalBinding(jndiBinding="iowiki/librarySession")
public class LibrarySessionBean implements LibrarySessionBeanLocal {
   List<String> bookShelf;    
   public LibrarySessionBean(){
      bookShelf = new ArrayList<String>();
   }
   public void addBook(String bookName) {
      bookShelf.add(bookName);
   }    
   public List<String> getBooks() {
      return bookShelf;
   }
}

LibrarySessionBeanLocal

package com.iowiki.stateless;
import java.util.List;
import javax.ejb.Local;
@Local
public interface LibrarySessionBeanLocal {
   void addBook(String bookName);
   List getBooks();
}

构建项目,在Jboss上部署应用程序,并在Jboss控制台中验证以下输出 -

...
16:30:02,723 INFO  [SessionSpecContainer] Starting jboss.j2ee:jar=EjbComponent.jar,name=LibrarySessionBean,service=EJB3
16:30:02,723 INFO  [EJBContainer] STARTED EJB: com.iowiki.stateless.LibrarySessionBean ejbName: LibrarySessionBean
16:30:02,731 INFO  [JndiSessionRegistrarBase] Binding the following Entries in Global JNDI:
   iowiki/librarySession - EJB3.x Default Local Business Interface
   iowiki/librarySession-com.iowiki.stateless.LibrarySessionBeanLocal - EJB3.x Local Business Interface
...

EJB - Entity Relationships

EJB 3.0提供了定义数据库实体关系/映射的选项,如一对一,一对多,多对一和多对多关系。

以下是相关注释 -

  • One-to-One - 对象具有一对一的关系。 例如,乘客可以一次使用单张票。

  • One-to-Many - 对象具有一对多的关系。 例如,父亲可以有多个孩子。

  • Many-to-One - 对象具有多对一关系。 例如,多个孩子有一个单身母亲。

  • Many-to-Many - 对象具有多对多的关系。 例如,一本书可以有多个作者,作者可以写多本书。

我们将在这里演示使用ManyToMany映射。 要表示ManyToMany关系,需要以下三个表 -

  • Book - 书桌,有书的记录。

  • Author - 作者表,有作者记录。

  • Book_Author - Book Author表,具有上述Book和Author表的链接。

创建表

在默认数据库postgres创建一个表book author book_author

CREATE TABLE book (
   book_id     integer,   
   name   varchar(50)      
);
CREATE TABLE author (
   author_id   integer,
   name   varchar(50)      
);
CREATE TABLE book_author (
   book_id     integer,
   author_id   integer 
);

创建实体类

@Entity
@Table(name="author")
public class Author implements Serializable{
   private int id;
   private String name;
   ...   
}
@Entity
@Table(name="book")
public class Book implements Serializable{
   private int id;
   private String title;
   private Set<Author> authors;
   ...   
}

在Book Entity中使用ManyToMany批注。

@Entity
public class Book implements Serializable{
   ...
   @ManyToMany(cascade = {CascadeType.PERSIST, CascadeType.MERGE}
      , fetch = FetchType.EAGER)
   @JoinTable(table = @Table(name = "book_author"),
      joinColumns = {@JoinColumn(name = "book_id")},
      inverseJoinColumns = {@JoinColumn(name = "author_id")})
   public Set<Author> getAuthors(){
      return authors;
   }
   ...
}

例子 Example Application

让我们创建一个测试EJB应用程序来测试EJB 3.0中的实体关系对象。

描述
1EJB - Create Application章节中解释,在com.iowiki.entity包下创建一个名为EjbComponent的项目。 请使用在EJB - Persistence章节中创建的项目本章来理解EJB概念中的嵌入对象。
2 按照EJB - Create Application章节中的说明在Author.java包下创建Author.java 。 保持其余文件不变。
3com.iowiki.entity包下创建com.iowiki.entity 。 使用EJB - Persistence章节作为参考。 保持其余文件不变。
4 清理并构建应用程序以确保业务逻辑按照要求运行。
5 最后,在JBoss Application Server上以jar文件的形式部署应用程序。 如果JBoss Application服务器尚未启动,它将自动启动。
6 现在创建EJB客户端,一个基于控制台的应用程序,其方式与EJB - Create Application章节中主题Create Client to access EJB

EJBComponent (EJB Module)

Author.java

package com.iowiki.entity;
import java.io.Serializable;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
@Entity
@Table(name="author")
public class Author implements Serializable{
   private int id;
   private String name;
   public Author(){}
   public Author(int id, String name){
      this.id = id;
      this.name = name;
   }
   @Id  
   @GeneratedValue(strategy= GenerationType.IDENTITY)
   @Column(name="author_id")
   public int getId() {
      return id;
   }
   public void setId(int id) {
      this.id = id;
   }
   public String getName() {
      return name;
   }
   public void setName(String name) {
      this.name = name;
   }
   public String toString(){
      return id + "," + name;
   }    
}

Book.java

package com.iowiki.entity;
import java.io.Serializable;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Table;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
@Entity
@Table(name="book")
public class Book implements Serializable{
   private int id;
   private String name;
   private Set<Author> authors;
   public Book(){        
   }
   @Id  
   @GeneratedValue(strategy= GenerationType.IDENTITY)
   @Column(name="book_id")
   public int getId() {
      return id;
   }
   public void setId(int id) {
      this.id = id;
   }
   public String getName() {
      return name;
   }
   public void setName(String name) {
      this.name = name;
   }
   public void setAuthors(Set<Author> authors) {
      this.authors = authors;
   }    
   @ManyToMany(cascade = {CascadeType.PERSIST, CascadeType.MERGE}
      , fetch = FetchType.EAGER)
   @JoinTable(table = @Table(name = "book_author"),
      joinColumns = {@JoinColumn(name = "book_id")},
      inverseJoinColumns = {@JoinColumn(name = "author_id")})
   public Set<Author> getAuthors() {
      return authors;
   }
}

LibraryPersistentBeanRemote.java

package com.iowiki.stateless;
import com.iowiki.entity.Book;
import java.util.List;
import javax.ejb.Remote;
@Remote
public interface LibraryPersistentBeanRemote {
   void addBook(Book bookName);
   List<Book> getBooks();
}

LibraryPersistentBean.java

package com.iowiki.stateless;
import com.iowiki.entity.Book;
import java.util.List;
import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
@Stateless
public class LibraryPersistentBean implements LibraryPersistentBeanRemote {
   public LibraryPersistentBean(){
   }
   @PersistenceContext(unitName="EjbComponentPU")
   private EntityManager entityManager;         
   public void addBook(Book book) {
      entityManager.persist(book);
   }    
   public List<Book> getBooks() {
      return entityManager.createQuery("From Book").getResultList();
   }
}
  • 只要在JBOSS上部署EjbComponent项目,请注意jboss日志。

  • JBoss已自动为会话bean创建了一个JNDI条目 - LibraryPersistentBean/remote

  • 我们将使用此查找字符串来获取类型的远程业务对象 - com.iowiki.interceptor.LibraryPersistentBeanRemote

JBoss应用服务器日志输出

...
16:30:01,401 INFO  [JndiSessionRegistrarBase] Binding the following Entries in Global JNDI:
   LibraryPersistentBean/remote - EJB3.x Default Remote Business Interface
   LibraryPersistentBean/remote-com.iowiki.interceptor.LibraryPersistentBeanRemote - EJB3.x Remote Business Interface
16:30:02,723 INFO  [SessionSpecContainer] Starting jboss.j2ee:jar=EjbComponent.jar,name=LibraryPersistentBean,service=EJB3
16:30:02,723 INFO  [EJBContainer] STARTED EJB: com.iowiki.interceptor.LibraryPersistentBeanRemote ejbName: LibraryPersistentBean
16:30:02,731 INFO  [JndiSessionRegistrarBase] Binding the following Entries in Global JNDI:
   LibraryPersistentBean/remote - EJB3.x Default Remote Business Interface
   LibraryPersistentBean/remote-com.iowiki.interceptor.LibraryPersistentBeanRemote - EJB3.x Remote Business Interface
...   

EJBTester (EJB Client)

jndi.properties

java.naming.factory.initial=org.jnp.interfaces.NamingContextFactory
java.naming.factory.url.pkgs=org.jboss.naming:org.jnp.interfaces
java.naming.provider.url=localhost
  • 这些属性用于初始化java命名服务的InitialContext对象。

  • InitialContext对象将用于查找无状态会话bean。

EJBTester.java

package com.iowiki.test;
import com.iowiki.stateful.LibraryBeanRemote;
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.*;
import javax.naming.InitialContext;
import javax.naming.NamingException;
public class EJBTester {
   BufferedReader brConsoleReader = null; 
   Properties props;
   InitialContext ctx;
   {
      props = new Properties();
      try {
         props.load(new FileInputStream("jndi.properties"));
      } catch (IOException ex) {
         ex.printStackTrace();
      }
      try {
         ctx = new InitialContext(props);            
      } catch (NamingException ex) {
         ex.printStackTrace();
      }
      brConsoleReader = 
      new BufferedReader(new InputStreamReader(System.in));
   }
   public static void main(String[] args) {
      EJBTester ejbTester = new EJBTester();
      ejbTester.testEmbeddedObjects();
   }
   private void showGUI(){
      System.out.println("**********************");
      System.out.println("Welcome to Book Store");
      System.out.println("**********************");
      System.out.print("Options \n1. Add Book\n2. Exit \nEnter Choice: ");
   }
   private void testEmbeddedObjects(){
      try {
         int choice = 1; 
         LibraryPersistentBeanRemote libraryBean = 
         (LibraryPersistentBeanRemote)
         ctx.lookup("LibraryPersistentBean/remote");
         while (choice != 2) {
            String bookName;
            String authorName;
            showGUI();
            String strChoice = brConsoleReader.readLine();
            choice = Integer.parseInt(strChoice);
            if (choice == 1) {
               System.out.print("Enter book name: ");
               bookName = brConsoleReader.readLine();
               System.out.print("Enter author name: ");
               authorName = brConsoleReader.readLine();               
               Book book = new Book();
               book.setName(bookName);
               Author author = new Author();
               author.setName(authorName);
               Set<Author> authors = new HashSet<Author>();
               authors.add(author);
               book.setAuthors(authors);
               libraryBean.addBook(book);          
            } else if (choice == 2) {
               break;
            }
         }
         List<Book> booksList = libraryBean.getBooks();
         System.out.println("Book(s) entered so far: " + booksList.size());
         int i = 0;
         for (Book book:booksList) {
            System.out.println((i+1)+". " + book.getName());
            System.out.print("Author: ");
            Author[] authors = (Author[])books.getAuthors().toArray();
            for(int j=0;j<authors.length;j++){
               System.out.println(authors[j]);
            }
            i++;
         }           
      } catch (Exception e) {
         System.out.println(e.getMessage());
         e.printStackTrace();
      }finally {
         try {
            if(brConsoleReader !=null){
               brConsoleReader.close();
            }
         } catch (IOException ex) {
            System.out.println(ex.getMessage());
         }
      }
   }
}

EJBTester执行以下任务 -

  • 从jndi.properties加载属性并初始化InitialContext对象。

  • 在testInterceptedEjb()方法中,使用名称 - “LibraryPersistenceBean/remote”完成jndi查找以获取远程业务对象(无状态EJB)。

  • 然后向用户显示库存储用户界面,并要求他/她输入选项。

  • 如果用户输入1,系统将询问书名并使用无状态会话bean addBook()方法保存书籍。 会话Bean将书存储在数据库中。

  • 如果用户输入2,系统将使用无状态会话bean getBooks()方法检索书籍并退出。

运行客户端以访问EJB

在项目资源管理器中找到EJBTester.java。 右键单击EJBTester类并选择run file

在Netbeans控制台中验证以下输出。

run:
**********************
Welcome to Book Store
**********************
Options 
1. Add Book
2. Exit 
Enter Choice: 1
Enter book name: learn html5
Enter Author name: Robert
**********************
Welcome to Book Store
**********************
Options 
1. Add Book
2. Exit 
Enter Choice: 2
Book(s) entered so far: 1
1. learn html5
Author: Robert
BUILD SUCCESSFUL (total time: 21 seconds)

EJB - Access Database

在EJB 3.0中,持久性机制用于访问容器管理数据库相关操作的数据库。 开发人员可以直接在EJB业务方法中使用JDBC API调用来访问数据库。

要在EJB中演示数据库访问,我们需要执行以下任务 -

  • Step 1 - 在数据库中创建一个表。

  • Step 2 - 创建一个有业务的无状态EJB。

  • Step 3 - 更新无状态EJB。 添加方法以通过实体管理器添加记录并从数据库中获取记录。

  • Step 4 - 基于控制台的应用程序客户端将访问无状态EJB以在数据库中保留数据。

Create Table

在默认数据库postgres创建一个表。

CREATE TABLE books (
   id     integer PRIMARY KEY,
   name   varchar(50)
);

创建一个模型类

public class Book implements Serializable{
   private int id;
   private String name;
   public Book(){        
   }
   public int getId() {
      return id;
   }
   ...
}

创建无状态EJB

@Stateless
public class LibraryPersistentBean implements LibraryPersistentBeanRemote {
   public void addBook(Book book) {
     //persist book using jdbc calls
   }    
   public List<Book> getBooks() {        
     //get books using jdbc calls
   }
   ...
}

在构建EJB模块之后,我们需要一个客户端来访问无状态bean,我们将在下一节中创建它。

例子 Example Application

让我们创建一个测试EJB应用程序来测试EJB数据库访问机制。

描述
1EJB - Create Application章节中解释,在com.iowiki.entity包下创建一个名为EjbComponent的项目。 您还可以使用在EJB - Create Application的项目EJB - Create Application章节,以便本章了解EJB数据访问概念。
2Book.java包下创建Book.java com.iowiki.entity如下所示进行修改。
3 按照EJB - Create Application章节中的说明创建LibraryPersistentBean.javaLibraryPersistentBeanRemote ,并按如下所示进行修改。
4 清理并构建应用程序以确保业务逻辑按照要求运行。
5 最后,在JBoss Application Server上以jar文件的形式部署应用程序。 如果JBoss Application服务器尚未启动,它将自动启动。
6 现在创建EJB客户端,一个基于控制台的应用程序,其方式与EJB - Create Application章节中主题Create Client to access EJB 。 修改它,如下所示。

EJBComponent (EJB Module)

Book.java

package com.iowiki.entity;
import java.io.Serializable;
public class Book implements Serializable{
   private int id;
   private String name;
   public Book(){        
   }
   public int getId() {
      return id;
   }
   public void setId(int id) {
      this.id = id;
   }
   public String getName() {
      return name;
   }
   public void setName(String name) {
      this.name = name;
   }    
}

LibraryPersistentBeanRemote.java

package com.iowiki.stateless;
import com.iowiki.entity.Book;
import java.util.List;
import javax.ejb.Remote;
@Remote
public interface LibraryPersistentBeanRemote {
   void addBook(Book bookName);
   List<Book> getBooks();
}

LibraryPersistentBean.java

package com.iowiki.stateless;
import com.iowiki.entity.Book;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;
import javax.ejb.Stateless;
@Stateless
public class LibraryPersistentBean implements LibraryPersistentBeanRemote {
   public LibraryPersistentBean(){
   }
   public void addBook(Book book) {
      Connection con = null;
      String url = "jdbc:postgresql://localhost:5432/postgres";
      String driver = "org.postgresql.driver";
      String userName = "sa";
      String password = "sa";
      List<Book> books = new ArrayList<Book>();
      try {
         Class.forName(driver).newInstance();
         con = DriverManager.getConnection(url , userName, password);
         PreparedStatement st = 
         con.prepareStatement("insert into book(name) values(?)");
         st.setString(1,book.getName());
         int result = st.executeUpdate();                
      } catch (SQLException ex) {
         ex.printStackTrace();
      } catch (InstantiationException ex) {
         ex.printStackTrace();
      } catch (IllegalAccessException ex) {
         ex.printStackTrace();
      } catch (ClassNotFoundException ex) {
         ex.printStackTrace();
      }    
   }    
   public List<Book> getBooks() {
      Connection con = null;
      String url = "jdbc:postgresql://localhost:5432/postgres";
      String driver = "org.postgresql.driver";
      String userName = "sa";
      String password = "sa";
      List<Book> books = new ArrayList<Book>();
      try {
         Class.forName(driver).newInstance();
         con = DriverManager.getConnection(url , userName, password);
         Statement st = con.createStatement();
         ResultSet rs = st.executeQuery("select * from book");
         Book book;
         while (rs.next()) {
            book = new Book();
            book.setId(rs.getInt(1));                 
            book.setName(rs.getString(2));
            books.add(book);
         }
      } catch (SQLException ex) {
         ex.printStackTrace();
      } catch (InstantiationException ex) {
         ex.printStackTrace();
      } catch (IllegalAccessException ex) {
         ex.printStackTrace();
      } catch (ClassNotFoundException ex) {
         ex.printStackTrace();
      }
      return books;
   }
}
  • 只要在JBOSS上部署EjbComponent项目,请注意jboss日志。

  • JBoss已自动为会话bean创建了一个JNDI条目 - LibraryPersistentBean/remote

  • 我们将使用此查找字符串来获取类型的远程业务对象 - com.iowiki.stateless.LibraryPersistentBeanRemote

JBoss应用服务器日志输出

...
16:30:01,401 INFO  [JndiSessionRegistrarBase] Binding the following Entries in Global JNDI:
   LibraryPersistentBean/remote - EJB3.x Default Remote Business Interface
   LibraryPersistentBean/remote-com.iowiki.stateless.LibraryPersistentBeanRemote - EJB3.x Remote Business Interface
16:30:02,723 INFO  [SessionSpecContainer] Starting jboss.j2ee:jar=EjbComponent.jar,name=LibraryPersistentBeanRemote,service=EJB3
16:30:02,723 INFO  [EJBContainer] STARTED EJB: com.iowiki.stateless.LibraryPersistentBeanRemote ejbName: LibraryPersistentBean
16:30:02,731 INFO  [JndiSessionRegistrarBase] Binding the following Entries in Global JNDI:
   LibraryPersistentBean/remote - EJB3.x Default Remote Business Interface
   LibraryPersistentBean/remote-com.iowiki.stateless.LibraryPersistentBeanRemote - EJB3.x Remote Business Interface
...   

EJBTester (EJB Client)

jndi.properties

java.naming.factory.initial=org.jnp.interfaces.NamingContextFactory
java.naming.factory.url.pkgs=org.jboss.naming:org.jnp.interfaces
java.naming.provider.url=localhost
  • 这些属性用于初始化java命名服务的InitialContext对象。

  • InitialContext对象将用于查找无状态会话bean。

EJBTester.java

package com.iowiki.test;
import com.iowiki.stateless.LibraryPersistentBeanRemote;
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.List;
import java.util.Properties;
import javax.naming.InitialContext;
import javax.naming.NamingException;
public class EJBTester {
   BufferedReader brConsoleReader = null; 
   Properties props;
   InitialContext ctx;
   {
      props = new Properties();
      try {
         props.load(new FileInputStream("jndi.properties"));
      } catch (IOException ex) {
         ex.printStackTrace();
      }
      try {
         ctx = new InitialContext(props);            
      } catch (NamingException ex) {
         ex.printStackTrace();
      }
      brConsoleReader = 
      new BufferedReader(new InputStreamReader(System.in));
   }
   public static void main(String[] args) {
      EJBTester ejbTester = new EJBTester();
      ejbTester.testEntityEjb();
   }
   private void showGUI(){
      System.out.println("**********************");
      System.out.println("Welcome to Book Store");
      System.out.println("**********************");
      System.out.print("Options \n1. Add Book\n2. Exit \nEnter Choice: ");
   }
   private void testEntityEjb(){
      try {
         int choice = 1; 
         LibraryPersistentBeanRemote libraryBean =
         LibraryPersistentBeanRemote)
         ctx.lookup("LibraryPersistentBean/remote");
         while (choice != 2) {
            String bookName;
            showGUI();
            String strChoice = brConsoleReader.readLine();
            choice = Integer.parseInt(strChoice);
            if (choice == 1) {
               System.out.print("Enter book name: ");
               bookName = brConsoleReader.readLine();
               Book book = new Book();
               book.setName(bookName);
               libraryBean.addBook(book);          
            } else if (choice == 2) {
               break;
            }
         }
         List<Book> booksList = libraryBean.getBooks();
         System.out.println("Book(s) entered so far: " + booksList.size());
         int i = 0;
         for (Book book:booksList) {
            System.out.println((i+1)+". " + book.getName());
            i++;
         }           
      } catch (Exception e) {
         System.out.println(e.getMessage());
         e.printStackTrace();
      }finally {
         try {
            if(brConsoleReader !=null){
               brConsoleReader.close();
            }
         } catch (IOException ex) {
            System.out.println(ex.getMessage());
         }
      }
   }
}

EJBTester执行以下任务 -

  • 从jndi.properties加载属性并初始化InitialContext对象。

  • 在testStatefulEjb()方法中,使用名称“LibraryStatelessSessionBean/remote”完成jndi查找以获取远程业务对象(有状态EJB)。

  • 然后向用户显示库存储用户界面,并要求他/她输入选项。

  • 如果用户输入1,系统将询问书名并使用无状态会话bean addBook()方法保存书籍。 会话Bean通过EntityManager调用将数据库保存在数据库中。

  • 如果用户输入2,系统将使用无状态会话bean getBooks()方法检索书籍并退出。

  • 然后使用名称“LibraryStatelessSessionBean/remote”完成另一个jndi查找,以再次获取远程业务对象(有状态EJB)并完成书籍列表。

运行客户端以访问EJB

在项目资源管理器中找到EJBTester.java。 右键单击EJBTester类并选择run file

在Netbeans控制台中验证以下输出。

run:
**********************
Welcome to Book Store
**********************
Options 
1. Add Book
2. Exit 
Enter Choice: 1
Enter book name: Learn Java
**********************
Welcome to Book Store
**********************
Options 
1. Add Book
2. Exit 
Enter Choice: 2
Book(s) entered so far: 1
1. learn java
BUILD SUCCESSFUL (total time: 15 seconds)

EJB - Query Language

EJB Query Language编写自定义查询非常方便,无需担心底层数据库详细信息。 它与HQL,hibernate查询语言非常相似,通常称为EJBQL。

为了演示EJB中的EJBQL,我们将执行以下任务 -

  • Step 1 - 在数据库中创建表。

  • Step 2 - 创建一个有业务的无状态EJB。

  • Step 3更新无状态EJB。 添加方法以通过实体管理器添加记录并从数据库中获取记录。

  • Step 4 - 基于控制台的应用程序客户端将访问无状态EJB以在数据库中保留数据。

Create Table

在默认数据库postgres创建一个表。

CREATE TABLE books (
   id     integer PRIMARY KEY,
   name   varchar(50)
);

创建一个模型类

public class Book implements Serializable{
   private int id;
   private String name;
   public Book(){        
   }
   public int getId() {
      return id;
   }
   ...
}

创建无状态EJB

@Stateless
public class LibraryPersistentBean implements LibraryPersistentBeanRemote {
   public void addBook(Book book) {
     //persist book using entity manager
   }    
   public List<Book> getBooks() {        
     //get books using entity manager
   }
   ...
}

在构建EJB模块之后,我们需要一个客户端来访问无状态bean,我们将在下一节中创建它。

例子 Example Application

让我们创建一个测试EJB应用程序来测试EJB数据库访问机制。

描述
1EJB - Create Application章节中解释,在com.iowiki.entity包下创建一个名为EjbComponent的项目。 您还可以使用在EJB - Create Application的项目EJB - Create Application章节,以便本章了解EJB数据访问概念。
2Book.java包下创建Book.java com.iowiki.entity如下所示进行修改。
3 按照EJB - Create Application章节中的说明创建LibraryPersistentBean.javaLibraryPersistentBeanRemote ,并按如下所示进行修改。
4 清理并构建应用程序以确保业务逻辑按照要求运行。
5 最后,在JBoss Application Server上以jar文件的形式部署应用程序。 如果JBoss Application服务器尚未启动,它将自动启动。
6 现在创建EJB客户端,一个基于控制台的应用程序,其方式与EJB - Create Application章节中主题Create Client to access EJB 。 修改它,如下所示。

EJBComponent (EJB Module)

Book.java

package com.iowiki.entity;
import java.io.Serializable;
public class Book implements Serializable{
   private int id;
   private String name;
   public Book(){        
   }
   public int getId() {
      return id;
   }
   public void setId(int id) {
      this.id = id;
   }
   public String getName() {
      return name;
   }
   public void setName(String name) {
      this.name = name;
   }    
}

LibraryPersistentBeanRemote.java

package com.iowiki.stateless;
import com.iowiki.entity.Book;
import java.util.List;
import javax.ejb.Remote;
@Remote
public interface LibraryPersistentBeanRemote {
   void addBook(Book bookName);
   List<Book> getBooks();
}

LibraryPersistentBean.java

package com.iowiki.stateless;
import com.iowiki.entity.Book;
import java.util.List;
import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;
@Stateless
public class LibraryPersistentBean implements LibraryPersistentBeanRemote {
   public LibraryPersistentBean(){
   }
   @PersistenceContext(unitName="EntityEjbPU")
   private EntityManager entityManager;         
   public void addBook(Book book) {
      entityManager.persist(book);
   }    
   public List<Book> getBooks() {
      //create an ejbql expression
      String ejbQL = "From Book b where b.name like ?1";
      //create query
      Query query = entityManager.createQuery(ejbQL);
      //substitute parameter.
      query.setParameter(1, "%test%");   
      //execute the query
      return query.getResultList();
   }   
}
  • 只要在JBOSS上部署EjbComponent项目,请注意jboss日志。

  • JBoss已自动为会话bean创建了一个JNDI条目 - LibraryPersistentBean/remote

  • 我们将使用此查找字符串来获取类型的远程业务对象 - com.iowiki.stateless.LibraryPersistentBeanRemote

JBoss应用服务器日志输出

...
16:30:01,401 INFO  [JndiSessionRegistrarBase] Binding the following Entries in Global JNDI:
   LibraryPersistentBean/remote - EJB3.x Default Remote Business Interface
   LibraryPersistentBean/remote-com.iowiki.stateless.LibraryPersistentBeanRemote - EJB3.x Remote Business Interface
16:30:02,723 INFO  [SessionSpecContainer] Starting jboss.j2ee:jar=EjbComponent.jar,name=LibraryPersistentBeanRemote,service=EJB3
16:30:02,723 INFO  [EJBContainer] STARTED EJB: com.iowiki.stateless.LibraryPersistentBeanRemote ejbName: LibraryPersistentBean
16:30:02,731 INFO  [JndiSessionRegistrarBase] Binding the following Entries in Global JNDI:
   LibraryPersistentBean/remote - EJB3.x Default Remote Business Interface
   LibraryPersistentBean/remote-com.iowiki.stateless.LibraryPersistentBeanRemote - EJB3.x Remote Business Interface
...   

EJBTester (EJB Client)

jndi.properties

java.naming.factory.initial=org.jnp.interfaces.NamingContextFactory
java.naming.factory.url.pkgs=org.jboss.naming:org.jnp.interfaces
java.naming.provider.url=localhost
  • 这些属性用于初始化java命名服务的InitialContext对象。

  • InitialContext对象将用于查找无状态会话bean。

EJBTester.java

package com.iowiki.test;
import com.iowiki.stateless.LibraryPersistentBeanRemote;
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.List;
import java.util.Properties;
import javax.naming.InitialContext;
import javax.naming.NamingException;
public class EJBTester {
   BufferedReader brConsoleReader = null; 
   Properties props;
   InitialContext ctx;
   {
      props = new Properties();
      try {
         props.load(new FileInputStream("jndi.properties"));
      } catch (IOException ex) {
         ex.printStackTrace();
      }
      try {
         ctx = new InitialContext(props);            
      } catch (NamingException ex) {
         ex.printStackTrace();
      }
      brConsoleReader = 
      new BufferedReader(new InputStreamReader(System.in));
   }
   public static void main(String[] args) {
      EJBTester ejbTester = new EJBTester();
      ejbTester.testEntityEjb();
   }
   private void showGUI(){
      System.out.println("**********************");
      System.out.println("Welcome to Book Store");
      System.out.println("**********************");
      System.out.print("Options \n1. Add Book\n2. Exit \nEnter Choice: ");
   }
   private void testEntityEjb(){
      try {
         int choice = 1; 
         LibraryPersistentBeanRemote libraryBean =
         LibraryPersistentBeanRemote)
         ctx.lookup("LibraryPersistentBean/remote");
         while (choice != 2) {
            String bookName;
            showGUI();
            String strChoice = brConsoleReader.readLine();
            choice = Integer.parseInt(strChoice);
            if (choice == 1) {
               System.out.print("Enter book name: ");
               bookName = brConsoleReader.readLine();
               Book book = new Book();
               book.setName(bookName);
               libraryBean.addBook(book);          
            } else if (choice == 2) {
               break;
            }
         }
         List<Book> booksList = libraryBean.getBooks();
         System.out.println("Book(s) entered so far: " + booksList.size());
         int i = 0;
         for (Book book:booksList) {
            System.out.println((i+1)+". " + book.getName());
            i++;
         }           
      } catch (Exception e) {
         System.out.println(e.getMessage());
         e.printStackTrace();
      }finally {
         try {
            if(brConsoleReader !=null){
               brConsoleReader.close();
            }
         } catch (IOException ex) {
            System.out.println(ex.getMessage());
         }
      }
   }
}

EJBTester执行以下任务 -

  • 从jndi.properties加载属性并初始化InitialContext对象。

  • 在testStatefulEjb()方法中,使用名称“LibraryStatelessSessionBean/remote”完成jndi查找以获取远程业务对象(有状态ejb)。

  • 然后向用户显示库存储用户界面,并要求他/她输入选项。

  • 如果用户输入1,系统将询问书名并使用无状态会话bean addBook()方法保存书籍。 会话Bean通过EntityManager调用将数据库保存在数据库中。

  • 如果用户输入2,系统将使用无状态会话bean getBooks()方法检索书籍并退出。

  • 然后使用名称“LibraryStatelessSessionBean/remote”完成另一个jndi查找,以再次获取远程业务对象(有状态EJB)并完成书籍列表。

运行客户端以访问EJB

在项目资源管理器中找到EJBTester.java。 右键单击EJBTester类并选择run file

在Netbeans控制台中验证以下输出。

run:
**********************
Welcome to Book Store
**********************
Options 
1. Add Book
2. Exit 
Enter Choice: 1
Enter book name: Learn Testing
**********************
Welcome to Book Store
**********************
Options 
1. Add Book
2. Exit 
Enter Choice: 2
Book(s) entered so far: 1
1. learn Testing
BUILD SUCCESSFUL (total time: 15 seconds)

EJB - Exception Handling

EJB是企业应用程序的一部分,通常基于分布式环境。 因此,除了可能发生的正常异常之外,还可能存在通信故障,安全权限,服务器故障等异常。

EJB容器以两种方式考虑异常 -

  • Application Exception - 如果违反业务规则或在执行业务逻辑时发生异常。

  • System Exception - 任何异常,不是由业务逻辑或业务代码引起的。 RuntimeException,RemoteException是SystemException。 例如,EJB查找期间出错。 RuntimeException,RemoteException是SystemException。

EJB容器如何处理异常?

发生Application Exception时,EJB容器会拦截异常,但会将其返回给客户端。 它不会回滚事务,除非它在代码中由EJBContext.setRollBackOnly()方法指定。 在Application Exception的情况下,EJB容器不会包装异常。

发生System Exception时,EJB容器拦截异常,回滚事务并启动清理任务。 它将异常包装到RemoteException中并将其抛出到客户端。

处理应用程序异常

应用程序异常通常在Session EJB方法中抛出,因为这些是负责执行业务逻辑的方法。 应该在业务方法的throws子句中声明应用程序异常,并且应该抛出以防业务逻辑失败。

@Stateless
public class LibraryPersistentBean implements LibraryPersistentBeanRemote {
   ...
   public List<Book> getBooks() throws NoBookAvailableException {        
      List<Book> books = 
         entityManager.createQuery("From Books").getResultList();
      if(books.size == 0)
		throw NoBookAvailableException
           ("No Book available in library.");
      return books;
   }
   ...
}

处理系统异常

系统异常可能随时发生,如命名查找失败,获取数据时发生sql错误。 在这种情况下,应将此类异常包装在EJBException下并抛回客户端。

@Stateless
public class LibraryPersistentBean implements LibraryPersistentBeanRemote {
   ...
   public List<Book> getBooks() {   
      try {
         List<Book> books = 
            entityManager.createQuery("From Books").getResultList();
      } catch (CreateException ce){
         throw (EJBException) new EJBException(ce).initCause(ce);
      } catch (SqlException se){
         throw (EJBException) new EJBException(se).initCause(se);    
      }	  
      return books;
   }
   ...
}

在客户端,处理EJBException。

public class EJBTester {
   private void testEntityEjb(){
   ...
   try{
      LibraryPersistentBeanRemote libraryBean =
      LibraryPersistentBeanRemote)ctx.lookup("LibraryPersistentBean/remote");
      List<Book> booksList = libraryBean.getBooks();
   } catch(EJBException e) {
      Exception ne = (Exception) e.getCause();
      if(ne.getClass().getName().equals("SqlException")){
         System.out.println("Database error: "+ e.getMessage());
      }
   }
   ...
   }
}

EJB - Web Services

EJB 3.0提供了将会话EJB公开为Web服务的选项。 @WebService注释用于将类标记为Web服务端点,@ WebMethod用于将方法作为Web方法公开给客户端。

@Stateless
@WebService(serviceName="LibraryService")
public class LibraryPersistentBean implements LibraryPersistentBeanRemote {
   ...
   @WebMethod(operationName="getBooks")
   public List<book> getBooks()  {    
      return entityManager.createQuery("From Books").getResultList();
   }
   ...
}
</book>

例子 Example Application

让我们创建一个测试EJB应用程序来测试EJB 3.0中的blob/clob支持。

描述
1 在EJB-Create Application章节中解释,在com.iowiki.entity包下创建一个名为EjbComponent的项目。 请使用在EJB - Persistence章节中创建的项目,以便本章了解EJB概念中的clob/blob对象。
2 在com.iowiki.stateless包下创建LibraryPersistentBean.java。 使用EJB - Persistence章节作为参考。 保持其余文件不变。
3 清理并构建应用程序以确保业务逻辑按照要求运行。
4 最后,在JBoss Application Server上以jar文件的形式部署应用程序。 如果JBoss Application服务器尚未启动,它将自动启动。

LibraryPersistentBean.java

package com.iowiki.stateless;
import com.iowiki.entity.Book;
import java.util.List;
import javax.ejb.Stateless;
import javax.jws.WebMethod;
import javax.jws.WebService;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
@Stateless
@WebService(serviceName="LibraryService")
public class LibraryPersistentBean implements LibraryPersistentBeanRemote {
   public LibraryPersistentBean(){
   }
   @PersistenceContext(unitName="EjbComponentPU")
   private EntityManager entityManager;         
   public void addBook(Book book) {
      entityManager.persist(book);
   }    
   @WebMethod(operationName="getBooks")
   public List <Book> getBooks() {
      return entityManager.createQuery("From Book").getResultList();
   }
}

JBoss应用服务器日志输出

10:51:37,271 INFO  [EJBContainer] STARTED EJB: com.iowiki.stateless.LibraryPersistentBean ejbName: LibraryPersistentBean
10:51:37,287 INFO  [JndiSessionRegistrarBase] Binding the following Entries in Global JNDI:
	LibraryPersistentBean/remote - EJB3.x Default Remote Business Interface
	LibraryPersistentBean/remote-com.iowiki.stateless.LibraryPersistentBeanRemote - EJB3.x Remote Business Interface
10:51:37,349 INFO  [EJBContainer] STARTED EJB: com.tuturialspoint.messagebean.LibraryMessageBean ejbName: BookMessageHandler
10:51:37,443 INFO  [DefaultEndpointRegistry] register: jboss.ws:context=EjbComponent,endpoint=LibraryPersistentBean
10:51:38,191 INFO  [WSDLFilePublisher] WSDL published to: file:/D:/Jboss-5.0.1/server/default/data/wsdl/EjbComponent.jar/
LibraryService3853081455302946642.wsdl

创建客户端以作为Web服务访问EJB

在NetBeans IDE中,选择,File 》 New Project 》 。选择类别下的项目类型, Java ,项目类型为Java Application 。 单击“ Next 》按钮。输入项目名称和位置。 单击“ Finish 》按钮。 我们选择了名称作为EJBWebServiceClient。

在Project explorer窗口中右键单击项目名称。 选择“ New 》 WebService Client

WSDL客户端

使用compile选项卡中的“ Add Project按钮Add Project先前在WSDL和客户端位置下创建的EJB组件项目的LibraryPersistentBean。

Web服务Bean

单击完成按钮。 验证项目资源管理器中的以下结构。

Web服务Bean

Create EJBWebServiceClient.java

package ejbwebserviceclient;
public class EJBWebServiceClient {
   public static void main(String[] args) {   
   }
}

选择Web Service getBooks web方法,如下图所示,并将其拖到EJBWebServiceClient的代码窗口。

Web服务方法拖动

您将看到类似于下面所示的输出。

拖动Web服务方法

更新EJBWebServiceClient代码以使用此方法。

package ejbwebserviceclient;
public class EJBWebServiceClient {
   public static void main(String[] args) {
      for(com.iowiki.stateless.Book book:getBooks()){
         System.out.println(book.getName());
      }       
   }
   private static java.util.List
   <com.iowiki.stateless.Book> getBooks() {
      com.iowiki.stateless.LibraryService service = 
         new com.iowiki.stateless.LibraryService();
      com.iowiki.stateless.LibraryPersistentBean port = 
         service.getLibraryPersistentBeanPort();
      return port.getBooks();
   }      
}

运行客户端

在Project explorer窗口中右键单击项目名称。 选择Run 。 Netbeans将构建客户端并运行它。 验证以下输出。

ant -f D:\\SVN\\EJBWebServiceClient run
init:
Deleting: D:\SVN\EJBWebServiceClient\build\built-jar.properties
deps-jar:
Updating property file: D:\SVN\EJBWebServiceClient\build\built-jar.properties
wsimport-init:
wsimport-client-LibraryPersistentBean:
files are up to date
classLoader = java.net.URLClassLoader@4ce46c
SharedSecrets.getJavaNetAccess()=java.net.URLClassLoader$7@182cdac
wsimport-client-generate:
Compiling 1 source file to D:\SVN\EJBWebServiceClient\build\classes
compile:
run:
learn java
Learn Spring
learn JSF
Learn HTML
Learn JBoss
Learn EJB
Learn Hibernate
Learn IBatis
Times Now
learn html5
Learn images
Learn Testing
Forbes
test1
BUILD SUCCESSFUL (total time: 1 second)

EJB - Packaging Applications

使用EJB 3.0的打包应用程序的要求与J2EE平台的要求类似。 EJB组件作为jar文件打包到模块中,并作为ear文件打包到应用程序企业归档中。

任何企业应用程序主要有三个组件 -

  • jar - Java Application aRchive,包含EJB模块,EJB客户端模块和实用程序模块。

  • war - Web应用程序aRchive,包含Web模块。

  • ear - 企业应用程序aRchive,包含罐子和战争模块。

耳

在NetBeans中,创建,开发,打包和部署J2EE应用程序非常容易。

在NetBeans IDE中,选择File 》 New Project 》在类别下选择项目类型, Java EE ,项目类型作为Enterprise Application 。 单击“ Next 》按钮。 输入项目名称和位置。 单击“ Finish 》按钮。 我们选择了名称为EnterpriseApplicaton。

选择服务器和设置。 使用提供的默认名称检查Create EJB ModuleCreate Web Application Module 。 单击完成按钮。 NetBeans将在项目窗口中创建以下结构。

EAR项目

右键单击项目资源Enterprise Application中的Project Enterprise Application ,然后选择Build。

ant -f D:\\SVN\\EnterpriseApplication dist
pre-init:
init-private:
init-userdir:
init-user:
init-project:
do-init:
post-init:
init-check:
init:
deps-jar:
deps-j2ee-archive:
EnterpriseApplication-ejb.init:
EnterpriseApplication-ejb.deps-jar:
EnterpriseApplication-ejb.compile:
EnterpriseApplication-ejb.library-inclusion-in-manifest:
Building jar: D:\SVN\EnterpriseApplication\EnterpriseApplication-ejb\dist\EnterpriseApplication-ejb.jar
EnterpriseApplication-ejb.dist-ear:
EnterpriseApplication-war.init:
EnterpriseApplication-war.deps-module-jar:
EnterpriseApplication-war.deps-ear-jar:
EnterpriseApplication-ejb.init:
EnterpriseApplication-ejb.deps-jar:
EnterpriseApplication-ejb.compile:
EnterpriseApplication-ejb.library-inclusion-in-manifest:
EnterpriseApplication-ejb.dist-ear:
EnterpriseApplication-war.deps-jar:
EnterpriseApplication-war.library-inclusion-in-archive:
EnterpriseApplication-war.library-inclusion-in-manifest:
EnterpriseApplication-war.compile:
EnterpriseApplication-war.compile-jsps:
EnterpriseApplication-war.do-ear-dist:
Building jar: D:\SVN\EnterpriseApplication\EnterpriseApplication-war\dist\EnterpriseApplication-war.war
EnterpriseApplication-war.dist-ear:
pre-pre-compile:
pre-compile:
Copying 1 file to D:\SVN\EnterpriseApplication\build
Copying 1 file to D:\SVN\EnterpriseApplication\build
do-compile:
post-compile:
compile:
pre-dist:
do-dist-without-manifest:
do-dist-with-manifest:
Building jar: D:\SVN\EnterpriseApplication\dist\EnterpriseApplication.ear
post-dist:
dist:
BUILD SUCCESSFUL (total time: 1 second)

在这里你可以看到,Netbeans首先准备Jar,然后战争,最后,携带jar和war,文件的耳朵文件。 每个jar,war和ear文件都带有一个meta-inf文件夹,根据J2EE规范获得元数据。

↑回到顶部↑
WIKI教程 @2018