背景:
在分布式计算中,经常涉及到多服务器之间不同进程的通信与计算交互,所以就需要用到远端调用。比如可以基于Http进行调用,或者WebService技术,或者RMI。通过这种技术,就可以进行服务能力的扩展,实现分布式计算。
Spring为远端调用的实现提供了许多不同的方案,比如Http调用器、第三方远端调用库Hessian/Burlap、RMI、基于Java RMI的解决方案等。这几种方案的套路其实都差不多,接下来我们就只看一下Http调用器的设计和实现原理。
Spring Http调用器
这个调用器,顾名思义,是基于HTTP协议的远程调用,分为客户端和服务端。客户端的功能是打开Http连接,将请求对象序列化,将请求发送给服务端。对于服务端来说,负责接收请求,将请求中对象反序列化,处理请求,把结果序列化之后通过http返回到客户端。接下来就看下具体的代码。
Http调用器客户端
客户端的服务配置是通过HttpInvokerProxyFactoryBean实现的,下面是HttpInvokerProxyFactoryBean的定义:
public class HttpInvokerProxyFactoryBean extends HttpInvokerClientInterceptor
implements FactoryBean<Object> {
private Object serviceProxy;
@Override
public void afterPropertiesSet() {
super.afterPropertiesSet();
if (getServiceInterface() == null) {
throw new IllegalArgumentException("Property 'serviceInterface' is required");
}
this.serviceProxy = new ProxyFactory(getServiceInterface(), this).getProxy(getBeanClassLoader());
}
@Override
public Object getObject() {
return this.serviceProxy;
}
@Override
public Class<?> getObjectType() {
return getServiceInterface();
}
@Override
public boolean isSingleton() {
return true;
}
}
HttpInvokerProxyFactoryBean间接实现了InitializingBean接口,重写了afterPropertiesSet方法。在afterPropertiesSet方法中,生成了一个代理对象,赋值给了serviceProxy。在new ProxyFactory的时候,构造函数第二个参数,传入了this,这个参数是接收一个Interceptor对象的,HttpInvokerProxyFactoryBean继承了HttpInvokerClientInterceptor,所以这个Interceptor对象就是HttpInvokerClientInterceptor。这个参数会作为一个Advice设置到代理对象中。
根据之前分析过的Spring AOP的实现原理,Advice会设置为代理对象的拦截器,在调用目标对象方法是,会触发代理对象中的拦截器方法,所以,我们再看下HttpInvokerClientInterceptor中的invoke代码:
@Override
public Object invoke(MethodInvocation methodInvocation) throws Throwable {
if (AopUtils.isToStringMethod(methodInvocation.getMethod())) {
return "HTTP invoker proxy for service URL [" + getServiceUrl() + "]";
}
// 创建RemoteInvocation对象,封装了对远端的调用信息
RemoteInvocation invocation = createRemoteInvocation(methodInvocation);
RemoteInvocationResult result;
try {
// 实际的调用入口
result = executeRequest(invocation, methodInvocation);
}
catch (Throwable ex) {
throw convertHttpInvokerAccessException(ex);
}
try {
// 返回结果
return recreateRemoteInvocationResult(result);
}
catch (Throwable ex) {
if (result.hasInvocationTargetException()) {
throw ex;
}
else {
throw new RemoteInvocationFailureException("