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 | 文件名 |
---|---|
Windows | jboss-5.1.0.GA-jdk6.zip |
Linux | jboss-5.1.0.GA-src.tar.gz |
Mac | jboss-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中配置服务器。
配置完所有内容后,您将看到以下屏幕。
第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 》 。 您将看到以下屏幕
在类别Java EE下选择项目类型,将项目类型选择为EJB Module 。 单击“ Next 》按钮。 您将看到以下屏幕。
输入项目名称和位置。 单击“ Next 》按钮。 您将看到以下屏幕。
选择Server作为JBoss Application Server 。 单击Finish按钮。 您将看到NetBeans创建的以下项目。
创建一个示例EJB
要创建一个简单的EJB,我们将使用NetBeans“新建”向导。 在下面给出的示例中,我们将在EjbComponent项目下创建名为librarySessionBean的无状态EJB类。
在项目资源管理器窗口中选择项目EjbComponent并右键单击它。 选择, New 》 Session Bean 。 您将看到New Session 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。
步 | 描述 |
---|---|
1 | 在EJB - Create Application章节中解释,在com.iowiki.stateless包下创建一个名为EjbComponent的项目。 您还可以使用在EJB - Create Application的项目EJB - Create Application章节,以便本章了解无状态EJB概念。 |
2 | 按照EJB - Create Application章节中的说明创建LibrarySessionBean.java和LibrarySessionBeanRemote 。 保持其余文件不变。 |
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。
步 | 描述 |
---|---|
1 | 在EJB − Create Application章节中解释,在com.iowiki.stateful包下创建一个名为EjbComponent的项目。 您还可以使用在EJB - Create Application的项目EJB - Create Application章节,以便本章了解有状态EJB概念。 |
2 | 按照EJB − Create Application章节中的说明创建LibraryStatefulSessionBean.java和LibraryStatefulSessionBeanRemote 。 保持其余文件不变。 |
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持久性机制。
步 | 描述 |
---|---|
1 | 在EJB - Create Application章节中解释,在com.iowiki.entity包下创建一个名为EjbComponent的项目。 您还可以使用在EJB - Create Application的项目EJB - Create Application章节,以便本章了解EJB持久性概念。 |
2 | 在Book.java包下创建Book.java com.iowiki.entity如下所示进行修改。 |
3 | 按照EJB - Create Application章节中的说明创建LibraryPersistentBean.java和LibraryPersistentBeanRemote ,并按如下所示进行修改。 |
4 | 在EjbComponent > 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。
步 | 描述 |
---|---|
1 | 在EJB - Create Application章节中解释,在com.iowiki.entity包下创建一个名为EjbComponent的项目。 您还可以使用在EJB - Create Application的项目EJB - Create Application章节,以便本章了解EJB持久性概念。 |
2 | 在EJB-Persistence章节中创建的包Book.java下创建Book.java 。 |
3 | 创建在EJB-Persistence章节中创建的LibraryPersistentBean.java和LibraryPersistentBeanRemote 。 |
4 | 在EjbComponent > setup文件夹中创建jboss-ds.xml ,在EjbComponent > src > conf文件夹中创建persistence.xml 。 这些文件夹可以在EJB-Persistence章节中创建的Netbeans文件选项卡中看到。 |
5 | 在com.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
|
2 | javax.ejb.Stateful | 指定给定的EJB类是有状态会话Bean。 Attributes
|
3 | javax.ejb.MessageDrivenBean | 指定给定的EJB类是消息驱动的bean。 Attributes
|
4 | javax.ejb.EJB | 用于将依赖项指定或注入到另一个EJB中作为EJB实例。 Attributes
|
5 | javax.ejb.Local | 用于指定会话bean的本地接口。 此本地接口声明会话bean的业务方法(可以是无状态或有状态的)。 此接口用于将业务方法公开给本地客户端,本地客户端在与EJB相同的部署/应用程序中运行。 Attributes
|
6 | javax.ejb.Remote | 用于指定会话bean的远程接口。 此远程接口说明会话bean的业务方法(可以是无状态或有状态的)。 此接口用于将业务方法公开给远程客户端,这些客户端作为EJB在不同的部署/应用程序中运行。 Attributes
|
7 | javax.ejb.Activation ConfigProperty | 用于指定消息驱动Bean所需的属性。 例如,终点,目的地,消息选择器等。 此批注作为参数传递给javax.ejb.MessageDrivenBean批注的activationConfig属性。 Attributes
|
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中的各种回调。
步 | 描述 |
---|---|
1 | 在EJB - Create Application章节中解释,在com.iowiki.stateless包下创建一个名为EjbComponent的项目。 您还可以使用在EJB - Persistence章节中创建的项目,如本章所述,向EJB添加各种回调。 |
2 | 按照EJB - Create Application章节中的说明创建LibrarySessionBean.java和LibrarySessionBeanRemote 。 保持其余文件不变。 |
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。
步 | 描述 |
---|---|
1 | 在EJB - Create Application章节中解释,在com.iowiki.timer包下创建一个名为EjbComponent的项目。 |
2 | 按照EJB - Create Application章节中的说明创建TimerSessionBean.java和TimerSessionBeanRemote 。 保持其余文件不变。 |
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中的依赖注入服务。
步 | 描述 |
---|---|
1 | 在EJB - 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。
步 | 描述 |
---|---|
1 | 在EJB - Create Application章节中解释,在com.iowiki.interceptor包下创建一个名为EjbComponent的项目。 您还可以使用在EJB - Create Application的项目EJB - Create Application本章的EJB - Create Application章节来理解截获的EJB概念。 |
2 | 在EJB - Create Application章节中解释,在com.iowiki.interceptor包下创建LibraryBean.java和LibraryBeanRemote 。 保持其余文件不变。 |
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中的嵌入对象。
步 | 描述 |
---|---|
1 | 在EJB - Create Application章节中解释,在com.iowiki.entity包下创建一个名为EjbComponent的项目。 请使用在EJB - Persistence章节中创建的项目本章来理解EJB概念中的嵌入对象。 |
2 | 按照EJB - Create Application章节中的说明,在com.iowiki.entity包下创建Publisher.java 。 保持其余文件不变。 |
3 | 在com.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支持。
步 | 描述 |
---|---|
1 | 在EJB - Create Application章节中解释,在com.iowiki.entity包下创建一个名为EjbComponent的项目。 请使用在EJB - Persistence章节中创建的项目本章来理解ejb概念中的clob/blob对象。 |
2 | 在com.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与
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中的实体关系对象。
步 | 描述 |
---|---|
1 | 在EJB - Create Application章节中解释,在com.iowiki.entity包下创建一个名为EjbComponent的项目。 请使用在EJB - Persistence章节中创建的项目本章来理解EJB概念中的嵌入对象。 |
2 | 按照EJB - Create Application章节中的说明在Author.java包下创建Author.java 。 保持其余文件不变。 |
3 | 在com.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数据库访问机制。
步 | 描述 |
---|---|
1 | 在EJB - Create Application章节中解释,在com.iowiki.entity包下创建一个名为EjbComponent的项目。 您还可以使用在EJB - Create Application的项目EJB - Create Application章节,以便本章了解EJB数据访问概念。 |
2 | 在Book.java包下创建Book.java com.iowiki.entity如下所示进行修改。 |
3 | 按照EJB - Create Application章节中的说明创建LibraryPersistentBean.java和LibraryPersistentBeanRemote ,并按如下所示进行修改。 |
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数据库访问机制。
步 | 描述 |
---|---|
1 | 在EJB - Create Application章节中解释,在com.iowiki.entity包下创建一个名为EjbComponent的项目。 您还可以使用在EJB - Create Application的项目EJB - Create Application章节,以便本章了解EJB数据访问概念。 |
2 | 在Book.java包下创建Book.java com.iowiki.entity如下所示进行修改。 |
3 | 按照EJB - Create Application章节中的说明创建LibraryPersistentBean.java和LibraryPersistentBeanRemote ,并按如下所示进行修改。 |
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 。
使用compile选项卡中的“ Add Project按钮Add Project先前在WSDL和客户端位置下创建的EJB组件项目的LibraryPersistentBean。
单击完成按钮。 验证项目资源管理器中的以下结构。
Create EJBWebServiceClient.java
package ejbwebserviceclient;
public class EJBWebServiceClient {
public static void main(String[] args) {
}
}
选择Web Service getBooks web方法,如下图所示,并将其拖到EJBWebServiceClient的代码窗口。
您将看到类似于下面所示的输出。
更新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 Module和Create Web Application Module 。 单击完成按钮。 NetBeans将在项目窗口中创建以下结构。
右键单击项目资源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规范获得元数据。