java - 如何从 Spring Boot Client 到 GlassFish Server 进行远程 JNDI 查找?
问题描述
我从一个工作的 Spring Boot 应用程序开始,使用最新版本的 Spring Boot 和嵌入式 Tomcat。它包含一个 HomeController,其索引方法映射到 webapp 目录中的相应 .jsp。
@RequestMapping(value={"/", "/home", "/home/index"})
public ModelAndView index() {
ModelAndView mv = new ModelAndView("/home/index");
return mv;
}
我的目标是对 glassfish 服务器进行远程 JNDIlookup 以访问 EJB 单例服务。我之前使用一个简单的桌面客户端验证了对 Glassfish 服务器的远程 JNDI 查找工作正常。
我遵循了 WildFly 的本教程,将其重新用于 Glassfish: https ://www.baeldung.com/spring-ejb
看起来很简单。我将导入 Glassfish 的而不是 WildFly 的客户端模块,而不是 WildFly 的 InitialContext 属性,我将使用 Glassfish 的。
所以我用这个更新了我的 pom.xml(我还添加了一个包含远程接口的依赖项):
<dependency>
<groupId>org.glassfish.main.appclient</groupId>
<artifactId>gf-client</artifactId>
<version>5.1.0</version>
</dependency>
像这样更新 McvConfig.java(我的 GlassFish 的基本端口是 8000,它为 JNDI 端口添加了 37):
@Bean
public Context ejbInitialContext() {
InitialContext initialContext = null;
try {
Properties jndiProps = new Properties();
jndiProps.put(Context.INITIAL_CONTEXT_FACTORY,
"com.sun.enterprise.naming.impl.SerialInitContextFactory");
jndiProps.put(Context.STATE_FACTORIES,
"com.sun.corba.ee.impl.presentation.rmi.JNDIStateFactoryImpl");
jndiProps.put(Context.URL_PKG_PREFIXES, "com.sun.enterprise.naming");
jndiProps.put("org.omg.CORBA.ORBInitialHost", "localhost");
// optional. Defaults to 3700. Only needed if target orb port is not 3700.
jndiProps.put("org.omg.CORBA.ORBInitialPort", "8037");
initialContext = new InitialContext(jndiProps);
} catch (NamingException e) {
}
return initialContext;
}
并像这样更新了 HomeController:
@Autowired
Context ejbInitialContext;
@RequestMapping(value={"/", "/home", "/home/index"})
public ModelAndView index() {
ModelAndView mv = new ModelAndView("/home/index");
ServiceRemote service = (ServiceRemote) ejbInitialContext.lookup("java:global/core/Service");
mv.addObject("Hello", service.hello());
return mv;
}
我运行了 GlassFish 服务器,然后尝试运行我的 Spring Boot 应用程序。Sprint Boot 日志没有显示,过了一会儿,我得到了这个(完整日志:https ://pastebin.com/E11xLmFN ):
org.omg.CORBA.COMM_FAILURE: FINE: 00410001: Connection failure: socketType: IIOP_CLEAR_TEXT; hostname: localhost; port: 3700 vmcid: OMG minor code: 1 completed: No
...
Caused by: java.lang.RuntimeException: java.net.ConnectException: Connection refused: connect
...
Caused by: java.net.ConnectException: Connection refused: connect
我尝试访问本地主机,它只是说:
This site can’t be reached
折腾了一阵子,总结了几点:
- 添加新的依赖项是破坏 Spring MVC 并取消我的 Web 服务所需要的。
Spring 正在尝试与 GlashFish 集成,因为堆栈跟踪包括以下内容:
在 org.springframework.jndi.JndiTemplate.lambda$lookup$0(JndiTemplate.java:157) 在 org.springframework.jndi.JndiTemplate.execute(JndiTemplate.java:92) 在 org.springframework.jndi.JndiTemplate.lookup(JndiTemplate. java:157) 在 org.springframework.jndi.JndiTemplate.lookup(JndiTemplate.java:179)
Spring完全忽略了我的Bean,使用默认的GlassFish InitialContext,因为日志中的端口号还是3700,GlassFish的默认,但是我指定了8048。
Spring 以某种方式检测客户端模块并定期尝试连接到 Glassfish。问题是我完全不知道如何告诉 Spring 使用我的自定义 InitialContext 属性。
我在网上到处寻找解决方案。大多数类似的问题都没有很好地提出,也没有得到答案,还有一些专门针对 DataSource,这对我来说太具体了,因为我试图将整个 Service 层放在 Jakarta EE 服务器上。
解决方案
没关系。我只是想出了该怎么做。如果您查看堆栈跟踪,它从 Spring Boot 应用程序的开头开始: SpringApplication.run(App.class, args);
Spring Boot 实际上是在它自己的初始化中初始化 GlassFish AppClient。当我写这个问题时,这一点很清楚。
事实证明,这样做的唯一方法是将 InitialContext 中的相同属性放入 System Properties 中,如下所示:
@SuppressWarnings("unused")
private static ApplicationContext applicationContext;
public static void main( String[] args ) throws NamingException
{
Properties props = System.getProperties();
jndiProps.put(Context.INITIAL_CONTEXT_FACTORY,
"com.sun.enterprise.naming.impl.SerialInitContextFactory");
jndiProps.put(Context.STATE_FACTORIES,
"com.sun.corba.ee.impl.presentation.rmi.JNDIStateFactoryImpl");
jndiProps.put(Context.URL_PKG_PREFIXES, "com.sun.enterprise.naming");
jndiProps.put("org.omg.CORBA.ORBInitialHost", "localhost");
// optional. Defaults to 3700. Only needed if target orb port is not 3700.
jndiProps.put("org.omg.CORBA.ORBInitialPort", "8037");
System.setProperties(props);
applicationContext = SpringApplication.run(App.class, args);
}
在用新的属性集覆盖系统属性之前,您必须先获取初始系统属性并将其添加到其中,否则您将破坏整个事物。
它也必须在运行 SpringApplication 之前完成,因为那是初始化发生的地方。
我要做的最后一件事是将前面提到的 GlassFish AppClient 移到 pom.xml 中所有 Spring 依赖项的下面。将它放在顶部附近是为我认为在 Tomcat 服务器本身中的连接器类创建一个 NoClassDefFoundError。
<dependency>
<groupId>org.glassfish.main.appclient</groupId>
<artifactId>gf-client</artifactId>
<version>5.1.0</version>
</dependency>
之后,我打开我的网页,在 GlassFish 服务器上的 EJB Singleton 中创建的测试文本通过我的 Spring Boot 客户端传递到我的浏览器。证明系统按预期工作。
推荐阅读
- python - Webdriver.chrome 没有打开 chrome
- angular - Angular 9 测试的“预期是间谍,但得到了功能”错误
- android - 考虑到 API 29 中的新安全更改,如何将应用程序返回到前台?
- active-directory - 如何保持 Active Directory 的两个实例同步
- javascript - 我正在使用 Angular,它有一个模态对话框,然后有复选框。我无法让复选框记住他们的选择
- mysql - 使用 SQL 获取 MySQL 中两行之间的增量时间
- visual-studio-code - 我曾经在每个打开的文件编辑器的顶部都有标签 - 现在它只显示当前打开的标签
- python - 使用 pysftp 和 paramiko 时出现权限错误
- reactjs - 如何可视化我从 firestore n react datable 获得的用户数组?
- tkinter - Tkinter 将标签更改为默认字体