【发布时间】:2021-05-08 19:23:38
【问题描述】:
我们使用一个包含两个应用程序(app1 和 app2)的 Websphere 集群。我可以从 Intellij-Idea 的本地 Spring Boot 中调用这两个应用程序的 EJB。
当我将 Spring Boot 应用程序部署到公司私有 openshift 云时,两个服务之一(客户端)与其中一个 websphere 应用程序通信时出现编组异常。
@Service
public class App1BookingsManagementService implements EjbService<DomainFacade> {
private static final String DOMAINFACADE_EJB_NAME = "ejb/org/company/app/DomainFacade";
private static final Logger LOG = LoggerFactory.getLogger(App1BookingsManagementService.class);
@Autowired
private InitialContext initialContext;
public List<BookingDataRow> getBookingsToday() {
DomainFacade domainFacade = null;
try {
domainFacade = createEjbStub();
BookingSelektionskriterien selektionskriterien = new BookingSelektionskriterien();
selektionskriterien.setTerminFrom(valueOf(now()));
selektionskriterien.setTerminUntil(valueOf(now().plusDays(1)));
ResultList<BookingDataRow> resultList = domainFacade.sucheBookingsDataRows(selektionskriterien);
if (resultList == null) {
LOG.warn("Error in EJB {} from APP1 returned null. ", DOMAINFACADE_EJB_NAME);
}
LOG.info("Calling EJB sucheBookingsDataRows returned {} results. ", resultList.getList().size());
return resultList.getList();
} catch (NamingException | CreateException | RemoteException | DomainException e) {
LOG.error("Error in calling EJB {} from APP1: {}, {}", DOMAINFACADE_EJB_NAME, e.getClass().getName(), e.getMessage());
} finally {
if (domainFacade != null) {
try {
domainFacade.remove();
} catch (RemoteException | RemoveException e) {
LOG.error("could not remove ejb {}", DOMAINFACADE_EJB_NAME, e);
}
}
}
return Collections.emptyList();
}
public DomainFacade createEjbStub() throws NamingException, RemoteException, CreateException {
Object stub = initialContext.lookup(DOMAINFACADE_EJB_NAME);
DomainFacadeHome facadeHome = (DomainFacadeHome) PortableRemoteObject.narrow(stub, DomainFacadeHome.class);
return facadeHome.create();
}
}
这里是配置:
@Configuration
public class CorbaConfig {
@Value("${corba-location}")
private String corbaLocation;
@Value("classpath:sas.client.props")
private Resource sasClientProps;
@Bean
public InitialContext corbaContext() throws NamingException, IOException {
Hashtable<String, Object> env = new Hashtable<>();
env.put(Context.INITIAL_CONTEXT_FACTORY, "com.ibm.websphere.naming.WsnInitialContextFactory");
env.put(PROPS.HOSTNAME_NORMALIZER, PROPS.HOSTNAME_NORMALIZER_NONE);
env.put("com.ibm.CORBA.ConfigURL", sasClientProps.getInputStream());
env.put(Context.PROVIDER_URL, corbaLocation);
return new InitialContext(env);
}
@Bean
public MBeanServer mbeanServer() {
MBeanServerFactoryBean factory = new MBeanServerFactoryBean();
factory.setLocateExistingServerIfPossible(true);
factory.afterPropertiesSet();
return factory.getObject();
}
}
这是我在 openshift 中看到的错误:
2021-02-04 08:14:53,714 [ERROR] P=891120:O=0:CT appname=app-ejbcall corid= c.s.n.e.s.App1BookingsManagementService: Error in calling EJB ejb/org/company/app/DomainFacade from APP1: java.rmi.MarshalException, CORBA MARSHAL 0x4942f89a No; nested exception is:
org.omg.CORBA.MARSHAL:
>> SERVER (id=431c9d95, host=was.company.org) TRACE START:
>> org.omg.CORBA.MARSHAL: Unable to read value from underlying bridge : Default data must be read first vmcid: IBM minor code: 89A completed: No
>> at com.ibm.rmi.iiop.CDRReader.read_value(CDRReader.java:1644)
>> at com.ibm.rmi.iiop.EncoderInputStream.read_value(EncoderInputStream.java:970)
>> at org.company.app.Domain.ejb.facade._EJSRemoteStatelessDomainFacade_a1729579_Tie.sucheBookingenDataRows(Unknown Source)
>> at org.company.app.Domain.ejb.facade._EJSRemoteStatelessDomainFacade_a1729579_Tie._invoke(Unknown Source)
>> at com.ibm.CORBA.iiop.ServerDelegate.dispatchInvokeHandler(ServerDelegate.java:638)
>> at com.ibm.CORBA.iiop.ServerDelegate.dispatch(ServerDelegate.java:508)
>> at com.ibm.rmi.iiop.ORB.process(ORB.java:613)
>> at com.ibm.CORBA.iiop.ORB.process(ORB.java:1584)
>> at com.ibm.rmi.iiop.Connection.doRequestWork(Connection.java:3190)
>> at com.ibm.rmi.iiop.Connection.doWork(Connection.java:3051)
>> at com.ibm.rmi.iiop.WorkUnitImpl.doWork(WorkUnitImpl.java:64)
>> at com.ibm.ws.giop.threadpool.WorkQueueElement.dispatch(WorkQueueElement.java:174)
>> at com.ibm.ws.giop.filter.GiopFilterChain.processMessage(GiopFilterChain.java:203)
>> at com.ibm.ws.giop.threadpool.PooledThread.handleRequest(PooledThread.java:81)
>> at com.ibm.ws.giop.threadpool.PooledThread.run(PooledThread.java:102)
>> at com.ibm.ws.util.ThreadPool$Worker.run(ThreadPool.java:1892)
>> SERVER (id=431c9d95, host=was.company.org) TRACE END.
vmcid: IBM minor code: 89A completed: No
在本地与同一个 websphere 服务器通信没有问题。一种猜测是 RMI 存根不一样,但它在本地也是一个问题,不是吗?
| App 1 | App 2 | |
|---|---|---|
| Local Spring Boot run in IDE | OK | OK |
| Deployt in Openshift Cloud | OK | NOK |
【问题讨论】:
-
该错误表明问题出在 EJB 方法调用上的 BookingSelektionskriterien 参数上,因此 App 1 没有受到影响(如果它没有任何具有类似参数的方法)也就不足为奇了。您有多确定这两个场景都使用相同的 Stub 类和相同版本的 BookingSelektionskriterien?这似乎是写入 EJB 2.x API 的 EJB,但它是封装在 EJB 2.x 模块还是 EJB 3.x 模块中(即 ejb-jar.xml 是什么版本)?您是如何生成 Stub 类的? EJB 部署? RMIC?还是创建EJBStubs?
-
J2EE 应用程序很旧:ejb-jar version="2.1"。我认为你是对的,在 app1 中存根已经存在,在 app2 中我必须自己添加它,我使用 rmic-maven-plugin 并且只包含
**/ejb/facade/*Home.class和**/ejb/facade/*Facade.class。因此,对于 BookingSelektionskriterien 没有存根。但为什么它在本地有效呢? -
BookingSelektionskriterien 不需要存根,它不是远程对象,它将被序列化并作为参数传递。一个环境有效,而另一个环境无效这一事实使这两个环境的类路径上看起来像是某物的不同版本。我会确保在两个环境中加载相同版本的 Stub 类和 BookingSelektionskriterien。如果它们相同,则比较 Java 的版本。也许使用不同级别的 Java 引入了一些序列化差异。然后检查 ORB 的版本。
-
我在玩依赖关系:
com.ibm.ws:ws-admin-client、com.ibm.ws:orb和org.glassfish.corba:glassfish-corba-orb。我删除了 glassfish-corba-orb,它仍在本地运行,部署后我得到java.lang.ClassNotFoundException: javax.rmi.PortableRemoteObject。在这两种环境中,我都在使用 OpenJava 8
标签: spring-boot openshift websphere ejb marshalling