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

一、前言

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

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

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

本文分为系列文章,将会有多篇,初步预计将会有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等技术认证。

原文发布于微信公众号 - 大魏分享(david-share)

原文发表时间:2018-06-12

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏Core Net

Ios8之后, 定位的delegate不能触发的问题

2828
来自专栏Danny的专栏

【EJB学习笔记】——EJB开发环境搭建(Eclipse集成JBoss)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/huyuyang6688/article/...

1143
来自专栏刘君君

Spring Cloud Netflix OSS 学习总结

6384
来自专栏Vue ssr

mod_rewrite: Could not set permissions on rewrite_log_lock

[crit] (22)Invalid argument: mod_rewrite: Could not set permissions on rewrite_...

1443
来自专栏IT笔记

SpringBoot开发案例之奇技淫巧

程序员都有着一种天生的好奇心,这种好奇心引导着我们的编程生涯。写几行代码,装载到计算机里,让它按照你的思路工作,这是非常有趣的事情。但随着开发的东西越来越多,我...

89110
来自专栏java学习

Spring学习笔记1_Spring的概述

本章目录 Spring学习笔记1_Spring的概述 1.Spring介绍 2.Spring作用 3.Spring起源 4.Spring体系结构 5.Spri...

2956
来自专栏世界第一语言是java

springcloud微服务实战:Eureka+Zuul+Feign/Ribbon+Hystrix Turbine+SpringConfig+sleuth+zipkin

4733
来自专栏Java技术栈

Spring Boot核心配置

启动类 在包根目录下添加启动类,必须包含main方法,再添加Spring Boot启动方法: SpringApplication.run(SampleContr...

3376
来自专栏IT 指南者专栏

SpringMVC 框架系列之组件概述与配置详解

微信公众号:compassblog 欢迎关注,互相学习,共同进步! 有任何问题,请后台留言联系! 在上一篇文章 SpringMVC 框架系列之初识与入门实例 的...

2827
来自专栏Aloys的开发之路

Groovy实现原理分析——准备工作

首先说明一下为什么要写这样一系列分析Groovy实现原理的博文。我之前在华为大数据部门曾维护过一份规则引擎的项目,该项目说白了就是一种DSL(Domain Sp...

3376

扫码关注云+社区