gpt4 book ai didi

java - 公开为 RmiServiceExporter 代理的服务的引用返回值(或 RMI 的替代方案)

转载 作者:行者123 更新时间:2023-11-30 03:59:33 25 4
gpt4 key购买 nike

如果我通过 RMI 导出服务 RmiServiceExporter ,服务调用的返回值被序列化并通过线路发送到客户端。但除非我有一个返回简单数据的简单服务,否则这不是很有用。

我也希望能够在此返回值上调用方法,并让它们在服务器上运行,而不是在客户端上运行。本质上,我想要一个在客户端上创建的返回值的代理。有没有办法用 RmiServiceExporter 来做到这一点(或者 Spring 支持的另一个远程处理选项)?

<小时/>

我尝试实现一些返回值的自动换行,这就是我的想法:

在服务器端:

class RmiReturnValueStubbingExporter extends RmiServiceExporter {

/* we can't use the Spring implementation of RmiInvocationHandler
* because it's package protected */
private class RmiReturnValueInvocationWrapper implements RmiInvocationHandler {
private final Object wrappedObject;

private RmiReturnValueInvocationWrapper(Class interf, Object wrappedObject) {
this.wrappedObject = createProxyFor(interf, wrappedObject);
}

@Override
public String getTargetInterfaceName() throws RemoteException {
return null;
}

@Override
public Object invoke(RemoteInvocation invocation) throws
RemoteException, NoSuchMethodException, IllegalAccessException,
InvocationTargetException {
return RmiReturnValueStubbingExporter.this.invoke(
invocation, this.wrappedObject);
}
}

@Override
protected Object invoke(RemoteInvocation invocation, Object targetObject)
throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
Object ret = maybeWrap(super.invoke(invocation, targetObject));

if (ret instanceof Remote) {
try {
UnicastRemoteObject.exportObject((Remote) ret, 0);
} catch (RemoteException e) {
throw new InvocationTargetException(e);
}
}

return ret;
}

private Object maybeWrap(Object superValue) {
if (superValue instanceof OntologyTerm) {
return new RmiReturnValueInvocationWrapper(
OntologyTerm.class, superValue);
} else if (superValue instanceof List) {
return new RmiReturnValueInvocationWrapper(
List.class, superValue);
} else {
return superValue;
}
}

private Object createProxyFor(Class interf, Object object) {
ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.addInterface(interf);
proxyFactory.addAdvice(new RemoteInvocationTraceInterceptor(getExporterName()));

proxyFactory.setTarget(object);
// don't make opaque, on the client we need to know the interfaces implemented
return proxyFactory.getProxy(getBeanClassLoader());
}
}

在客户端:

class RmiStubReturnValueProxyFactoryBean extends RmiProxyFactoryBean {

@Override
protected Object doInvoke(MethodInvocation methodInvocation,
RmiInvocationHandler invocationHandler) {

def superValue = super.doInvoke(methodInvocation, invocationHandler)

if (superValue instanceof java.lang.reflect.Proxy &&
java.lang.reflect.Proxy.getInvocationHandler(superValue)
instanceof RemoteObjectInvocationHandler) {
RmiInvocationHandler rih = superValue

def proxiedInterfaces = rih.invoke(
new RemoteInvocation('getProxiedInterfaces',
[] as Class[], [] as Object[]))

def clientProxy = new ProxyFactory(proxiedInterfaces)

clientProxy.addAdvice({ MethodInvocation invoc ->
doInvoke(invoc, rih)
} as MethodInterceptor)

clientProxy.getProxy beanClassLoader
} else {
superValue
}
}
}

这似乎适用于两层包装;在这种情况下,服务返回 List<OntologyTerm> 。我怀疑这有相当大的问题,首先调用UnicastRemoteObject.exportObject没有回收任何东西。这里可能还缺少的另一件事是处理客户端作为服务参数获取的这些 stub 的传递。因为参数是 Proxy在客户端创建的对象(包装 RMI stub ),我想服务器至少必须从客户端加载类,这是我想避免的事情。

我的问题是,是否已经实现了类似的东西(不一定使用 RMI),我可以轻松地指定哪些类型作为值返回并序列化,以及哪些类型的返回值应该被 stub 。

最佳答案

这是一个古老的问题,它起源于 CORBA、Jini 和 EJB 的第一个版本等技术。这个想法大多被放弃,因为它根本无法很好地扩展。

由于网络开销,远程对象不能被透明地视为本地对象。由于网络延迟,当调用远程对象时,您希望在远程调用中打包最多的数据,而在本地对象中,您更喜欢使方法调用保持尽可能的细粒度,以便从面向对象的角度来看它们是最可重用的。

方法可重用性和低网络开销这两个要求发生冲突,最终结果是远程对象的 API 总是与本地对象的 API 有很大不同,即使存在可以完全透明地调用远程对象的技术。

目前广泛采用的解决方案是发送 DTOs (Data Transfer Objects)通过网络,它们只是数据对象。这可以通过 RMI、HTTP (REST)、SOAP 或其他协议(protocol)来完成。

然后在每一端都可以对域模型进行一些映射,以便可以在其中写入服务和持久层。另一方面,DTO 模型并不意味着跨越表示层。

关于java - 公开为 RmiServiceExporter 代理的服务的引用返回值(或 RMI 的替代方案),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22299077/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com