50

本地&远程访问一个EJB | 从开发角度看应用架构4

 5 years ago
source link: http://www.10tiao.com/html/360/201806/2663487974/1.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

一、前言


本文仅代表作者的个人观点;

本文的内容仅限于技术探讨,不能作为指导生产环境的素材;

本文素材是红帽公司产品技术和手册;

本文分为系列文章,将会有多篇,初步预计将会有9篇。


二、对EJB的访问方式


EJB是一个包含在应用程序服务器上运行的业务逻辑的可移植组件。 如果客户端和EJB是同一应用程序的一部分,则客户端可以在本地访问EJB,如果EJB在远程运行,则客户端可以通过远程接口访问EJB。


如果客户端和EJB是本地的,也就是说,它们在相同的JVM进程中运行,则客户端可以调用EJB中的所有公共方法。 在EJB远程的情况下,必须提供一个远程接口,它是一个公开EJB业务方法的简单Java接口。 EJB类实现远程接口中的方法,其实现细节对客户端是隐藏的。


使用@EJB注释访问本地EJB


假设已经定义了如下的EJB:

@Stateless

public class TodoBean {  public void addTodo(TodoItem item) {  ...  }  public void findTodo(int id) {  ...  }  ...  } ... }

客户可以通过使用@EJB注释将EJB直接注入到代码中来调用EJB上的方法:

public class TodoClient {  @EJB
  TodoBean todo;

  TodoItem item = new TodoItem();
  item.setDescription("Buy milk");
  item.setStatus("PENDING");

  //invoke EJB methods
  todo.addTodo(item);
...
}



访问远程EJB


在客户机在Java EE应用程序服务器的上下文之外运行的情况下,或者在应用程序服务器上运行的Java EE组件需要访问部署在远程应用程序服务器上的另一个EJB的情况下,可以使用JNDI来查找EJB。


为了确保远程客户端可以使用EJB,必须声明一个列出EJB业务方法的接口,并让EJB实现并覆盖这些方法。 例如,假设希望提供执行各种数学操作的EJB,请声明一个接口并列出如下所示的方法:

package com.redhat.training.ejb;public interface Calculator {

  public int add(int a, int b);
  public int multiply(int a, int b);
...
}

我们现在必须在EJB中提供这些方法的具体实现,并通过使用@Remote注释指出Calculator是EJB的远程接口:

package com.redhat.training.ejb;@Stateless@Remote(Calculator.class)

public class CalculatorBean implements Calculator {  @Override  public int add(int a, int b) {    return a + b;  }  @Override  public int multiply(int a, int b) {    return a * b;  }  ...  } ... }

我们的EJB现在可以打包并部署在应用服务器上,并可以为远程客户端提供服务。



三、使用JNDI查找远程EJB


Java EE标准为客户端指定了标准的JNDI查找方案来查找EJB。 示例如下:

/<application-name>/<module-name>/<bean-name>!<fully-qualified-interface-name>

application-name:应用程序名称是部署EJB的EAR的名称(没有.ear扩展名)。 如果EJB JAR没有在EAR中部署,那么这是空白的。 应用程序名称也可以在EAR的application.xml部署描述符中指定。


module-name:默认情况下,模块名称是EJB JAR文件的名称(不带.jar后缀)。 模块名称可以在ejb-jar.xml部署描述符中重写。


bean-name:要调用的EJB的名称(实现类)。


fully-qualified-interface-name:远程接口的完全限定类名。 包括完整的软件包名称。

考虑到上面的代码清单,假设EJB打包在名为calculator-ejb.jar的文件中,该文件被进一步打包到名为myapp.ear的EAR文件中。 客户端可以使用以下查找字符串查找EJB:

myapp/calculator-ejb/CalculatorBean!com.redhat.training.ejb.Calculator


在部署EJB时,应用程序服务器会在服务器日志中列出EJB的不同JNDI绑定。 下面的清单显示了如果将EJB打包并部署为JAR文件,而不是EAR文件,则显示JNDI条目:

INFO  [org.jboss.as.ejb3.deployment] (MSC service thread 1-2) WFLYEJB0473: JNDI bindings for session bean named 'CalculatorBean' in deployment unit 'deployment "calculator-ejb.jar"' are as follows:java:global/calculator-ejb/CalculatorBean!com.redhat.training.ejb.Calculator
java:app/calculator-ejb/CalculatorBean!com.redhat.training.ejb.Calculator
java:module/CalculatorBean!com.redhat.training.ejb.Calculator
java:global/calculator-ejb/CalculatorBean
java:app/calculator-ejb/CalculatorBean
java:module/CalculatorBean

使用JNDI命名机制查找远程EJB的示例JNDI客户机程序如下所示:

package com.redhat.training.client;

public class CalculatorClient {

  public static void main(String[] args) throws Exception {    String JNDI_URL= "myapp/calculator-ejb/CalculatorBean!com.redhat.training.ejb.Calculator";
    try {
      Context ic = new InitialContext();      Calculator calc = (Calculator) ic.lookup(JNDI_URL);
      System.out.println("Response from server = " + calc.add(1,2);
      ...
    }
    catch (Exception e) {
      // handle the exception
    }

  }
...
}

我们还需要在客户端程序的类路径中提供一个名为jndi.properties的文件,其中包含运行EJB的远程应用程序服务器的主机名,IP地址,端口和安全详细信息(如果安全用于远程访问)。

java.naming.factory.initial=org.jboss.naming.remote.client.InitialContextFactory
java.naming.provider.url=http-remoting://10.2.0.15:8080
jboss.naming.client.ejb.context=true

JNDI API的InitialContext是一个标准的Java EE通用构造,用于查找部署在应用程序服务器上的组件。 它使用一组属性在类路径中查找jndi.properties。 某些属性对所有应用程序服务器都是通用的,有些属性是针对每个应用程序服务器的。



四、实验展现


实验由两个Maven子项目组成,它们位于hello-remote目录下的主项目文件夹下,其中包含hello-remote-ejb和hello-remote-client。


hello-remote-ejb项目在JBoss EAP中安装可远程访问的EJB,以便通过JNDI查找可用于外部客户端。 hello-remote-client项目是远程访问(从另一个JVM)EJB的Java SE应用程序。


首先,在JBDS中import已经存在的maven项目:

接下来,再import client:


查看hello-remote-ejb的pom.xml:


在源码的如下部分, 使用maven-ejb-plugin为ejb打包:

package已被声明为ejb,这告诉Maven如何打包最终的可部署artifact:


查看业务接口:HelloRemote.java文件:

这是一个简单的Java接口,它带有一个公共方法sayHello(一个class),它接受一个字符串名称参数并返回一个字符串。 在使用EJB时,通常使用接口来定义可用的方法,而不考虑实现。


查看最终执行任务的类的源码:HelloBean.java文件。

注意到这个EJB类实现了HelloRemote接口的sayHello方法,并且注意到标记这个类为无状态EJB的@Stateless注解。


接下来,启动EAP:

接下来,通过运行以下命令来构建和部署EJB到JBoss EAP:

查看EAP日志,hello-ejb-remote.jar已经被部署到EAP中:

JBoss EAP要求将EJB绑定在java:jboss / exported / *名称空间下,以允许外部客户端查找和调用EJB。


注意到没有“导出的”JNDI绑定。 您需要为EJB提供一个远程接口,以便将EJB绑定在该名称空间下。

编辑EJB项目的实现类HelloBean.java以启用远程JNDI查找并重新部署应用程序。


编辑实现类HelloBean.java以启用远程JNDI查找。 将@Remote注释添加到您的实现类并保存该文件,在源码中增加以下两行:

重新编译和部署hello-ejb-remote:

再次观察JNDI绑定。 这次我们可以在JBDS Console选项卡中看到导出的JNDI绑定:


使用Maven将hello-remote-ejb构件安装到本地存储库中,以便在编译期间可供客户端项目使用:


接下来,查看hello-client项目的源代码,并更新它以使用JNDI查找HelloBean。

在JBDS左窗格的Project Explorer选项卡中展开hello-client项目,然后双击pom.xml文件。


单击pom.xml选项卡查看pom.xml,我们可以看到对hello-remote-ejb的依赖(需要远程调用它)依赖关系的类型是ejb-client。 这告诉Maven这个工件是用于代码编译的hello-remote-ejb工件中定义的EJB的客户端。

查看HelloClient.java源码,将下面突出的部分修改:

修改成如下样子:


更新jndi.properties文件(src/main/resources)以使用http-remoting来访问在本地JBoss EAP服务器上运行的EJB。


将java.naming.provider.url属性设置为值http-remoting://127.0.0.1:8080,如以下图例所示:

修改成:

接下来,编译并运行客户端:

最后一行的reponse说明客户端对ejb调用成功!


魏新宇

  • "大魏分享"运营者、红帽资深解决方案架构师

  • 专注开源云计算、容器及自动化运维在金融行业的推广

  • 拥有MBA、ITIL V3、Cobit5、C-STAR、TOGAF9.1(鉴定级)等管理认证。

  • 拥有红帽RHCE/RHCA、VMware VCP-DCV、VCP-DT、VCP-Network、VCP-Cloud、AIX、HPUX等技术认证。




About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK