我在 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):
我明白了:
Exception in thread "main" java.lang.ClassCastException: javax.naming.Reference cannot be cast to common.service.BookService
是否有简单的解决方案可以解决我所缺少的问题,或者我是否正在混合油和水试图将 EJB Singleton 放入 JNDI?或者我是否缺少像 EJBHome 或 Servlet 这样的大东西?
我是否需要扩展工厂类来将我的服务类添加到 JDNI 中,或者 ObjectFactory 应该起作用吗?如果我必须扩展工厂类,我该怎么做?
我希望我已经足够好地定义了问题的范围,但这对我来说是全新的,所以如果有人有实现类似事情的经验,我很感激任何能让我更接近正确做法的意见。
最佳答案
我明白了。我做了两件不该做的事。
- 在构建我的 war 文件之前,我忘记了 maven 安装我的通用模块...哎呀!
- 似乎 @Remote 和 @Local 注释不能位于同一个接口(interface)中,否则会失败(这很遗憾,因为我试图设置它,所以我不必有两个几乎相同的接口(interface))。
这里有一些更多的细节,以防其他人遇到类似的问题并且需要查看一些有效的东西(我在这里没有完成@Local,因为我还没有尝试过。不过添加应该很简单) :
- 对于远程执行,您需要一个使用 @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/