当前位置: 首页 > 知识库问答 >
问题:

Spring远程EJB无法在Liberty上解析bean

娄利
2023-03-14

我有一个EJB服务器在一台Liberty服务器上运行,而客户端在另一台服务器上运行。

如果我使用下面的代码手动查找远程EJB,我可以访问EJB。

Context ctx = new InitialContext();
Object homeObject = ctx.lookup("corbaname::localhost:22809#ejb/global/TempEAR-0.0.1/com.ibm.temp-TempEJB-0.0.1/ConverterBean!com.ibm.temp.ejb.ConverterRemote")
ConverterRemote myRemoteEJB = (ConverterRemote) PortableRemoteObject.narrow(homeObject, ConverterRemote.class);
System.out.println("RESULT " + myRemoteEJB.celsiusToFar(1));

上述工作按预期方式工作,它能够调用在另一个服务器实例上运行的远程 EJB 并按预期工作。

我尝试在我的< code>@Controller类中使用Spring,并通过注释< code>@EJB或< code > @自动连线引用EJB

@EJB(name="testRemoteEJB")
ConverterRemote testRemoteEJB;

mvc-dispatcher-servlet.xml

<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:mvc="http://www.springframework.org/schema/mvc"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     xmlns:jee="http://www.springframework.org/schema/jee"
    xsi:schemaLocation="
        http://www.springframework.org/schema/beans     
        http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
        http://www.springframework.org/schema/context 
        http://www.springframework.org/schema/context/spring-context-3.0.xsd
        http://www.springframework.org/schema/mvc
        http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd
        http://www.springframework.org/schema/jee        
        http://www.springframework.org/schema/jee/spring-jee-3.0.xsd">

    <context:component-scan
        base-package="com.ibm.common.controller" />

    <mvc:annotation-driven />

    <jee:remote-slsb id="testRemoteEJB"
        jndi-name="jndi/testRemoteEJB"
        business-interface="com.ibm.temp.ejb.ConverterRemote">
    </jee:remote-slsb>  
</beans>

自由服务器.xml

  <jndiEntry id="testRemoteEJB" jndiName="jndi/testRemoteEJB" value="corbaname::localhost:22809#ejb/global/TempEAR-0.0.1/com.ibm.temp-TempEJB-0.0.1/ConverterBean!com.ibm.temp.ejb.ConverterRemote"/>

当我打印出testRemoteEJB对象时,它返回一个com.sun.proxy.$Proxy41对象,当我尝试调用方法函数时,我得到以下异常

[err] org.springframework.remoting.RemoteProxyFailureException: No matching RMI stub method found for: public abstract double com.ibm.temp.ejb.Converter.celsiusToFar(double) throws java.rmi.RemoteException; nested exception is java.lang.NoSuchMethodException: java.lang.String.celsiusToFar(double)
[err]   at org.springframework.remoting.rmi.RmiClientInterceptorUtils.invokeRemoteMethod(RmiClientInterceptorUtils.java:83)
[err]   at org.springframework.ejb.access.SimpleRemoteSlsbInvokerInterceptor.doInvoke(SimpleRemoteSlsbInvokerInterceptor.java:98)
[err]   at org.springframework.ejb.access.AbstractRemoteSlsbInvokerInterceptor.invokeInContext(AbstractRemoteSlsbInvokerInterceptor.java:140)
[err]   at org.springframework.ejb.access.AbstractSlsbInvokerInterceptor.invoke(AbstractSlsbInvokerInterceptor.java:189)
[err]   at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
[err]   at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:207)
[err]   at com.sun.proxy.$Proxy41.celsiusToFar(Unknown Source)
[err]   at com.ibm.common.controller.JSONController.lookupEJB(JSONController.java:89)
[err]   at com.ibm.common.controller.JSONController.getTempCtoF(JSONController.java:157)
[err]   at sun.reflect.GeneratedMethodAccessor663.invoke(Unknown Source)
[err]   at java.lang.reflect.Method.invoke(Method.java:498)
[err]   at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:221)
[err]   at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:137)
[err]   at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:110)
[err]   at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:806)
[err]   at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:729)
[err]   at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:85)
[err]   at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:959)
[err]   at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:893)
[err]   at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:970)
[err]   at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:861)
[err]   at javax.servlet.http.HttpServlet.service(HttpServlet.java:687)
[err]   at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:846)
[err]   at javax.servlet.http.HttpServlet.service(HttpServlet.java:790)
[err]   at com.ibm.ws.webcontainer.servlet.ServletWrapper.service(ServletWrapper.java:1258)
[err]   at [internal classes]
[err]   at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
[err]   at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
[err]   at java.lang.Thread.run(Thread.java:748)
[err] Caused by: java.lang.NoSuchMethodException: java.lang.String.celsiusToFar(double)
[err]   at java.lang.Class.getMethod(Class.java:1786)
[err]   at org.springframework.remoting.rmi.RmiClientInterceptorUtils.invokeRemoteMethod(RmiClientInterceptorUtils.java:75)
[err]   ... 48 more

很明显,远程查找没有解决问题,但我很困惑,因为我知道我可以手动访问它,所以连接字符串应该是有效的。

我是否会错过什么?

这最初用于传统WAS,但不用于Liberty

共有2个答案

帅令雪
2023-03-14

<code>@EJB</code>注释旨在提供与工作手册示例的前3行等效的内容,然后在应用注释的字段上设置结果。因此,它应该执行以下操作:

Context ctx = new InitialContext();
Object homeObject = ctx.lookup("corbaname::localhost:22809#ejb/global/TempEAR-0.0.1/com.ibm.temp-TempEJB-0.0.1/ConverterBean!com.ibm.temp.ejb.ConverterRemote")
ConverterRemote myRemoteEJB = (ConverterRemote) PortableRemoteObject.narrow(homeObject, ConverterRemote.class);

如果带有注释的字段位于JavaEE容器管理对象上,例如servlet、servlet过滤器、EJB、拦截器等。,那么Liberty将执行该行为,并且@EJB注释将按预期工作。

然而,在这个场景中,@EJB注释位于springframework管理的对象上,因此是springfframework执行@EJB注释的处理,并且springframework似乎省略了“PortableRemoteObject.nark()”的使用。

CORBA远程对象的COS命名查找不能保证返回远程接口的specific _Stub实现。它可能是一个通用存根类的实例,比如< code > org . OMG . Stub . Java . RMI . _ Remote _ Stub 。当springframework试图在这样的存根上调用方法时,它将失败,并出现NoSuchMethodException,因为存根没有实现远程接口。执行< code>narrow()将通用存根实例转换为实现远程接口的特定存根实例。如果可以更新springframework来执行< code>narrow(),那么这个场景就可以工作了。

这个场景的行为在传统的WebSphere和Liberty之间会有所不同,因为它们都使用非常不同的CORBA ORB实现。

传统的WebSphere使用IBMORB,它预计应用程序将需要一个特定的存根类,并尝试在查找时提供一个窄存根;随后的窄()调用将是无操作的。IBMORB主动处理窄存根,试图提高性能。但是,应该注意的是,即使使用IBMORB,查找时返回的存根也不总是特定的存根;应该始终执行窄()

Liberty使用Yoko ORB,它不试图在JNDI查找中返回特定的存根实例,因为这不是规范所要求的。返回的存根几乎总是通用存根,并且查找后应该总是跟有< code>narrow()。

要么需要更新应用程序以利用 Java EE 托管对象上的@EJB,要么需要更改 springframework 使用的机制以获取 EJB 引用,以便执行 narrow()

徐智渊
2023-03-14

@Tracy的回答100%正确解释了问题所在。不过,如果你在这里,你可能正在寻找现在该做什么。

我们能够通过扩展一些Spring类并稍微更改查找来解决这个问题。

以下是我们所做更改的摘要。

最初,我们的bean定义配置为

    <jee:remote-slsb id="testRemoteEJB"
        jndi-name="jndi/testRemoteEJB"
        business-interface="com.ibm.temp.ejb.ConverterRemote">
    </jee:remote-slsb>  

我们把这个换成了

       <bean id="testRemoteEJB"  class="com.ibm.ejb.access.MySimpleRemoteStatelessSessionProxyFactoryBean">
          <property name="jndiName" value="jndi/testRemoteEJB"/>
          <property name="businessInterface" value="com.ibm.temp.ejb.ConverterRemote"/>
        </bean>

我们创建了类 MySimple远程无状态会话代理代理工厂豆 通过扩展类 简单远程无状态会话代理工厂豆

我们覆盖了 create() 方法并手动执行了 EJB 查找。

package com.ibm.ejb.access;

import java.lang.reflect.InvocationTargetException;

import javax.naming.NamingException;
import javax.rmi.PortableRemoteObject;

import org.springframework.ejb.access.SimpleRemoteStatelessSessionProxyFactoryBean;

//import com.ibm.temp.ejb.ConverterRemote;

public class MySimpleRemoteStatelessSessionProxyFactoryBean extends SimpleRemoteStatelessSessionProxyFactoryBean {

    @Override
    protected Object create() throws NamingException, InvocationTargetException {
        System.out.println("MySimpleRemote: create()"); 
        
        
        //String remoteURL = "corbaname::localhost:22809#ejb/global/TempEAR-0.0.1/com.ibm.temp-TempEJB-0.0.1/ConverterBean!com.ibm.temp.ejb.ConverterRemote";
        Object homeObject = this.lookup();
        String jndiValue = homeObject.toString();
        System.out.println("jndi = "  + jndiValue);

        if (homeObject instanceof String) {
            //Note if your spring mvc references a jndi is looked up again, you might have to do a double lookup
            homeObject = this.lookup(jndiValue);
        }
        Object myEJB = PortableRemoteObject.narrow(homeObject, this.getBusinessInterface());
        System.out.println("jndi = "  + myEJB);
    
        return myEJB;
    }
}

根据您是否在 Spring xml 中传入远程查找 URL,或者是否传入 jndi 并在 Liberty 服务器中指定远程查找 URL.xml,代码必须执行 1 次或 2 次查找。然后我们手动处理窄。

这对我们来说是可行的,它允许客户不必对他们的原始代码做任何修改,只需修改spring xml配置文件。

我们创建了一个示例应用程序来演示这一点,你可以读到这里https://github.com/rcauchon/app-modernization-ejb

 类似资料:
  • 当我尝试从远程客户端访问在JBoss EAP 6.2中运行的EJB时,我收到以下异常: 我将这些属性用于调用远程ejb方法。 endpoint.name=客户端endpointremote.connectionprovider.create.options.org.xnio.选项。SSL_ENABLED=falseremote.connections=默认remote.connection.def

  • 我在本地机器上创建了两个liberty实例。我在服务器X中部署了一个包含远程ejb的war模块,并在服务器Y中部署了另一个war模块,它必须从服务器X中远程查找ejb。 下面是从宁静的 Web 服务中查找 ejb 的代码。 当我尝试调用 Web 服务时,我得到以下异常 本地对象不支持 DII 操作 P.S.我已经在两个端口号不同的服务器上启用了ejbRemote功能。 我将查找字符串更改为“cor

  • 我正试图通过MoneySend API在万事达卡的沙箱上提出付款请求。下面是C#的示例代码,也可以在这里找到 问题陈述: 完全异常: mastercard.core.exceptions.apiExceptions:无法解析远程名称:“sandbox.api.mastercard.com”-->system.net.webException:无法解析远程名称:“sandbox.api.master

  • 这样的问题已经问过好几次了,我明白为什么会发生,大概除了重试,我们对此无能为力。 我有一个关于名称解析的问题。 我使用的是3.5.NET的AWS.NET SDK。我正在上传一个大文件(>500MB到1.5GB,医学图像)。我调用方法。 错误发生在大约250MB上载完成后。 这是实际的例外

  • 我试图在Redbook示例(IBM WebSphere Application server Liberty Profile Guide for Developers,5.2.3使用远程EJB开发应用程序)中调用Liberty Profile服务器中的远程EJB。 所有编译和部署都没有问题,但在运行时会给出以下错误消息: 只有带有@local注释的接口是绑定的,并且它显示在日志中。带有@Remot

  • 我目前正在努力让远程EJB调用在wildfly(8.x和9.x)上工作。 详细来说,它是关于使用EJB客户机API方法从独立的客户机应用程序(而不是从另一个应用程序服务器)进行远程调用。远程命名方法适合我,但不适用于我的场景,因为我需要使用客户端拦截器将上下文数据传递给服务器端拦截器进行远程调用。 但是现在,为了一个简单的示例,我尝试使用客户机API进行远程调用。因此,我尝试了用于远程ejb调用的