12 远程服务

felix.shao2025-03-14

12 远程服务

12.1 RMI

 略。

12.1.1 使用示例

RMI 使用示例

 参考步骤如下。

  1. 建立 RMI 对外接口。
  2. 建立接口实现类。
  3. 建立服务端配置文件。
  4. 建立服务断测试。
  5. 建立测试端配置文件。
  6. 编写测试代码。

 具体 demo 见 com.stu.spring.context.chapter12.rmi.ServerTest,不过由于 Window 以及 Linux 下,RMI 解析 host 等问题。

  • 实际观测发现,Spring demo 会出现远程连接拒绝问题,然后转本地处理。

12.1.2 服务端实现

RmiServiceExporter 类层次结构

 服务实现类关键类是 RmiServiceExporter,以下是其类层次结构。

RmiServiceExporter
  RmiBasedExporter
    RemoteInvocationBasedExporter
      RemoteExporter
        RemotingSupport
          Object
          BeanClassLoaderAware
            Aware 
  InitializingBean
  DisposableBean
RmiServiceExporter 初始化
public class RmiServiceExporter extends RmiBasedExporter implements InitializingBean, DisposableBean {
    public void afterPropertiesSet() throws RemoteException {
		prepare();
	}

    public void prepare() throws RemoteException {
        // 检测校验 service
		checkService();

		if (this.serviceName == null) {
			throw new IllegalArgumentException("Property 'serviceName' is required");
		}

		// 如果用户在配置中配置了 clientSocketFactory 或者 serverSocketFactory 的处理
		if (this.clientSocketFactory instanceof RMIServerSocketFactory) {
            // 如果 clientSocketFactory 同时又实现了 RMIServerSocketFactory,那么会忽略配置中的 serverSocketFactory 而使用 clientSocketFactory
			this.serverSocketFactory = (RMIServerSocketFactory) this.clientSocketFactory;
		}
        // clientSocketFactory 和 serverSocketFactory 要么同时出现,要么都不出现
		if ((this.clientSocketFactory != null && this.serverSocketFactory == null) ||
				(this.clientSocketFactory == null && this.serverSocketFactory != null)) {
			throw new IllegalArgumentException(
					"Both RMIClientSocketFactory and RMIServerSocketFactory or none required");
		}

		// 如果配置中的 registryClientSocketFactory 同时实现了 RMIServerSocketFactory,那么会忽略配置中的 registryServerSocketFactory 而使用 registryClientSocketFactory
		if (this.registryClientSocketFactory instanceof RMIServerSocketFactory) {
			this.registryServerSocketFactory = (RMIServerSocketFactory) this.registryClientSocketFactory;
		}
        // 不允许出现只配置 registryClientSocketFactory 却没有配置 registryServerSocketFactory 
		if (this.registryClientSocketFactory == null && this.registryServerSocketFactory != null) {
			throw new IllegalArgumentException(
					"RMIServerSocketFactory without RMIClientSocketFactory for registry not supported");
		}

		this.createdRegistry = false;

		// 确定 RMI registry
		if (this.registry == null) {
			this.registry = getRegistry(this.registryHost, this.registryPort,
				this.registryClientSocketFactory, this.registryServerSocketFactory);
			this.createdRegistry = true;
		}

		// 初始化以及缓存导出的 Object.
		this.exportedObject = getObjectToExport();

		if (logger.isDebugEnabled()) {
			logger.debug("Binding service '" + this.serviceName + "' to RMI registry: " + this.registry);
		}

		// Export RMI object.
		if (this.clientSocketFactory != null) {
            /**
             * 使用由给定的套接字工厂指定的传送方式导出远程对象,以便能够接收传入的调用
             * clientSocketFactory: 进行远程对象调用的客户端套接字工厂
             * serverSocketFactory: 接收远程调用的服务端套接字工厂
             */
			UnicastRemoteObject.exportObject(
					this.exportedObject, this.servicePort, this.clientSocketFactory, this.serverSocketFactory);
		}
		else {
            // 导出 remote object,以使它能接收特定端口的调用
			UnicastRemoteObject.exportObject(this.exportedObject, this.servicePort);
		}

		// Bind RMI object to registry.
		try {
			if (this.replaceExistingBinding) {
				this.registry.rebind(this.serviceName, this.exportedObject);
			}
			else {
                // 绑定服务名称到 remote object,外界调用 serviceName 的时候会被 exportedObject 接收
				this.registry.bind(this.serviceName, this.exportedObject);
			}
		}
		catch (AlreadyBoundException ex) {
			// Already an RMI object bound for the specified service name...
			unexportObjectSilently();
			throw new IllegalStateException(
					"Already an RMI object bound for name '"  + this.serviceName + "': " + ex.toString());
		}
		catch (RemoteException ex) {
			// Registry binding failed: let's unexport the RMI object as well.
			unexportObjectSilently();
			throw ex;
		}
	}
}

 发布流程如下。

  1. 校验 service。
  2. 处理用户自定义的 SocketFactory 属性。

 registryClientSocketFactory 与 registryClientSocketFactory 用于主机与 RMI 服务器之间连接的创建。
 clientSocketFactory、serverSocketFactory 用于导出远程对象,serverSocketFactory 用于在服务端建立套接字等待客户端连接,而 clientSocketFactory 用于调用端建立套接字发起连接。
3. 根据配置参数获取 Registry。 4. 构造对外发布的实例。
5. 发布实例。

 1. 获取 Registry
public class RmiServiceExporter extends RmiBasedExporter implements InitializingBean, DisposableBean {
    // 考虑了注册主机和发布的服务并不在一台机器上的场景
    protected Registry getRegistry(String registryHost, int registryPort,
			@Nullable RMIClientSocketFactory clientSocketFactory, @Nullable RMIServerSocketFactory serverSocketFactory)
			throws RemoteException {

		if (registryHost != null) {
			// 远程连接测试
			if (logger.isDebugEnabled()) {
				logger.debug("Looking for RMI registry at port '" + registryPort + "' of host [" + registryHost + "]");
			}
            // 如果 registryHost 不为空则尝试获取对应主机的 Registry
			Registry reg = LocateRegistry.getRegistry(registryHost, registryPort, clientSocketFactory);
			testRegistry(reg);
			return reg;
		}

		else {
            // 获取本地的 Registry
			return getRegistry(registryPort, clientSocketFactory, serverSocketFactory);
		}
	}

    protected Registry getRegistry(int registryPort,
			@Nullable RMIClientSocketFactory clientSocketFactory, @Nullable RMIServerSocketFactory serverSocketFactory)
			throws RemoteException {

		if (clientSocketFactory != null) {
			if (this.alwaysCreateRegistry) {
                // alwaysCreateRegistry 为 true,会首先测试是否已经建立了对指定端口的连接,如果已经建立则复用已经创建的实例,否则重新创建
				logger.debug("Creating new RMI registry");
                // 使用 clientSocketFactory 创建 Registry
				return LocateRegistry.createRegistry(registryPort, clientSocketFactory, serverSocketFactory);
			}
			if (logger.isDebugEnabled()) {
				logger.debug("Looking for RMI registry at port '" + registryPort + "', using custom socket factory");
			}
			synchronized (LocateRegistry.class) {
				try {
					// 复用测试.
					Registry reg = LocateRegistry.getRegistry(null, registryPort, clientSocketFactory);
					testRegistry(reg);
					return reg;
				}
				catch (RemoteException ex) {
					logger.trace("RMI registry access threw exception", ex);
					logger.debug("Could not detect RMI registry - creating new one");
					// Assume no registry found -> create new one.
					return LocateRegistry.createRegistry(registryPort, clientSocketFactory, serverSocketFactory);
				}
			}
		}

		else {
            // 如果创建 Registry 实例时不需要使用自定义的套接字工厂,那么就看可以直接使用 LocateRegistry.createRegistry 来创建了
			return getRegistry(registryPort);
		}
	}

    protected Registry getRegistry(int registryPort) throws RemoteException {
		if (this.alwaysCreateRegistry) {
			logger.debug("Creating new RMI registry");
			return LocateRegistry.createRegistry(registryPort);
		}
		if (logger.isDebugEnabled()) {
			logger.debug("Looking for RMI registry at port '" + registryPort + "'");
		}
		synchronized (LocateRegistry.class) {
			try {
				// 查看对应当前 registryPort 的 registry 是否已经创建,如果创建直接使用.
				Registry reg = LocateRegistry.getRegistry(registryPort);
                // 测试是否可用,如果不可用则抛出异常
				testRegistry(reg);
				return reg;
			}
			catch (RemoteException ex) {
				logger.trace("RMI registry access threw exception", ex);
				logger.debug("Could not detect RMI registry - creating new one");
				// 根据端口创建 Registry.
				return LocateRegistry.createRegistry(registryPort);
			}
		}
	}
}
 2. 初始化要导出的实体对象
public class RmiServiceExporter extends RmiBasedExporter implements InitializingBean, DisposableBean {
    protected Remote getObjectToExport() {
		// 如果配置的 service 属性对应的类实现了 Remote 接口且没有配置 serviceInterface 属性,那么直接使用 service 作为处理类
		if (getService() instanceof Remote &&
				(getServiceInterface() == null || Remote.class.isAssignableFrom(getServiceInterface()))) {
			// conventional RMI service
			return (Remote) getService();
		}
		else {
			// RMI invoker
			if (logger.isDebugEnabled()) {
				logger.debug("RMI service [" + getService() + "] is an RMI invoker");
			}
            // 使用 RmiInvocationWrapper 对 service 进行封装
			return new RmiInvocationWrapper(getProxyForService(), this);
		}
	}
}

public abstract class RmiBasedExporter extends RemoteInvocationBasedExporter {
    protected Remote getObjectToExport() {
		// determine remote object
		if (getService() instanceof Remote &&
				(getServiceInterface() == null || Remote.class.isAssignableFrom(getServiceInterface()))) {
			// conventional RMI service
			return (Remote) getService();
		}
		else {
			// RMI invoker
			if (logger.isDebugEnabled()) {
				logger.debug("RMI service [" + getService() + "] is an RMI invoker");
			}
			return new RmiInvocationWrapper(getProxyForService(), this);
		}
	}
}

public abstract class RemoteExporter extends RemotingSupport {
    protected Object getProxyForService() {
        // 验证 service
		checkService();
        // 验证 serviceInterface
		checkServiceInterface();

        // 使用 JDK 的方式创建代理
		ProxyFactory proxyFactory = new ProxyFactory();
        // 添加代理接口
		proxyFactory.addInterface(getServiceInterface());

		if (this.registerTraceInterceptor != null ? this.registerTraceInterceptor : this.interceptors == null) {
            // 加入代理的横切面 RemoteInvocationTraceInterceptor 并记录 Exporter 名称
			proxyFactory.addAdvice(new RemoteInvocationTraceInterceptor(getExporterName()));
		}
		if (this.interceptors != null) {
			AdvisorAdapterRegistry adapterRegistry = GlobalAdvisorAdapterRegistry.getInstance();
			for (Object interceptor : this.interceptors) {
				proxyFactory.addAdvisor(adapterRegistry.wrap(interceptor));
			}
		}
        // 设置要代理的目标类
		proxyFactory.setTarget(getService());
		proxyFactory.setOpaque(true);

        // 创建代理
		return proxyFactory.getProxy(getBeanClassLoader());
	}
}
 3. RMI 服务激活调用

 prepare() 方法里面做了服务名称绑定 this.registry.bind(this.serviceName, this.exportedObject),其中的 exportedObject 其实是被 RemoteInvocationTraceInterceptor 进行过封装的,也就是说当其他服务器调用 serviceName 的 RMI 服务时,Java 会为我们封装其内部操作,而直接会将代码转型 RMIInvocationWrapper 的 invoke 方法中。

class RmiInvocationWrapper implements RmiInvocationHandler {
    public Object invoke(RemoteInvocation invocation)
		throws RemoteException, NoSuchMethodException, IllegalAccessException, InvocationTargetException {

        // rmiExporter 为之前初始化的 RMIServiceExporter,invocation 为包含着需要激活的方法参数,而 wrappedObject 则是之前封装的代理类
		return this.rmiExporter.invoke(invocation, this.wrappedObject);
	}
}

public abstract class RmiBasedExporter extends RemoteInvocationBasedExporter {
    protected Object invoke(RemoteInvocation invocation, Object targetObject)
			throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {

		return super.invoke(invocation, targetObject);
	}
}

public abstract class RemoteInvocationBasedExporter extends RemoteExporter {
    protected Object invoke(RemoteInvocation invocation, Object targetObject)
			throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {

		if (logger.isTraceEnabled()) {
			logger.trace("Executing " + invocation);
		}
		try {
			return getRemoteInvocationExecutor().invoke(invocation, targetObject);
		}
		catch (NoSuchMethodException ex) {
			if (logger.isDebugEnabled()) {
				logger.debug("Could not find target method for " + invocation, ex);
			}
			throw ex;
		}
		catch (IllegalAccessException ex) {
			if (logger.isDebugEnabled()) {
				logger.debug("Could not access target method for " + invocation, ex);
			}
			throw ex;
		}
		catch (InvocationTargetException ex) {
			if (logger.isDebugEnabled()) {
				logger.debug("Target method failed for " + invocation, ex.getTargetException());
			}
			throw ex;
		}
	}
}

public class DefaultRemoteInvocationExecutor implements RemoteInvocationExecutor {
    public Object invoke(RemoteInvocation invocation, Object targetObject)
			throws NoSuchMethodException, IllegalAccessException, InvocationTargetException{

		Assert.notNull(invocation, "RemoteInvocation must not be null");
		Assert.notNull(targetObject, "Target object must not be null");
        // 通过反射方式激活方法
		return invocation.invoke(targetObject);
	}
}

public class RemoteInvocation implements Serializable {
    public Object invoke(Object targetObject)
			throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
        // 根据方法名称获取代理类中对应方法
		Method method = targetObject.getClass().getMethod(this.methodName, this.parameterTypes);
        // 执行代理中的方法
		return method.invoke(targetObject, this.arguments);
	}
}

12.1.3 客户端实现

RmiProxyFactoryBean 类层次结构
RmiProxyFactoryBean
    RmiClientInterceptor
        RemoteInvocationBasedAccessor
            UrlBasedRemoteAccessor
                RemoteAccessor
                    RemotingSupport
                        Object
                        BeanClassLoaderAware
                            Aware
                InitializingBean
        MethodInterceptor
    FactoryBean
    BeanClassLoaderAware
        Aware
 RmiProxyFactoryBean 初始化
public class RmiProxyFactoryBean extends RmiClientInterceptor implements FactoryBean<Object>, BeanClassLoaderAware {
    public void afterPropertiesSet() {
		super.afterPropertiesSet();
		Class<?> ifc = getServiceInterface();
		Assert.notNull(ifc, "Property 'serviceInterface' is required");
        // 根据设置的接口创建代理,并使用当前类 this 作为增强器
		this.serviceProxy = new ProxyFactory(ifc, this).getProxy(getBeanClassLoader());
	}

    public Object getObject() {
		return this.serviceProxy;
	}
}

public class RmiClientInterceptor extends RemoteInvocationBasedAccessor
		implements MethodInterceptor {
    public void afterPropertiesSet() {
		super.afterPropertiesSet();
		prepare();
	}
}

public abstract class UrlBasedRemoteAccessor extends RemoteAccessor implements InitializingBean {
    public void afterPropertiesSet() {
		if (getServiceUrl() == null) {
			throw new IllegalArgumentException("Property 'serviceUrl' is required");
		}
	}
}
 1. 通过代理并获取 stub
public class RmiClientInterceptor extends RemoteInvocationBasedAccessor
		implements MethodInterceptor {
    public void prepare() throws RemoteLookupFailureException {
		// 如果配置了 lookupStubOnStartup 属性便会在启动时寻找 stub,生效时系统启动时被执行并缓存,从而提高使用时候的响应时间
		if (this.lookupStubOnStartup) {
			Remote remoteObj = lookupStub();
			if (logger.isDebugEnabled()) {
				if (remoteObj instanceof RmiInvocationHandler) {
					logger.debug("RMI stub [" + getServiceUrl() + "] is an RMI invoker");
				}
				else if (getServiceInterface() != null) {
					boolean isImpl = getServiceInterface().isInstance(remoteObj);
					logger.debug("Using service interface [" + getServiceInterface().getName() +
						"] for RMI stub [" + getServiceUrl() + "] - " +
						(!isImpl ? "not " : "") + "directly implemented");
				}
			}
			if (this.cacheStub) {
                // 将获取的 stub 缓存
				this.cachedStub = remoteObj;
			}
		}
	}
}

 获取 stub 是 RMI 应用中的关键步骤,可以使用下面两种方式进行。

  • 使用自定义的套接字工厂。如果使用这种方式,你需要在构造 Registry 实例时将自定义套接字工厂传入,并使用 Registry 中提供的 lookup 方法来获取对应的 stub。
  • 直接使用 RMI 提供的标准方法:Naming.lookup 方法来获取对应的 stub。
public class RmiClientInterceptor extends RemoteInvocationBasedAccessor
		implements MethodInterceptor {
    protected Remote lookupStub() throws RemoteLookupFailureException {
		try {
			Remote stub = null;
			if (this.registryClientSocketFactory != null) {
				URL url = new URL(null, getServiceUrl(), new DummyURLStreamHandler());
				String protocol = url.getProtocol();
                // 验证传输协议
				if (protocol != null && !"rmi".equals(protocol)) {
					throw new MalformedURLException("Invalid URL scheme '" + protocol + "'");
				}
                // 主机
				String host = url.getHost();
                // 端口
				int port = url.getPort();
                // 服务名
				String name = url.getPath();
				if (name != null && name.startsWith("/")) {
					name = name.substring(1);
				}
                // 连接 RMI 服务器
				Registry registry = LocateRegistry.getRegistry(host, port, this.registryClientSocketFactory);
				stub = registry.lookup(name);
			}
			else {
				// Can proceed with standard RMI lookup API...
				stub = Naming.lookup(getServiceUrl());
			}
			if (logger.isDebugEnabled()) {
				logger.debug("Located RMI stub with URL [" + getServiceUrl() + "]");
			}
			return stub;
		}
		catch (MalformedURLException ex) {
			throw new RemoteLookupFailureException("Service URL [" + getServiceUrl() + "] is invalid", ex);
		}
		catch (NotBoundException ex) {
			throw new RemoteLookupFailureException(
					"Could not find RMI service [" + getServiceUrl() + "] in RMI registry", ex);
		}
		catch (RemoteException ex) {
			throw new RemoteLookupFailureException("Lookup of RMI stub failed", ex);
		}
	}
}
 2. 增强器进行远程连接
public class RmiClientInterceptor extends RemoteInvocationBasedAccessor
		implements MethodInterceptor {
    public Object invoke(MethodInvocation invocation) throws Throwable {
        // 获取的服务器中对应的注册的 remote 对象,通过序列化传输
		Remote stub = getStub();
		try {
			return doInvoke(invocation, stub);
		}
		catch (RemoteConnectFailureException ex) {
			return handleRemoteConnectFailure(invocation, ex);
		}
		catch (RemoteException ex) {
			if (isConnectFailure(ex)) {
				return handleRemoteConnectFailure(invocation, ex);
			}
			else {
				throw ex;
			}
		}
	}

    protected Remote getStub() throws RemoteLookupFailureException {
		if (!this.cacheStub || (this.lookupStubOnStartup && !this.refreshStubOnConnectFailure)) {
            // 如果有缓存直接使用缓存
			return (this.cachedStub != null ? this.cachedStub : lookupStub());
		}
		else {
			synchronized (this.stubMonitor) {
				if (this.cachedStub == null) {
					this.cachedStub = lookupStub();
				}
				return this.cachedStub;
			}
		}
	}
}

 进行远程方法的调用有两种情况。

  • 是 RMIInvocationHandler 类型的。
  • 不是 RMIInvocationHandler 类型的。
public class RmiClientInterceptor extends RemoteInvocationBasedAccessor
		implements MethodInterceptor {
    protected Object doInvoke(MethodInvocation invocation, Remote stub) throws Throwable {
        // stub 从服务器传回且经过 Spring 的封装
		if (stub instanceof RmiInvocationHandler) {
			// RMI invoker
			try {
				return doInvoke(invocation, (RmiInvocationHandler) stub);
			}
			catch (RemoteException ex) {
				throw RmiClientInterceptorUtils.convertRmiAccessException(
					invocation.getMethod(), ex, isConnectFailure(ex), getServiceUrl());
			}
			catch (InvocationTargetException ex) {
				Throwable exToThrow = ex.getTargetException();
				RemoteInvocationUtils.fillInClientStackTraceIfPossible(exToThrow);
				throw exToThrow;
			}
			catch (Throwable ex) {
				throw new RemoteInvocationFailureException("Invocation of method [" + invocation.getMethod() +
						"] failed in RMI service [" + getServiceUrl() + "]", ex);
			}
		}
		else {
			// 直接使用反射方法继续激活
			try {
				return RmiClientInterceptorUtils.invokeRemoteMethod(invocation, stub);
			}
			catch (InvocationTargetException ex) {
				Throwable targetEx = ex.getTargetException();
				if (targetEx instanceof RemoteException) {
					RemoteException rex = (RemoteException) targetEx;
					throw RmiClientInterceptorUtils.convertRmiAccessException(
							invocation.getMethod(), rex, isConnectFailure(rex), getServiceUrl());
				}
				else {
					throw targetEx;
				}
			}
		}
	}

    protected Object doInvoke(MethodInvocation methodInvocation, RmiInvocationHandler invocationHandler)
		throws RemoteException, NoSuchMethodException, IllegalAccessException, InvocationTargetException {

		if (AopUtils.isToStringMethod(methodInvocation.getMethod())) {
			return "RMI invoker proxy for service URL [" + getServiceUrl() + "]";
		}
        // 将 methodInvocation 中的方法名及参数等信息重新封装到 RemoteInvocation,并通过远程代理方法直接调用
		return invocationHandler.invoke(createRemoteInvocation(methodInvocation));
	}
}

12.2 HttpInvoker

 RMI 使用 Java 标准的对象序列化,但很难穿越防火墙;另外 Hessian/Burlap 能很好地穿越防火墙,但使用自己私有的一套对象徐丽华机制。
 Spring 的 HttpInvoker 应运而生。来执行基于 HTTP 的远程调用(让防火墙高兴的事),并使用 Java 的序列化机制(让程序员高兴的事)。

12.2.1 使用示例

HttpInvoker 使用示例

 使用步骤如下。

1. 创建对外接口。  
2. 创建接口实现类。 
3. 创建服务端配置文件 applicationContext-server.xml。
4. 在 WEB-INF 下创建 remote-servlet.xml。
5. 创建测试端配置 client.xml。
6. 创建测试类。

 使用示例见 com.stu.spring.context.chapter12.httpinvoker.HttpInvokerTest。注意服务端需要打 war 包发布到对应的服务器上(没有测试了,直接看代码吧)。

12.2.2 服务端实现

HttpInvokerServiceExporter 类层次结构
HttpInvokerServiceExporter
    RemoteInvocationSerializingExporter
        RemoteInvocationBasedExporter
            RemoteExporter
                RemotingSupport
                    Object
                    BeanClassLoaderAware
                        Aware
        InitializingBean
    HttpRequestHandler
 1. 创建代理
public abstract class RemoteInvocationSerializingExporter extends RemoteInvocationBasedExporter implements InitializingBean {
    public void afterPropertiesSet() {
        this.prepare();
    }

    public void prepare() {
        // 代码前面已介绍,同 RmiServiceExporter 初始化 的 2. 初始化要导出的实体对象 小节
        this.proxy = this.getProxyForService();
    }
}
 2. 处理来自客户端的 request
public class HttpInvokerServiceExporter extends RemoteInvocationSerializingExporter implements HttpRequestHandler {
    public void handleRequest(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {

		try {
            // 从 request 中读取序列化对象
			RemoteInvocation invocation = readRemoteInvocation(request);
            // 执行调用
			RemoteInvocationResult result = invokeAndCreateResult(invocation, getProxy());
            // 将结果的序列化对象写入输出流
			writeRemoteInvocationResult(request, response, result);
		}
		catch (ClassNotFoundException ex) {
			throw new NestedServletException("Class not found during deserialization", ex);
		}
	}
}
  2.1 从 request 中读取序列化对象
public class HttpInvokerServiceExporter extends RemoteInvocationSerializingExporter implements HttpRequestHandler {
    protected RemoteInvocation readRemoteInvocation(HttpServletRequest request)
			throws IOException, ClassNotFoundException {

		return readRemoteInvocation(request, request.getInputStream());
	}

    protected RemoteInvocation readRemoteInvocation(HttpServletRequest request, InputStream is)
			throws IOException, ClassNotFoundException {
        // 创建对象输入流
		ObjectInputStream ois = createObjectInputStream(decorateInputStream(request, is));
		try {
            // 从输入流中读取序列化对象
			return doReadRemoteInvocation(ois);
		}
		finally {
			ois.close();
		}
	}
}

public abstract class RemoteInvocationSerializingExporter extends RemoteInvocationBasedExporter
		implements InitializingBean {
    protected RemoteInvocation doReadRemoteInvocation(ObjectInputStream ois)
			throws IOException, ClassNotFoundException {

		Object obj = ois.readObject();
		if (!(obj instanceof RemoteInvocation)) {
			throw new RemoteException("Deserialized object needs to be assignable to type [" +
					RemoteInvocation.class.getName() + "]: " + ClassUtils.getDescriptiveType(obj));
		}
		return (RemoteInvocation) obj;
	}
}
  2.2 执行调用
public abstract class RemoteInvocationBasedExporter extends RemoteExporter {
    protected RemoteInvocationResult invokeAndCreateResult(RemoteInvocation invocation, Object targetObject) {
		try {
            // 激活代理中对应 invocation 中的方法
			Object value = invoke(invocation, targetObject);
            // 封装结果以便于序列化
			return new RemoteInvocationResult(value);
		}
		catch (Throwable ex) {
			return new RemoteInvocationResult(ex);
		}
	}
}
  2.3 将结果的序列化对象写入输出流
public class HttpInvokerServiceExporter extends RemoteInvocationSerializingExporter implements HttpRequestHandler {
	protected void writeRemoteInvocationResult(
			HttpServletRequest request, HttpServletResponse response, RemoteInvocationResult result)
			throws IOException {

		response.setContentType(getContentType());
		writeRemoteInvocationResult(request, response, result, response.getOutputStream());
	}

	protected void writeRemoteInvocationResult(
			HttpServletRequest request, HttpServletResponse response, RemoteInvocationResult result, OutputStream os)
			throws IOException {
		// 获取输入流
		ObjectOutputStream oos =
				createObjectOutputStream(new FlushGuardedOutputStream(decorateOutputStream(request, response, os)));
		try {
			// 将序列化对象写入输入流
			doWriteRemoteInvocationResult(result, oos);
		}
		finally {
			oos.close();
		}
	}
}

12.3 客户端实现

HttpInvokerProxyFactoryBean 类层次结构
HttpInvokerProxyFactoryBean
	HttpInvokerClientInterceptor
		RemoteInvocationBasedAccessor
			UrlBasedRemoteAccessor
				RemoteAccessor
					RemotingSupport
						Object
						BeanClassLoaderAware
							Aware
				InitializingBean
		MethodInterceptor
			Interceptor
				Advice
		HttpInvokerClientConfiguration
	FactoryBean

HttpInvokerProxyFactoryBean 初始化
public class HttpInvokerProxyFactoryBean extends HttpInvokerClientInterceptor implements FactoryBean<Object> {
	public void afterPropertiesSet() {
		super.afterPropertiesSet();
		Class<?> ifc = getServiceInterface();
		Assert.notNull(ifc, "Property 'serviceInterface' is required");
		// 创建代理并使用当前方法为拦截器增强
		this.serviceProxy = new ProxyFactory(ifc, this).getProxy(getBeanClassLoader());
	}

	public Object getObject() {
		return this.serviceProxy;
	}
}
HttpInvokerProxyFactoryBean 的 invoke 方法

 子类里面实现。

public class HttpInvokerClientInterceptor extends RemoteInvocationBasedAccessor
		implements MethodInterceptor, HttpInvokerClientConfiguration {
	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) {
			RemoteAccessException rae = convertHttpInvokerAccessException(ex);
			throw (rae != null ? rae : ex);
		}

		try {
			// 提取结果
			return recreateRemoteInvocationResult(result);
		}
		catch (Throwable ex) {
			if (result.hasInvocationTargetException()) {
				throw ex;
			}
			else {
				throw new RemoteInvocationFailureException("Invocation of method [" + methodInvocation.getMethod() +
						"] failed in HTTP invoker remote service at [" + getServiceUrl() + "]", ex);
			}
		}
	}
}

 函数主要有 3 个步骤。

  1. 构建 RemoteInvocation 实例。
  2. 远程执行方法。
  3. 提取结果。
 2. 远程执行方法
public class HttpInvokerClientInterceptor extends RemoteInvocationBasedAccessor
		implements MethodInterceptor, HttpInvokerClientConfiguration {
	protected RemoteInvocationResult executeRequest(
			RemoteInvocation invocation, MethodInvocation originalInvocation) throws Exception {

		return executeRequest(invocation);
	}

	protected RemoteInvocationResult executeRequest(RemoteInvocation invocation) throws Exception {
		return getHttpInvokerRequestExecutor().executeRequest(this, invocation);
	}
}

public abstract class AbstractHttpInvokerRequestExecutor implements HttpInvokerRequestExecutor, BeanClassLoaderAware {
	public final RemoteInvocationResult executeRequest(
			HttpInvokerClientConfiguration config, RemoteInvocation invocation) throws Exception {
		// 获取输出流
		ByteArrayOutputStream baos = getByteArrayOutputStream(invocation);
		if (logger.isDebugEnabled()) {
			logger.debug("Sending HTTP invoker request for service at [" + config.getServiceUrl() +
					"], with size " + baos.size());
		}
		return doExecuteRequest(config, baos);
	}
}

public class HttpComponentsHttpInvokerRequestExecutor extends AbstractHttpInvokerRequestExecutor {
	protected RemoteInvocationResult doExecuteRequest(
			HttpInvokerClientConfiguration config, ByteArrayOutputStream baos)
			throws IOException, ClassNotFoundException {
		// 创建 HttpPost 
		HttpPost postMethod = createHttpPost(config);
		// 设置含有方法的输出流到 post 中
		setRequestBody(config, postMethod, baos);
		try {
			// 执行方法并等待结果响应
			HttpResponse response = executeHttpPost(config, getHttpClient(), postMethod);
			// 验证
			validateResponse(config, response);
			// 提取返回的输入流
			InputStream responseBody = getResponseBody(config, response);
			// 从输入流中提取结果
			return readRemoteInvocationResult(responseBody, config.getCodebaseUrl());
		}
		finally {
			postMethod.releaseConnection();
		}
	}
}
  1. 创建 HttpPost
public class HttpComponentsHttpInvokerRequestExecutor extends AbstractHttpInvokerRequestExecutor {
	protected HttpPost createHttpPost(HttpInvokerClientConfiguration config) throws IOException {
		// 设置需要访问的 URL
		HttpPost httpPost = new HttpPost(config.getServiceUrl());

		RequestConfig requestConfig = createRequestConfig(config);
		if (requestConfig != null) {
			httpPost.setConfig(requestConfig);
		}

		LocaleContext localeContext = LocaleContextHolder.getLocaleContext();
		if (localeContext != null) {
			Locale locale = localeContext.getLocale();
			if (locale != null) {
				// 加入 accept_language 属性
				httpPost.addHeader(HTTP_HEADER_ACCEPT_LANGUAGE, locale.toLanguageTag());
			}
		}

		if (isAcceptGzipEncoding()) {
			// 加入 accept-encoding 属性
			httpPost.addHeader(HTTP_HEADER_ACCEPT_ENCODING, ENCODING_GZIP);
		}

		return httpPost;
	}
}
  2. 设置 RequestBody
public class HttpComponentsHttpInvokerRequestExecutor extends AbstractHttpInvokerRequestExecutor {
	protected void setRequestBody(
			HttpInvokerClientConfiguration config, HttpPost httpPost, ByteArrayOutputStream baos)
			throws IOException {

		// 将序列化流加入到 postMethod 中并声明 ContentType 类型为 application/x-java-serialized-object
		ByteArrayEntity entity = new ByteArrayEntity(baos.toByteArray());
		entity.setContentType(getContentType());
		httpPost.setEntity(entity);
	}
}

  3. 执行远程方法
public class HttpComponentsHttpInvokerRequestExecutor extends AbstractHttpInvokerRequestExecutor {
	protected HttpResponse executeHttpPost(
			HttpInvokerClientConfiguration config, HttpClient httpClient, HttpPost httpPost)
			throws IOException {

		return httpClient.execute(httpPost);
	}
}
  4. 远程相应验证
public class HttpComponentsHttpInvokerRequestExecutor extends AbstractHttpInvokerRequestExecutor {
	protected void validateResponse(HttpInvokerClientConfiguration config, HttpResponse response)
			throws IOException {

		StatusLine status = response.getStatusLine();
		if (status.getStatusCode() >= 300) {
			throw new NoHttpResponseException(
					"Did not receive successful HTTP response: status code = " + status.getStatusCode() +
					", status message = [" + status.getReasonPhrase() + "]");
		}
	}
}
  5. 提取响应信息
public class HttpComponentsHttpInvokerRequestExecutor extends AbstractHttpInvokerRequestExecutor {
	protected InputStream getResponseBody(HttpInvokerClientConfiguration config, HttpResponse httpResponse)
			throws IOException {

		if (isGzipResponse(httpResponse)) {
			return new GZIPInputStream(httpResponse.getEntity().getContent());
		}
		else {
			return httpResponse.getEntity().getContent();
		}
	}
}
  6. 提取返回结果
public class HttpComponentsHttpInvokerRequestExecutor extends AbstractHttpInvokerRequestExecutor {
	protected RemoteInvocationResult readRemoteInvocationResult(InputStream is, @Nullable String codebaseUrl)
			throws IOException, ClassNotFoundException {

		try (ObjectInputStream ois = createObjectInputStream(decorateInputStream(is), codebaseUrl)) {
			return doReadRemoteInvocationResult(ois);
		}
	}
}
Last Updated 3/16/2025, 9:52:57 PM