我使用 eclipse 创建了一个 EJB 项目,并创建了 2 个类,如下所示。
package com.abhijit.ejbs;
import java.util.List;
import javax.ejb.Remote;
@Remote
public interface TestEJBRemote {
public void addElement(int a);
public void removeElement(int a);
public List getElements();
}
实际的 EJB 如下 -
package com.abhijit.ejbs;
import java.util.ArrayList;
import java.util.List;
import javax.ejb.LocalBean;
import javax.ejb.Stateful;
/**
* Session Bean implementation class TesEJB
*/
@Stateful
@LocalBean
public class TestEJB implements TestEJBRemote {
List <Integer> myList = new ArrayList<>();
/**
* Default constructor.
*/
public TestEJB() {
// TODO Auto-generated constructor stub
}
@Override
public void addElement(int a) {
myList.add(a);
}
@Override
public void removeElement(int a) {
myList.remove(a);
}
@Override
public List getElements() {
return myList;
}
}
然后,这个 EJB 部署在 JBoss AS 7 上,它运行时不会出现任何错误。我在控制台中看到此消息 -
**java:global/EJB1/TestEJB!com.abhijit.ejbs.TestEJBRemote
java:app/EJB1/TestEJB!com.abhijit.ejbs.TestEJBRemote
java:module/TestEJB!com.abhijit.ejbs.TestEJBRemote
java:jboss/exported/EJB1/TestEJB!com.abhijit.ejbs.TestEJBRemote
java:global/EJB1/TestEJB!com.abhijit.ejbs.TestEJB
java:app/EJB1/TestEJB!com.abhijit.ejbs.TestEJB
java:module/TestEJB!com.abhijit.ejbs.TestEJB**
现在,我正在创建一个第二个Eclipse Java项目,并编写一个简单的Java远程客户端代码,如下所示:
package com;
import java.util.Hashtable;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import com.abhijit.ejbs.TestEJB;
import com.abhijit.ejbs.TestEJBRemote;
public class EJBClient {
public static void main(String[] args) {
TestEJBRemote values;
try {
System.out.println("----");
final Hashtable<String, String> jndiProperties = new Hashtable();
jndiProperties.put(Context.URL_PKG_PREFIXES, "org.jboss.ejb.client.naming");
//tried with rmi: also .. not working....
jndiProperties.put(Context.PROVIDER_URL, "ejb://localhost:1099");
InitialContext ic = new InitialContext(jndiProperties);
values = (TestEJBRemote)ic.lookup("java:global/EJB1/TestEJB!com.abhijit.ejbs.TestEJB");
System.out.println("---" + values.getElements());
}
catch(Exception e) {
e.printStackTrace();
}
}
尝试在 lookup() 中使用各种组合,但是当我运行这个将在单独的 JVM 中运行的 java 客户端代码时,它不起作用..我收到此错误 -
javax.naming.NoInitialContextException: Need to specify class name in environment or system property, or as an applet parameter, or in an application resource file: java.naming.factory.initial
at javax.naming.spi.NamingManager.getInitialContext(Unknown Source)
at javax.naming.InitialContext.getDefaultInitCtx(Unknown Source)
at javax.naming.InitialContext.getURLOrDefaultInitCtx(Unknown Source)
at javax.naming.InitialContext.lookup(Unknown Source)
at com.EJBClient.main(EJBClient.java:25)
我确信这一定与 jndi 参数有关。但我不明白它是什么...
此解决方案适用于 Wildfly 8、9 和 10。
1. 添加所需的依赖项wildfly-ejb-client-bom
需要将依赖项wildfly-ejb-client-bom
添加到项目中。
如果您使用的是 maven,则可以将以下依赖项添加到您的pom
中。
<dependency>
<groupId>org.wildfly</groupId>
<artifactId>wildfly-ejb-client-bom</artifactId>
<version>10.1.0.Final</version>
<type>pom</type>
<scope>runtime</scope>
</dependency>
信息使用其他版本的野蝇 8 (8.2.1.Final
) 或 9 (9.0.2.Final
)。
2. 创建jboss-ejb-client.properties
将jboss-ejb-client.properties
添加到resources
文件夹中,并添加以下内容。
remote.connectionprovider.create.options.org.xnio.Options.SSL_ENABLED=false
remote.connections=default
remote.connection.default.host=localhost
remote.connection.default.port = 8080
remote.connection.default.connect.options.org.xnio.Options.SASL_POLICY_NOANONYMOUS=false
3. 创建初始上下文
您需要按如下方式创建初始上下文。
final Hashtable<String, String> jndiProperties = new Hashtable<>();
jndiProperties.put(Context.URL_PKG_PREFIXES, "org.jboss.ejb.client.naming");
final Context context = new InitialContext(jndiProperties);
4. 查找远程业务界面
最后,您可以查找有状态会话 Bean。
TestEJBRemote remote = (TestEJBRemote) context.lookup("ejb:/EJB1/TestEJB!" + TestEJBRemote.class.getName() + "?stateful");
如果要查找无状态的 bean,则必须删除?stateful
。
不幸的是,最新的野蝇文档一团糟,它们没有提供有效的解决方案。但是你可以在 ejb-remote 下找到一个工作 hello world 示例:远程 EJB 客户端示例。
您尝试连接的方式是错误的。
以下应该是连接到远程 ejb 的格式:
// Create a look up string name
String name = "ejb:" + appName + "/" + moduleName + "/" + distinctName
+ "/" + beanName + "!" + interfaceName;
我为SO文档贡献了以下内容。
使用 JBoss AS 7.1 设置 EJB
1. 概述
在本文中,我们将讨论如何开始使用Enterprise JavaBeans(EJB)。我们将使用 JBoss AS 7.1.1.Final,但您可以自由使用您选择的任何服务器。
2. Bean 的 Maven 依赖项
为了使用 EJB,请确保将最新版本添加到 pom.xml 文件的依赖项部分:
<dependency>
<groupId>org.jboss.spec.javax.ejb</groupId>
<artifactId>jboss-ejb-api_3.2_spec</artifactId>
<version>1.0.0.Final</version>
</dependency>
请确保正确添加 JBoss 依赖项,因为我们将在本教程中使用 JBoss 作为我们的应用程序服务器。 在本教程的后面部分,我们将详细讨论如何为项目设置 maven 构建。
3. EJB 远程
让我们首先创建名为 HelloWorldRemote 的 Bean 接口。
public interface HelloWorldRemote {
public String getHelloWorld();
}
现在我们将实现上述接口并将其命名为HelloWorldBean
。
@Stateless
public class HelloWorldBean implements HelloWorldRemote {
public HelloWorldBean() {
}
@Override
public String getHelloWorld(){
return ("Hello World");
}
}
请注意类声明顶部的@Stateless
表示法。它表示无状态会话 Bean。
4. 远程 Bean 的 Maven 设置
在本节中,我们将讨论如何设置 maven 以在服务器上构建和运行应用程序。
让我们一一看一下插件。
4.1. 编译器插件
maven-compiler-plugin 用于编译我们项目的源代码。
在这里,我们使用了插件的 2.3.1 版本,在配置下将源和目标 JDK 设置为 1.7。
我们已将这些设置定义为 tag 中的属性,并通过 ${property} 引用它。
<version.compiler.plugin>2.3.1</version.compiler.plugin>
<!-- maven-compiler-plugin -->
<maven.compiler.target>1.7</maven.compiler.target>
<maven.compiler.source>1.7</maven.compiler.source>
4.2 EJB 插件
该插件生成 Bean 文件以及关联的客户端 jar。
我们已将 ejb 版本指定为 3.2,并且 generateClient 属性设置为 true 以生成客户端。
4.3 在 JBoss 中部署
jboss-as-maven-plugin 用于在 JBoss AS 7 中部署、重新部署、取消部署或运行应用程序。
在此配置中,我们指定与项目构建文件名相同的构建文件名,在我们的例子中,默认情况下为 artifactid-versionejb-remote-1.0-SNAPSHOT
。
4.4 EJB 所需的 Maven 依赖
jboss-javaee-6.0 定义了我们要使用的 JBoss Java EE 6 API 版本。
JBoss 分发了一套完整的 Java EE 6 API,包括物料清单 (BOM)。
BOM 指定项目堆栈(或集合)的版本。我们在标记中指定它,以便我们始终获得正确版本的工件。此依赖项的类型本身是包含所需依赖项的 pom。
<dependency>
<groupId>org.jboss.spec</groupId>
<artifactId>jboss-javaee-6.0</artifactId>
<version>${version.org.jboss.spec.jboss.javaee.6.0}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
4.5 注释
以下内容将获取注释依赖项:
<dependency>
<groupId>org.jboss.spec.javax.annotation</groupId>
<artifactId>jboss-annotations-api_1.1_spec</artifactId>
<scope>provided</scope>
</dependency>
4.6 EJB 版本 3.2
在下面的代码中,我们得到了最新版本的规范:
<dependency>
<groupId>org.jboss.spec.javax.ejb</groupId>
<artifactId>jboss-ejb-api_3.2_spec</artifactId>
<version>1.0.0.Final</version>
</dependency>
要在 JBoss 服务器中运行上述项目,我们需要首先运行:
mvn clean install
然后我们需要通过运行以下 maven 命令将其部署到正在运行的 JBoss 服务器上:
jboss-as:deploy
现在你应该看到 jar 文件正在部署在 jboss 服务器中。
或者,可以从项目中的目标文件夹复制可用的 jar,并将其粘贴到服务器的 Web app 文件夹中。
5. 设置客户端项目
创建远程 Bean 后,我们应该通过创建客户端来测试已部署的 Bean。
首先,让我们讨论一下该项目的 maven 设置。
5.1 使用的Maven插件
maven-compiler-plugin 用于编译项目的源代码。
我们为源类和目标类指定了 jdk 1.7 版本。
我们的客户端是一个Java程序,为了运行它,我们使用有助于执行系统和Java程序的exec-maven-plugin
。我们需要指定可执行文件(即.java),类路径和java类(com.baeldung.ejb.client.Client)。
类路径留空,因为插件包含基于提供的依赖项的必要类路径参数。
5.2 EJB3 客户端的 Maven 依赖
为了运行 EJB3 客户端,我们需要包含以下依赖项。
我们依靠此应用程序的 EJB 远程业务接口来运行客户端。因此,我们需要指定 ejb 客户端 jar 依赖项。值为"ejb-client"的标记用于指定此项目对 EJB 客户端 jar 的依赖关系。
<dependency>
<groupId>com.theopentutorials.ejb3</groupId>
<artifactId>ejbmavendemo</artifactId>
<type>ejb-client</type>
<version>${project.version}</version>
</dependency>
依赖关系jboss-transaction-api_1.1_spec
、jboss-ejb-api_3.1_spec
、jboss-ejb-client
、xnio-api
、xnio-nio
、jboss-remoting
、jboss-sasl
、jboss-marshalling-river
具有运行时的作用域,因为这些是必需的运行时,而不是在编译时。
依赖关系jboss-javaee-6.0和jboss-as-ejb-client-bom在 dependencyManagement 下具有导入范围。这用于将来自远程 POM 的依赖项管理信息包含在当前项目中。这些远程 POM 由 JBoss 提供,其中包含运行客户端所需的依赖项。
5.3 JBoss EJB 客户端属性
在"src/main/resources"下创建一个文件,并将其命名为jboss-ejb-client.properties。
remote.connectionprovider.create.options.org.xnio.Options.SSL_ENABLED=false
remote.connections=default
remote.connection.default.host=localhost
remote.connection.default.port = 4447
remote.connection.default.connect.options.org.xnio.Options.SASL_POLICY_NOANONYMOUS=false
6. 创建客户端类
首先,我们创建一个 ClientUtility 类:
public class ClientUtility {
private static Context initialContext;
private static final String PKG_INTERFACES = "org.jboss.ejb.client.naming";
public static Context getInitialContext() throws NamingException {
if (initialContext == null) {
Properties properties = new Properties();
properties.put(Context.URL_PKG_PREFIXES, PKG_INTERFACES);
initialContext = new InitialContext(properties);
}
return initialContext;
}
}
现在让我们创建实际的 Client 类,该类将使用我们在服务器中部署的 bean:
public class Client {
//The lookup method to get the EJB name
private static HelloWorldRemote doLookup() {
Context context = null;
HelloWorldRemote bean = null;
try {
// 1. Obtaining Context
context = ClientUtility.getInitialContext();
// 2. Generate JNDI Lookup name
String lookupName = getLookupName();
// 3. Lookup and cast
bean = (HelloWorldRemote) context.lookup(lookupName);
} catch (NamingException e) {
e.printStackTrace();
}
return bean;
}
private static String getLookupName() {
// The app name is the EAR name of the deployed EJB without .ear suffix.
// Since we haven't deployed the application as a .ear, the app name for
// us will be an empty string
String appName = "";
// The module name is the JAR name of the deployed EJB without the .jar
// suffix.
String moduleName = "ejb-remote-0.0.1-SNAPSHOT";
// AS7 allows each deployment to have an (optional) distinct name. This
// can be an empty string if distinct name is not specified.
String distinctName = "";
// The EJB bean implementation class name
String beanName = "HelloWorldBean";
// Fully qualified remote interface name
final String interfaceName = "com.baeldung.ejb.tutorial.HelloWorldRemote";
// Create a look up string name
String name = "ejb:" + appName + "/" + moduleName + "/" + distinctName
+ "/" + beanName + "!" + interfaceName;
return name;
}
}
客户端类使用 Bean 并输出结果。
7. 结论
因此,我们创建了一个 EJB 服务器和一个使用该服务的客户端。该项目可以在任何应用程序服务器上运行。