diff --git a/dubbo-rpc/dubbo-rpc-rmi/src/main/java/org/apache/dubbo/rpc/protocol/rmi/RmiProtocol.java b/dubbo-rpc/dubbo-rpc-rmi/src/main/java/org/apache/dubbo/rpc/protocol/rmi/RmiProtocol.java index d3ba2e8fde0..63e9fcdfff1 100644 --- a/dubbo-rpc/dubbo-rpc-rmi/src/main/java/org/apache/dubbo/rpc/protocol/rmi/RmiProtocol.java +++ b/dubbo-rpc/dubbo-rpc-rmi/src/main/java/org/apache/dubbo/rpc/protocol/rmi/RmiProtocol.java @@ -20,10 +20,12 @@ import org.apache.dubbo.common.URL; import org.apache.dubbo.rpc.RpcException; import org.apache.dubbo.rpc.protocol.AbstractProxyProtocol; - +import org.apache.dubbo.rpc.service.GenericService; +import org.apache.dubbo.rpc.support.ProtocolUtils; import org.springframework.remoting.RemoteAccessException; import org.springframework.remoting.rmi.RmiProxyFactoryBean; import org.springframework.remoting.rmi.RmiServiceExporter; +import org.springframework.remoting.support.RemoteInvocation; import java.io.IOException; import java.net.SocketTimeoutException; @@ -50,21 +52,14 @@ public int getDefaultPort() { @Override protected Runnable doExport(final T impl, Class type, URL url) throws RpcException { - final RmiServiceExporter rmiServiceExporter = new RmiServiceExporter(); - rmiServiceExporter.setRegistryPort(url.getPort()); - rmiServiceExporter.setServiceName(url.getPath()); - rmiServiceExporter.setServiceInterface(type); - rmiServiceExporter.setService(impl); - try { - rmiServiceExporter.afterPropertiesSet(); - } catch (RemoteException e) { - throw new RpcException(e.getMessage(), e); - } + RmiServiceExporter rmiServiceExporter = createExporter(impl, type, url, false); + RmiServiceExporter genericServiceExporter = createExporter(impl, GenericService.class, url, true); return new Runnable() { @Override public void run() { try { rmiServiceExporter.destroy(); + genericServiceExporter.destroy(); } catch (Throwable e) { logger.warn(e.getMessage(), e); } @@ -76,6 +71,8 @@ public void run() { @SuppressWarnings("unchecked") protected T doRefer(final Class serviceType, final URL url) throws RpcException { final RmiProxyFactoryBean rmiProxyFactoryBean = new RmiProxyFactoryBean(); + final String generic = url.getParameter(Constants.GENERIC_KEY); + final boolean isGeneric = ProtocolUtils.isGeneric(generic) || serviceType.equals(GenericService.class); /* RMI needs extra parameter since it uses customized remote invocation object @@ -86,11 +83,27 @@ protected T doRefer(final Class serviceType, final URL url) throws RpcExc 3. if the provider version is lower than v2.6.3, does not use customized RemoteInvocation. */ if (isRelease270OrHigher(url.getParameter(Constants.RELEASE_KEY))) { - rmiProxyFactoryBean.setRemoteInvocationFactory(RmiRemoteInvocation::new); + rmiProxyFactoryBean.setRemoteInvocationFactory((methodInvocation) -> { + RemoteInvocation invocation = new RmiRemoteInvocation(methodInvocation); + if (invocation != null && isGeneric) { + invocation.addAttribute(Constants.GENERIC_KEY, generic); + } + return invocation; + }); } else if (isRelease263OrHigher(url.getParameter(Constants.DUBBO_VERSION_KEY))) { - rmiProxyFactoryBean.setRemoteInvocationFactory(com.alibaba.dubbo.rpc.protocol.rmi.RmiRemoteInvocation::new); + rmiProxyFactoryBean.setRemoteInvocationFactory((methodInvocation) -> { + RemoteInvocation invocation = new com.alibaba.dubbo.rpc.protocol.rmi.RmiRemoteInvocation(methodInvocation); + if (invocation != null && isGeneric) { + invocation.addAttribute(Constants.GENERIC_KEY, generic); + } + return invocation; + }); + } + String serviceUrl = url.toIdentityString(); + if (isGeneric) { + serviceUrl = serviceUrl + "/" + Constants.GENERIC_KEY; } - rmiProxyFactoryBean.setServiceUrl(url.toIdentityString()); + rmiProxyFactoryBean.setServiceUrl(serviceUrl); rmiProxyFactoryBean.setServiceInterface(serviceType); rmiProxyFactoryBean.setCacheStub(true); rmiProxyFactoryBean.setLookupStubOnStartup(true); @@ -117,4 +130,22 @@ protected int getErrorCode(Throwable e) { return super.getErrorCode(e); } + private RmiServiceExporter createExporter(T impl, Class type, URL url, boolean isGeneric) { + final RmiServiceExporter rmiServiceExporter = new RmiServiceExporter(); + rmiServiceExporter.setRegistryPort(url.getPort()); + if (isGeneric) { + rmiServiceExporter.setServiceName(url.getPath() + "/" + Constants.GENERIC_KEY); + } else { + rmiServiceExporter.setServiceName(url.getPath()); + } + rmiServiceExporter.setServiceInterface(type); + rmiServiceExporter.setService(impl); + try { + rmiServiceExporter.afterPropertiesSet(); + } catch (RemoteException e) { + throw new RpcException(e.getMessage(), e); + } + return rmiServiceExporter; + } + } diff --git a/dubbo-rpc/dubbo-rpc-rmi/src/main/java/org/apache/dubbo/rpc/protocol/rmi/RmiRemoteInvocation.java b/dubbo-rpc/dubbo-rpc-rmi/src/main/java/org/apache/dubbo/rpc/protocol/rmi/RmiRemoteInvocation.java index dbbe9d66867..96b49e7e493 100644 --- a/dubbo-rpc/dubbo-rpc-rmi/src/main/java/org/apache/dubbo/rpc/protocol/rmi/RmiRemoteInvocation.java +++ b/dubbo-rpc/dubbo-rpc-rmi/src/main/java/org/apache/dubbo/rpc/protocol/rmi/RmiRemoteInvocation.java @@ -16,6 +16,8 @@ */ package org.apache.dubbo.rpc.protocol.rmi; +import org.apache.dubbo.common.Constants; +import org.apache.dubbo.common.utils.StringUtils; import org.apache.dubbo.rpc.RpcContext; import org.aopalliance.intercept.MethodInvocation; @@ -34,7 +36,7 @@ public class RmiRemoteInvocation extends RemoteInvocation { */ public RmiRemoteInvocation(MethodInvocation methodInvocation) { super(methodInvocation); - addAttribute(dubboAttachmentsAttrName, new HashMap(RpcContext.getContext().getAttachments())); + addAttribute(dubboAttachmentsAttrName, new HashMap<>(RpcContext.getContext().getAttachments())); } /** @@ -48,6 +50,10 @@ public Object invoke(Object targetObject) throws NoSuchMethodException, IllegalA InvocationTargetException { RpcContext context = RpcContext.getContext(); context.setAttachments((Map) getAttribute(dubboAttachmentsAttrName)); + String generic = (String) getAttribute(Constants.GENERIC_KEY); + if (StringUtils.isNotEmpty(generic)) { + context.setAttachment(Constants.GENERIC_KEY, generic); + } try { return super.invoke(targetObject); } finally { diff --git a/dubbo-rpc/dubbo-rpc-rmi/src/test/java/org/apache/dubbo/rpc/protocol/rmi/DemoService.java b/dubbo-rpc/dubbo-rpc-rmi/src/test/java/org/apache/dubbo/rpc/protocol/rmi/DemoService.java index 9e1d334fbcf..c139b1afc28 100644 --- a/dubbo-rpc/dubbo-rpc-rmi/src/test/java/org/apache/dubbo/rpc/protocol/rmi/DemoService.java +++ b/dubbo-rpc/dubbo-rpc-rmi/src/test/java/org/apache/dubbo/rpc/protocol/rmi/DemoService.java @@ -23,6 +23,8 @@ public interface DemoService { void sayHello(String name); + String sayHi(String name); + String echo(String text); long timestamp(); diff --git a/dubbo-rpc/dubbo-rpc-rmi/src/test/java/org/apache/dubbo/rpc/protocol/rmi/DemoServiceImpl.java b/dubbo-rpc/dubbo-rpc-rmi/src/test/java/org/apache/dubbo/rpc/protocol/rmi/DemoServiceImpl.java index 833969b2431..ec461eb6f11 100644 --- a/dubbo-rpc/dubbo-rpc-rmi/src/test/java/org/apache/dubbo/rpc/protocol/rmi/DemoServiceImpl.java +++ b/dubbo-rpc/dubbo-rpc-rmi/src/test/java/org/apache/dubbo/rpc/protocol/rmi/DemoServiceImpl.java @@ -31,6 +31,10 @@ public void sayHello(String name) { System.out.println("hello " + name); } + public String sayHi(String name) { + return "Hi, " + name; + } + public String echo(String text) { return text; } diff --git a/dubbo-rpc/dubbo-rpc-rmi/src/test/java/org/apache/dubbo/rpc/protocol/rmi/RmiProtocolTest.java b/dubbo-rpc/dubbo-rpc-rmi/src/test/java/org/apache/dubbo/rpc/protocol/rmi/RmiProtocolTest.java index a1853618823..4dcd21dfccb 100644 --- a/dubbo-rpc/dubbo-rpc-rmi/src/test/java/org/apache/dubbo/rpc/protocol/rmi/RmiProtocolTest.java +++ b/dubbo-rpc/dubbo-rpc-rmi/src/test/java/org/apache/dubbo/rpc/protocol/rmi/RmiProtocolTest.java @@ -23,8 +23,11 @@ import org.apache.dubbo.rpc.Protocol; import org.apache.dubbo.rpc.ProxyFactory; import org.apache.dubbo.rpc.RpcException; +import org.apache.dubbo.rpc.Invoker; import org.apache.dubbo.rpc.service.EchoService; +import org.apache.dubbo.rpc.service.GenericService; +import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; @@ -115,6 +118,19 @@ public void testRmiProtocol_echoService() throws Exception { rpcExporter.unexport(); } + @Test + public void testGenericInvoke() { + DemoService service = new DemoServiceImpl(); + URL url = URL.valueOf("rmi://127.0.0.1:9003/" + DemoService.class.getName() + "?release=2.7.0"); + Exporter exporter = protocol.export(proxy.getInvoker(service, DemoService.class, url)); + Invoker invoker = protocol.refer(GenericService.class, url); + GenericService client = proxy.getProxy(invoker, true); + String result = (String) client.$invoke("sayHi", new String[]{"java.lang.String"}, new Object[]{"haha"}); + Assertions.assertEquals("Hi, haha", result); + invoker.destroy(); + exporter.unexport(); + } + public static interface NonStdRmiInterface { void bark(); }