Java 作为RmiServiceExporter(或RMI的替代方案)代理的服务的参考返回值公开
如果我通过RMI使用Java 作为RmiServiceExporter(或RMI的替代方案)代理的服务的参考返回值公开,java,spring,rmi,Java,Spring,Rmi,如果我通过RMI使用RmiServiceExporter导出服务,服务调用的返回值将被序列化并通过线路发送到客户端。但是,除非我有一个简单的返回数据的服务,否则这不是很有用 我希望能够对这个返回值调用方法,并让它们在服务器上运行,而不是在客户机上运行。本质上,我希望在客户端上创建一个返回值的代理。使用RmiServiceExporter(或Spring支持的另一个远程处理选项)有什么方法可以做到这一点吗 我尝试实现一些返回值的自动包装,这就是我想到的: 在服务器端: class RmiRetu
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
}
}
}
这似乎适用于两个级别的包装;在这种情况下,服务将返回列表
。我怀疑这有很多问题,首先是调用UnicastRemoteObject.exportObject
而从未回收任何东西。这里可能还缺少的另一件事是处理这些存根的传递,这些存根是客户端作为参数传递给服务的。因为参数是在客户机上创建的Proxy
对象(包装RMI存根),我想至少服务器必须从客户机加载类,这是我想要避免的
我的问题是,是否已经实现了类似的功能(不一定使用RMI),我可以轻松指定哪些类型作为值返回并序列化,哪些类型的返回值应该存根。如果任何远程方法的返回值是导出的远程对象,这是一个古老的问题,起源于CORBA、Jini和EJB的第一个版本等技术。这个想法大部分被抛弃了,因为它根本无法很好地扩展 由于网络开销,无法将远程对象透明地视为本地对象。由于网络延迟,在调用远程对象时,您希望在远程调用中打包最多的数据, 而在本地对象中,您更喜欢保持方法调用尽可能细粒度,以便从OO的角度来看,它们可以是最可重用的 方法可重用性和低网络开销这两个要求相互冲突,最终结果是远程对象的API总是与本地对象的API非常不同, 即使存在对远程对象进行完全透明的调用的技术 目前广泛采用的解决方案是通过有线传输,这是一种仅用于数据的对象。这可以在RMI、HTTP(REST)、SOAP或其他协议中完成 然后在每一端都可以对域模型进行一些映射,以便在其中写入服务和持久性层。另一方面,DTO模型并不意味着要跨越表示层 我的问题是,是否已经实现了类似的功能(不是 必须使用RMI),我可以很容易地指定所使用的类型 作为值返回并序列化,以及返回值的类型 应该留个存根 我想建议的第一件也是最重要的事情是,您应该摆脱
RMI
<代码>RMI在您考虑它时是相当低的级别为什么要一路回到CORBA?唯一的答案可能是您不需要Java EEEJB
app服务器。但是您必须保持客户端和服务器JVM同步。如果不升级服务器,就不能升级客户端。您必须编写EJB应用服务器为您提供的所有服务(例如,连接池、命名和目录服务、池、请求队列、事务等)
EJB与RMI的对比
EJB构建在RMI之上。两者都暗示了Java客户机和bean。如果您的客户机需要用其他语言(例如.NET、PHP等)编写,请使用web服务或使用与平台无关的有线协议的其他语言,如HTTP或XML over HTTP或SOAP
Spring vs EJB
与Spring相比,EJB3.0中更好的选择取决于您是否喜欢POJO开发,除了ORM和JPA之外,还需要选择关系技术。EJB3.0的优点是EJB3.0是许多供应商的规范;弹簧只能从弹簧源获得。然而,弹簧非常坚固,具有很大的牵引力,不会移动。这会让你有更多的选择
WebServices
Spring的web服务模块在POJO服务接口方面非常灵活。这将允许您获得所需的概念隔离,将部署选择推迟到最后一刻,并允许您在第一个想法执行不好时改变主意。Web服务在理论上很好,但有一些问题需要注意:
- 延迟。Fowler的分布式对象第一定律:“不要!”一个由许多细粒度分布式SOAP服务组成的体系结构将是优雅、漂亮、缓慢的。分发前仔细考虑
- 从XML到对象和从对象到对象的编组会消耗CPU周期,这些CPU周期除了允许您的客户机使用平台无关协议之外,不会提供任何业务价值
- SOAP是一个标准,它每天都变得越来越臃肿和复杂,但它有很多工具支持。供应商喜欢它,因为它有助于推动ESB的销售。REST很简单,但不太容易理解。工具不支持它
最后,我建议使用SpringWeb服务谢谢,但即使是这样,也没有真正帮助我。我希望能够作为存根发送到客户端的对象数量是无限的。它们是从显式导出的服务创建的。我想要的是能够配置