java - 使用 GlassFish 5 将 Singleton Bean 存储在 JNDI 中

标签 java jakarta-ee glassfish ejb jndi

我在 Eclipse 中安装了可用的 Glassfish 5。

我的模块设置如下:

常见

  • 包含带有@remote和@local注释的单例bean的远程接口(interface)
  • 作为 pom 依赖项包含在所有其他模块中

核心

  • 包含一个实现通用接口(interface)的单例 bean
  • 旨在包含存储在 JNDI 中的服务类,允许任意数量的客户端查找和存储数据和/或访问其他服务逻辑
  • 构建一个部署到 GlassFish 上的 war 文件

桌面

  • 对单例 bean 进行 InitialContext 查找。 (我打算将其抽象为服务查找设计模式)。
  • 旨在成为远程访问服务器上存储的 Bean 的桌面客户端。
  • 现在,我只是试图让它远程访问核心中的服务,并将一些文本打印到控制台,证明它有效。

我认为我的问题源于对如何在 JNDI 中存储自定义 bean 的误解。我查看了 Google,但我主要找到了一些文章和问题的答案,告诉我将 name 和mappedName 添加到 Singleton 注释中,或者它们仅显示如何将预定义的 bean 添加到 JDNI 中,例如 boolean 值或字符串,而不是自定义定义的内容。

我的bean定义如下:

@Singleton(name = "BookService", mappedName = "ejb/BookService")
public class BookServiceImpl implements BookService {

    private static final long serialVersionUID = 1L;

这会在 Glassfish 服务器上产生以下结果: Core Server Screenshot

但是 JNDI 中什么也没有出现: JNDI Screenshot

客户端像这样进行InitialContext查找(我尝试了多种编写JNDI名称的方法):

BookService bookService = (BookService) initialContext.lookup("java:global/core/BookService");

使用这些配置(我用 8000 的基本端口定义了我的域,因此每个端口都是 8000 + 一些):

glashfishEnvironmentTable = new Hashtable<String, String>();
glashfishEnvironmentTable.put(Context.INITIAL_CONTEXT_FACTORY,
            "com.sun.enterprise.naming.impl.SerialInitContextFactory");
glashfishEnvironmentTable.put(Context.STATE_FACTORIES,
            "com.sun.corba.ee.impl.presentation.rmi.JNDIStateFactoryImpl");
glashfishEnvironmentTable.put(Context.URL_PKG_PREFIXES, "com.sun.enterprise.naming");
//glashfishEnvironmentTable.put(Context.PROVIDER_URL, "ejbd://localhost:8080/");
// on a different host than the appserver   
glashfishEnvironmentTable.put("org.omg.CORBA.ORBInitialHost", "localhost");
// optional.  Defaults to 3700.  Only needed if target orb port is not 3700.
glashfishEnvironmentTable.put("org.omg.CORBA.ORBInitialPort", "8037");

当我运行它时,我收到这样的错误:

Exception in thread "main" javax.naming.CommunicationException: Communication exception for SerialContext[myEnv={org.omg.CORBA.ORBInitialPort=8037, java.naming.factory.initial=com.sun.enterprise.naming.impl.SerialInitContextFactory, org.omg.CORBA.ORBInitialHost=localhost, java.naming.factory.url.pkgs=com.sun.enterprise.naming, java.naming.factory.state=com.sun.corba.ee.impl.presentation.rmi.JNDIStateFactoryImpl} [Root exception is java.rmi.MarshalException: CORBA MARSHAL 1330446343 No; nested exception is: 
org.omg.CORBA.MARSHAL: FINE: 00810007: Underflow in BufferManagerReadStream after last fragment in message  vmcid: OMG  minor code: 7  completed: No]

我认为我的InitialContext配置正确,因为当我像这样在JNDI中手动定义bean时(ServiceFactory不执行任何操作,因为我不知道如何正确扩展ObjectFactory):

Bean defined in JNDI

我明白了:

Exception in thread "main" java.lang.ClassCastException: javax.naming.Reference cannot be cast to common.service.BookService

是否有简单的解决方案可以解决我所缺少的问题,或者我是否正在混合油和水试图将 EJB Singleton 放入 JNDI?或者我是否缺少像 EJBHome 或 Servlet 这样的大东西?

我是否需要扩展工厂类来将我的服务类添加到 JDNI 中,或者 ObjectFactory 应该起作用吗?如果我必须扩展工厂类,我该怎么做?

我希望我已经足够好地定义了问题的范围,但这对我来说是全新的,所以如果有人有实现类似事情的经验,我很感激任何能让我更接近正确做法的意见。

最佳答案

我明白了。我做了两件不该做的事。

  1. 在构建我的 war 文件之前,我忘记了 maven 安装我的通用模块...哎呀!
  2. 似乎 @Remote 和 @Local 注释不能位于同一个接口(interface)中,否则会失败(这很遗憾,因为我试图设置它,所以我不必有两个几乎相同的接口(interface))。

这里有一些更多的细节,以防其他人遇到类似的问题并且需要查看一些有效的东西(我在这里没有完成@Local,因为我还没有尝试过。不过添加应该很简单) :

  1. 对于远程执行,您需要一个使用 @Remote 注解并扩展 Serialized 的接口(interface)(客户端/服务器接口(interface)需要序列化)。
import java.io.Serializable;

public interface Remote extends Serializable{

}
import javax.ejb.Remote;

@Remote
public interface BookServiceRemote extends Remote {

    public String readBook();

}
  • 您的 war 文件需要包含 BookServiceImpl
  • import javax.ejb.Singleton;
    
    import us.boggs.template.common.service.BookServiceRemote;
    
    @Singleton(name = "BookService")
    public class BookServiceImpl implements BookServiceRemote {
    
        private static final long serialVersionUID = 1L;
    
        @Override
        public String readBook() {
            return "Read the book.";
        }
    }
    
  • 您的客户端 pom.xml 必须包含公共(public)模块,并且:
  • <dependency>
     <groupId>org.glassfish.main.appclient</groupId>
     <artifactId>gf-client</artifactId>
     <version>5.1.0</version>
    </dependency>
    
  • 您的客户端主方法可以通过创建一个 InitialContext 并进行查找来使用它(我的基本端口是 8000,所以我的 ORBInitialPort 是 8000+37=8037):
  • private static Hashtable<String, String> glashfishEnvironmentTable;
    
    static {
        glashfishEnvironmentTable = new Hashtable<String, String>();
        glashfishEnvironmentTable.put(Context.INITIAL_CONTEXT_FACTORY,
                    "com.sun.enterprise.naming.impl.SerialInitContextFactory");
        glashfishEnvironmentTable.put(Context.STATE_FACTORIES,
                    "com.sun.corba.ee.impl.presentation.rmi.JNDIStateFactoryImpl");
        glashfishEnvironmentTable.put(Context.URL_PKG_PREFIXES, "com.sun.enterprise.naming"); 
        glashfishEnvironmentTable.put("org.omg.CORBA.ORBInitialHost", "localhost");
        // optional.  Defaults to 3700.  Only needed if target orb port is not 3700.
        glashfishEnvironmentTable.put("org.omg.CORBA.ORBInitialPort", "8037");
    }
    
    InitialContext initialContext = new InitialContext(glashfishEnvironmentTable);
            BookServiceRemote bookService = (BookServiceRemote) initialContext.lookup("java:global/core/BookService");
    System.out.println(bookService.readBook());
    

    关于java - 使用 GlassFish 5 将 Singleton Bean 存储在 JNDI 中,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59812550/

    相关文章:

    java - JPA 在 glassfish 中重新部署后停止工作

    security - GlassFish 管理控制台(端口 4848)安全吗?

    java - 如何使用 HTML 颜色通过 zxing 编写二维码

    java - 具有初始值的链表构造函数

    java - 在 Android Studio 中添加外部库时出现问题

    java - 如何处理使用相同库的许多 Web 应用程序的共享库

    java - 增加 MDB 实例

    java - Android SDK 和 Java

    javascript - 使用 Websockets 从 Java 端点发送图像

    java - 将 servlet 自动部署到 glassfish 后出现 404