Guide to EJB Set-up – EJB设置指南

最后修改: 2017年 1月 23日

中文/混合/英文(键盘快捷键:t)

1. Overview

1.概述

In this article, we’re going to discuss how to get started with Enterprise JavaBean (EJB) development.

在这篇文章中,我们将讨论如何开始进行企业JavaBean(EJB)开发。

Enterprise JavaBeans are used for developing scalable, distributed, server-side components and typically encapsulate the business logic of the application.

企业JavaBean用于开发可扩展的、分布式的服务器端组件,通常封装了应用程序的业务逻辑。

We’ll use WildFly 10.1.0 as our preferred server solution, however, you are free to use any Java Enterprise application server of your choice.

我们将使用WildFly 10.1.0作为我们的首选服务器解决方案,然而,你可以自由地使用你选择的任何Java企业应用服务器。

2. Setup

2.设置

Let’s start by discussing the Maven dependencies required for EJB 3.2 development and how to configure the WildFly application server using either the Maven Cargo plugin or manually.

我们先来讨论一下EJB 3.2开发所需的Maven依赖性,以及如何使用Maven Cargo插件或手动配置WildFly应用服务器。

2.1. Maven Dependency

2.1.Maven的依赖性

In order to use EJB 3.2, make sure you add the latest version to the dependencies section of your pom.xml file:

为了使用EJB 3.2,确保你在pom.xml文件的dependencies部分添加最新版本。

<dependency>
    <groupId>javax</groupId>
    <artifactId>javaee-api</artifactId>
    <version>7.0</version>
    <scope>provided</scope>
</dependency>
You will find the latest dependency in the Maven Repository. This dependency ensures that all Java EE 7 APIs are available during compile time. The provided scope ensures that once deployed, the dependency will be provided by the container where it has been deployed.

2.2. WildFly Setup With Maven Cargo

2.2.使用Maven Cargo的WildFly设置

Let’s talk about how to use the Maven Cargo plugin to setup the server.

我们来谈谈如何使用Maven Cargo插件来设置服务器。

Here is the code for the Maven profile that provisions the WildFly server:

以下是提供WildFly服务器的Maven配置文件的代码。

<profile>
    <id>wildfly-standalone</id>
    <build>
        <plugins>
            <plugin>
                <groupId>org.codehaus.cargo</groupId>
                <artifactId>cargo-maven2-plugin</artifactId>
                <version>${cargo-maven2-plugin.version</version>
                <configuration>
                    <container>
                        <containerId>wildfly10x</containerId>
                        <zipUrlInstaller>
                            <url>
                                http://download.jboss.org/
                                  wildfly/10.1.0.Final/
                                    wildfly-10.1.0.Final.zip
                            </url>
                        </zipUrlInstaller>
                    </container>
                    <configuration>
                        <properties>
                            <cargo.hostname>127.0.0.0</cargo.hostname>
                            <cargo.jboss.management-http.port>
                                9990
                            </cargo.jboss.management-http.port>
                            <cargo.servlet.users>
                                testUser:admin1234!
                            </cargo.servlet.users>
                        </properties>
                    </configuration>
                </configuration>
            </plugin>
        </plugins>
    </build>
</profile>

We use the plugin to download the WildFly 10.1 zip directly from the WildFly’s website. Which is then configured, by making sure that the hostname is 127.0.0.1 and setting the port to 9990.

我们使用该插件直接从WildFly的网站上下载WildFly 10.1zip。然后进行配置,确保主机名127.0.0.1,并将端口设置为9990。

Then we create a test user, by using the cargo.servlet.users property, with the user id testUser and the password admin1234!.

然后,我们通过使用cargo.servlet.users属性,创建一个测试用户,用户ID为testUser,密码为admin1234!.

Now that configuration of the plugin is completed we should be able to call a Maven target and have the server download, installed, launched and the application deployed.

现在插件的配置已经完成,我们应该可以调用Maven目标,让服务器下载、安装、启动并部署应用程序。

To do this, navigate to the ejb-remote directory and run the following command:

要做到这一点,请导航到ejb-remote目录并运行以下命令。

mvn clean package cargo:run

When you run this command for the first time, it will download the WildFly 10.1 zip file, extract it and execute the installation and then launch it. It will also add the test user discussed above. Any further executions will not download the zip file again.

当你第一次运行这个命令时,它将下载WildFly 10.1 zip文件,解压并执行安装,然后启动它。它还会添加上面讨论的测试用户。任何进一步的执行都不会再次下载该压缩文件。

2.3. Manual Setup of WildFly

2.3.WildFly的手动设置

In order to setup WildFly manually, you must download the installation zip file yourself from the wildfly.org website. The following steps are a high-level view of the WildFly server setup process:

为了手动设置 WildFly,您必须自己从wildfly.org网站下载安装 zip 文件。以下步骤是 WildFly 服务器设置过程的高级视图。

After downloading and unzipping the file’s contents to the location where you want to install the server, configure the following environment variables:

在下载并解压文件内容到你要安装服务器的位置后,配置以下环境变量。

JBOSS_HOME=/Users/$USER/../wildfly.x.x.Final
JAVA_HOME=`/usr/libexec/java_home -v 1.8`

Then in the bin directory, run the ./standalone.sh for Linux based operating systems or ./standalone.bat for Windows.

然后在bin目录下,运行基于Linux操作系统的./standalone.sh或Windows的./standalone.bat

After this, you will have to add a user. This user will be used to connect to the remote EJB bean. To find out how to add a user you should take a look at the ‘add a user’ documentation.

之后,你将不得不添加一个用户。这个用户将被用来连接到远程EJB Bean。要了解如何添加用户,你应该看一下‘添加用户’文档

For detailed setup instructions please visit WildFly’s Getting Started documentation.

有关详细的设置说明,请访问WildFly的入门文档

The project POM has been configured to work with the Cargo plugin and manual server configuration by setting two profiles. By default, the Cargo plugin is selected. However to deploy the application to an already installed, configured and running Wildfly server execute the following command in the ejb-remote directory:

项目的POM已经被配置为与Cargo插件和手动服务器配置一起工作,通过设置两个配置文件。默认情况下,Cargo插件被选中。然而,为了将应用程序部署到已经安装、配置和运行的Wildfly服务器上,在ejb-remote目录下执行以下命令。

mvn clean install wildfly:deploy -Pwildfly-runtime

3. Remote vs Local

3.远程本地

A business interface for a bean can be either local or remote.

一个bean的业务接口可以是本地的远程的

A @Local annotated bean can only be accessed if it is in the same application as the bean that makes the invocation, i.e. if they reside in the same .ear or .war.

只有当 @Local 注释的 bean 与进行调用的 bean 在同一个应用程序中时,即如果它们位于同一个 .ear.war 中,才能被访问。

A @Remote annotated bean can be accessed from a different application, i.e. an application residing in a different JVM or application server.

一个 @Remote 注释的Bean可以从不同的应用程序中被访问,即驻留在不同JVM或应用程序服务器中的应用程序。

There are some important points to keep in mind when designing a solution that includes EJBs:

在设计包含EJB的解决方案时,有一些要点需要注意:

  • The java.io.Serializable, java.io.Externalizable and interfaces defined by the javax.ejb package are always excluded when a bean is declared with @Local or @Remote
  • If a bean class is remote, then all implemented interfaces are to be remote
  • If a bean class contains no annotation or if the @Local annotation is specified, then all implemented interfaces are assumed to be local
  • Any interface that is explicitly defined for a bean which contains no interface must be declared as @Local
  • The EJB 3.2 release tends to provide more granularity for situations where local and remote interfaces need to explicitly defined

4. Creating the Remote EJB

4.创建Remote EJB

Let’s first create the bean’s interface and call it HelloWorld:

让我们首先创建Bean的接口并调用它HelloWorld:

@Remote
public interface HelloWorld {
    String getHelloWorld();
}

Now we will implement the above interface and name the concrete implementation HelloWorldBean:

现在我们将实现上述接口,并将具体实现命名为HelloWorldBean:

@Stateless(name = "HelloWorld")
public class HelloWorldBean implements HelloWorld {

    @Resource
    private SessionContext context;

    @Override
    public String getHelloWorld() {
        return "Welcome to EJB Tutorial!";
    }
}

Note the @Stateless annotation on the class declaration. It denotes that this bean is a stateless session bean. This kind of bean does not have any associated client state, but it may preserve its instance state and is normally used to do independent operations.

注意类声明中的@Stateless 注释。它表示这个Bean是一个无状态会话Bean。这种Bean没有任何相关的客户端状态,但它可以保留其实例状态,并且通常用于进行独立操作。

The @Resource annotation injects the session context into the remote bean.

@Resource 注释将会话上下文注入到远程Bean中。

The SessionContext interface provides access to the runtime session context that the container provides for a session bean instance. The container then passes the SessionContext interface to an instance after the instance has been created. The session context remains associated with that instance for its lifetime.

SessionContext接口提供了对容器为会话 bean 实例提供的运行时会话上下文的访问。然后,容器在实例创建后将 SessionContext 接口传递给实例。会话上下文在该实例的生命周期中一直与之相关联。

The EJB container normally creates a pool of stateless bean’s objects and uses these objects to process client requests. As a result of this pooling mechanism, instance variable values are not guaranteed to be maintained across lookup method calls.

EJB容器通常创建一个无状态Bean的对象池,并使用这些对象来处理客户端请求。由于这种池化机制,实例变量的值不能保证在整个查找方法调用中得到维护。

5. Remote Setup

5.远程设置

In this section, we will discuss how to setup Maven to build and run the application on the server.

在本节中,我们将讨论如何设置Maven以在服务器上构建和运行应用程序。

Let’s look at the plugins one by one.

让我们逐一看一下这些插件。

5.1. The EJB Plugin

5.1.EJB插件

The EJB plugin which is given below is used to package an EJB module. We have specified the EJB version as 3.2.

下面给出的EJB插件是用来打包EJB模块的。我们指定EJB的版本为3.2。

The following plugin configuration is used to setup the target JAR for the bean:

下面的插件配置被用来为Bean设置目标JAR。

<plugin>
    <artifactId>maven-ejb-plugin</artifactId>
    <version>2.4</version>
    <configuration>
        <ejbVersion>3.2</ejbVersion>
    </configuration>
</plugin>

5.2. Deploy the Remote EJB

5.2.部署远程EJB

To deploy the bean in a WildFly server ensure that the server is up and running.

要在WildFly服务器中部署Bean,请确保服务器已经启动并运行。

Then to execute the remote setup we will need to run the following Maven commands against the pom file in the ejb-remote project:

然后为了执行远程设置,我们需要针对ejb-remote项目中的pom文件运行以下Maven命令。

mvn clean install

Then we should run:

那我们就应该跑。

mvn wildfly:deploy

Alternatively, we can deploy it manually as an admin user from the admin console of the application server.

或者,我们可以从应用服务器的管理控制台中,以admin用户的身份手动部署

6. Client Setup

6.客户设置

After creating the remote bean we should test the deployed bean by creating a client.

在创建远程Bean之后,我们应该通过创建一个客户端来测试部署的Bean。

First, let’s discuss the Maven setup for the client project.

首先,我们来讨论一下客户项目的Maven设置。

6.1. Client-Side Maven Setup

6.1.客户端Maven设置

In order to launch the EJB3 client we need to add the following dependencies:

为了启动EJB3客户端,我们需要添加以下依赖项。

<dependency>
    <groupId>org.wildfly</groupId>
    <artifactId>wildfly-ejb-client-bom</artifactId>
    <type>pom</type>
    <scope>import</scope>
</dependency>

We depend on the EJB remote business interfaces of this application to run the client. So we need to specify the EJB client JAR dependency. We add the following in the parent pom:

我们依赖这个应用程序的EJB远程业务接口来运行客户端。所以我们需要指定EJB客户端的JAR依赖性。我们在父pom中添加以下内容。

<dependency>
    <groupId>com.baeldung.ejb</groupId>
    <artifactId>ejb-remote</artifactId>
    <type>ejb</type>
</dependency>

The <type> is specified as ejb.

<type> 被指定为ejb

6.2. Accessing the Remote Bean

6.2.访问远程 Bean

We need to create a file under src/main/resources and name it jboss-ejb-client.properties that will contain all the properties that are required to access the deployed bean:

我们需要在src/main/resources下创建一个文件,并命名为jboss-ejb-client.properties,该文件将包含访问部署的Bean所需的所有属性。

remote.connections=default
remote.connection.default.host=127.0.0.1
remote.connection.default.port=8080
remote.connection.default.connect.options.org.xnio.Options
  .SASL_POLICY_NOANONYMOUS = false
remote.connection.default.connect.options.org.xnio.Options
  .SASL_POLICY_NOPLAINTEXT = false
remote.connection.default.connect.options.org.xnio.Options
  .SASL_DISALLOWED_MECHANISMS = ${host.auth:JBOSS-LOCAL-USER}
remote.connection.default.username=testUser
remote.connection.default.password=admin1234!

7. Creating the Client

7.创建客户

The class that will access and use the remote HelloWorld bean has been created in EJBClient.java which is in the com.baeldung.ejb.client package.

com.baeldung.ejb.client包中的EJBClient.java中,已经创建了访问和使用远程HelloWorldbean的类。

7.1. Remote Bean URL

7.1.远程 Bean URL

The remote bean is located via a URL that conforms to the following format:

远程Bean是通过一个符合以下格式的URL定位的。

ejb:${appName}/${moduleName}/${distinctName}/${beanName}!${viewClassName}
  • The ${appName} is the application name of the deployment. Here we have not used any EAR file but a simple JAR or WAR deployment, so the application name will be empty
  • The ${moduleName} is the name we set for our deployment earlier, so it is ejb-remote
  • The ${distinctName} is a specific name which can be optionally assigned to the deployments that are deployed on the server. If a deployment doesn’t use distinct-name then we can use an empty String in the JNDI name, for the distinct-name, as we did in our example
  • The ${beanName} variable is the simple name of the implementation class of the EJB, so in our example it is HelloWorld
  • ${viewClassName} denotes the fully-qualified interface name of the remote interface

7.2. Look-up Logic

7.2.查表逻辑

Next, let’s have a look at our simple look-up logic:

接下来,让我们看一下我们的简单查找逻辑。

public HelloWorld lookup() throws NamingException { 
    String appName = ""; 
    String moduleName = "remote"; 
    String distinctName = ""; 
    String beanName = "HelloWorld"; 
    String viewClassName = HelloWorld.class.getName();
    String toLookup = String.format("ejb:%s/%s/%s/%s!%s",
      appName, moduleName, distinctName, beanName, viewClassName);
    return (HelloWorld) context.lookup(toLookup);
}

In order to connect to the bean we just created, we will need a URL which we can feed into the context.

为了连接到我们刚刚创建的bean,我们将需要一个URL,我们可以把它输入到上下文。

7.3. The Initial Context

7.3.初始环境

We’ll now create/initialize the session context:

我们现在要创建/初始化会话上下文。

public void createInitialContext() throws NamingException {
    Properties prop = new Properties();
    prop.put(Context.URL_PKG_PREFIXES, "org.jboss.ejb.client.naming");
    prop.put(Context.INITIAL_CONTEXT_FACTORY, 
      "org.jboss.naming.remote.client.InitialContextFacto[ERROR]
    prop.put(Context.PROVIDER_URL, "http-remoting://127.0.0.1:8080");
    prop.put(Context.SECURITY_PRINCIPAL, "testUser");
    prop.put(Context.SECURITY_CREDENTIALS, "admin1234!");
    prop.put("jboss.naming.client.ejb.context", false);
    context = new InitialContext(prop);
}

To connect to the remote bean we need a JNDI context. The context factory is provided by the Maven artifact org.jboss:jboss-remote-naming and this creates a JNDI context, which will resolve the URL constructed in the lookup method, into proxies to the remote application server process.

要连接到远程Bean,我们需要一个JNDI上下文。上下文工厂由Maven工件org.jboss:jboss-remote-naming提供,它可以创建一个JNDI上下文,将lookup方法中构建的URL解析为对远程应用服务器进程的代理。

7.4. Define Lookup Parameters

7.4.定义查找参数

We define the factory class with the parameter Context.INITIAL_CONTEXT_FACTORY.

我们用参数Context.INITIAL_CONTEXT_FACTORY.定义工厂类。

The Context.URL_PKG_PREFIXES is used to define a package to scan for additional naming context.

Context.URL_PKG_PREFIXES用于定义一个包来扫描额外的命名环境。

The parameter org.jboss.ejb.client.scoped.context = false tells the context to read the connection parameters (such as the connection host and port) from the provided map instead of from a classpath configuration file. This is especially helpful if we want to create a JAR bundle that should be able to connect to different hosts.

参数org.jboss.ejb.client.scoped.context = false告诉context从提供的map而不是从classpath配置文件中读取连接参数(比如连接主机和端口)。如果我们想创建一个应该能够连接到不同主机的JAR包,这就特别有帮助。

The parameter Context.PROVIDER_URL defines the connection schema and should start with http-remoting://.

参数Context.PROVIDER_URL定义了连接模式,应该以http-remoting://开始。

8. Testing

8.测试

To test the deployment and check the setup, we can run the following test to make sure everything works properly:

为了测试部署和检查设置,我们可以运行以下测试,以确保一切工作正常。

@Test
public void testEJBClient() {
    EJBClient ejbClient = new EJBClient();
    HelloWorldBean bean = new HelloWorldBean();
    
    assertEquals(bean.getHelloWorld(), ejbClient.getEJBRemoteMessage());
}

With the test passing, we can now be sure everything is working as expected.

随着测试的通过,我们现在可以确定一切都在按预期工作。

9. Conclusion

9.结论

So we have created an EJB server and a client which invokes a method on a remote EJB. The project can be run on any application server by properly adding the dependencies for that server.

所以我们已经创建了一个EJB服务器和一个客户端,它调用了远程EJB上的一个方法。该项目可以在任何应用服务器上运行,只要正确添加该服务器的依赖项。

The entire project can be found over on GitHub.

整个项目可以在GitHub上找到over