1.Spring除了使用基于HTTP协议的远程调用方案,还为开发者提供了基于RMI机制的远程调用方法,RMI远程调用网络通信实现是基于TCP/IP协议完成的,而不是通过HTTP协议。

在Spring RMI实现中,集成了标准的RMI-JRIM解决方案,该方案是java虚拟机实现的一部分,它使用java序列化来完成对象的传输,是一个java到java环境的分布式处理技术,不涉及异构平台的处理。

2.RMI客户端配置:

和基于HTTP协议的远程调用类似,RMI远程调用客户端也需要进行类似如下的配置:

[java] view plaincopy
  1. <bean id=”rmiProxy” class=”org.springframework.remoting.rmi.RmiProxyFactoryBean”>
  2. <property name=”serviceUrl”>
  3. <value>rmi://hostAddress:1099/serviceUrl</value>
  4. </property>
  5. <property name=”serviceInterface”>
  6. <value>远程调用接口</value>
  7. </property>
  8. </bean>
  9. <bean id=”rmiClient” class=”RMI远程调用客户端类全路径”>
  10. <property name=”serviceInterface”>
  11. <ref bean=”rmiProxy”/>
  12. </property>
  13. </bean>

注意:上面的配置中serviceUrl必须和服务端的远程调用提供者的id一致,另外,serviceUrl中使用的是rmi协议,默认端口是1099.

3.RmiProxyFactoryBean:

RmiProxyFactoryBean的主要功能是对RMI客户端封装,生成代理对象,查询得到RMI的stub对象,并通过这个stub对象发起相应的RMI远程调用请求。其源码如下:

[java] view plaincopy
  1. public class RmiProxyFactoryBean extends RmiClientInterceptor implements FactoryBean<Object>, BeanClassLoaderAware {
  2. //远程调用代理对象
  3. private Object serviceProxy;
  4. //Spring IoC容器完成依赖注入后的回调方法
  5. public void afterPropertiesSet() {
  6. //调用父类RmiClientInterceptor的回调方法
  7. super.afterPropertiesSet();
  8. //获取客户端配置的远程调用接口
  9. if (getServiceInterface() == null) {
  10. throw new IllegalArgumentException("Property 'serviceInterface' is required");
  11. }
  12. //创建远程调用代理对象并为代理对象设置拦截器。注意第二个参数this,因为
  13. //RmiProxyFactoryBean继承RmiClientInterceptor,因此其也是拦截器
  14. this.serviceProxy = new ProxyFactory(getServiceInterface(), this).getProxy(getBeanClassLoader());
  15. }
  16. //Spring IoC容器获取被管理对象的接口方法,获取远程调用代理
  17. public Object getObject() {
  18. return this.serviceProxy;
  19. }
  20. public Class<?> getObjectType() {
  21. return getServiceInterface();
  22. }
  23. public boolean isSingleton() {
  24. return true;
  25. }
  26. }

通过对上面RmiProxyFactoryBean源码分析中,我们看到在创建远程调用代理对象的时候需要设置拦截器,因为我们继续分析远程调用客户端拦截器RmiClientInterceptor。

4.RmiClientInterceptor封装RMI客户端:

RmiClientInterceptor对客户端的远程调用进行拦截,具体的生成远程调用代理对象、查找远程调用stub、以及通过RMI stub向服务端发起远程调用请求的具体实现都由RMI客户端拦截器实现,其源码如下:

[java] view plaincopy
  1. public class RmiClientInterceptor extends RemoteInvocationBasedAccessor
  2. implements MethodInterceptor {
  3. //在Spring启动时查找远程调用stub
  4. private boolean lookupStubOnStartup = true;
  5. //对查找到或使用过的远程调用stub进行缓存
  6. private boolean cacheStub = true;
  7. //当连接失败是是否刷新远程调用stub
  8. private boolean refreshStubOnConnectFailure = false;
  9. //RMI客户端socket工厂
  10. private RMIClientSocketFactory registryClientSocketFactory;
  11. //缓存的远程调用stub
  12. private Remote cachedStub;
  13. //创建远程调用stub监控器
  14. private final Object stubMonitor = new Object();
  15. //设置是否启动时查找RMI stub
  16. public void setLookupStubOnStartup(boolean lookupStubOnStartup) {
  17. this.lookupStubOnStartup = lookupStubOnStartup;
  18. }
  19. //设置是否缓存以查找的RMI stub
  20. public void setCacheStub(boolean cacheStub) {
  21. this.cacheStub = cacheStub;
  22. }
  23. //设置当连接失败时,是否刷新RMI stub
  24. public void setRefreshStubOnConnectFailure(boolean refreshStubOnConnectFailure) {
  25. this.refreshStubOnConnectFailure = refreshStubOnConnectFailure;
  26. }
  27. //设置客户端socket工厂
  28. public void setRegistryClientSocketFactory(RMIClientSocketFactory registryClientSocketFactory) {
  29. this.registryClientSocketFactory = registryClientSocketFactory;
  30. }
  31. //Spring IoC容器回调方法,由子类RmiProxyFactoryBean回调方法调用
  32. public void afterPropertiesSet() {
  33. //调用父类RemoteInvocationBasedAccessor的回调方法
  34. super.afterPropertiesSet();
  35. prepare();
  36. }
  37. //初始化RMI客户端
  38. public void prepare() throws RemoteLookupFailureException {
  39. //如果设置了启动时查找RMI stub
  40. if (this.lookupStubOnStartup) {
  41. //查找RMI stub
  42. Remote remoteObj = lookupStub();
  43. if (logger.isDebugEnabled()) {
  44. //如果查找到的RMI stub是RmiInvocationHandler类型
  45. if (remoteObj instanceof RmiInvocationHandler) {
  46. logger.debug("RMI stub [" + getServiceUrl() + "] is an RMI invoker");
  47. }
  48. //如果获取到客户端配置的serviceInterface不为null
  49. else if (getServiceInterface() != null) {
  50. //判断客户端配置的serviceInterface是否是RMI stub实例
  51. boolean isImpl = getServiceInterface().isInstance(remoteObj);
  52. logger.debug("Using service interface [" + getServiceInterface().getName() +
  53. "] for RMI stub [" + getServiceUrl() + "] - " +
  54. (!isImpl ? "not " : "") + "directly implemented");
  55. }
  56. }
  57. //如果设置了缓存RMI stub,将缓存的stub设置为查找到的RMI stub
  58. if (this.cacheStub) {
  59. this.cachedStub = remoteObj;
  60. }
  61. }
  62. }
  63. //查找RMI stub
  64. protected Remote lookupStub() throws RemoteLookupFailureException {
  65. try {
  66. Remote stub = null;
  67. //如果设置了客户端socket工厂
  68. if (this.registryClientSocketFactory != null) {
  69. //获取并解析客户端配置的serviceUrl
  70. URL url = new URL(null, getServiceUrl(), new DummyURLStreamHandler());
  71. //获取客户端配置的serviceUrl协议
  72. String protocol = url.getProtocol();
  73. //如果客户端配置的serviceUrl中协议不为null且不是rmi
  74. if (protocol != null && !"rmi".equals(protocol)) {
  75. throw new MalformedURLException("Invalid URL scheme '" + protocol + "'");
  76. }
  77. //获取客户端配置的serviceUrl中的主机地址
  78. String host = url.getHost();
  79. //获取客户端配置的serviceUrl中的端口
  80. int port = url.getPort();
  81. //获取客户端配置的serviceUrl中请求路径
  82. String name = url.getPath();
  83. //如果请求路径不为null,且请求路径以”/”开头,则去掉”/”
  84. if (name != null && name.startsWith("/")) {
  85. name = name.substring(1);
  86. }
  87. //根据客户端配置的serviceUrl信息和客户端socket工厂创建远程对
  88. //象引用
  89. Registry registry = LocateRegistry.getRegistry(host, port, this.registryClientSocketFactory);
  90. //通过远程对象引用查找指定RMI请求的RMI stub
  91. stub = registry.lookup(name);
  92. }
  93. //如果客户端配置的serviceUrl中协议为null或者是rmi
  94. else {
  95. //直接通过RMI标准API查找客户端配置的serviceUrl的RMI stub
  96. stub = Naming.lookup(getServiceUrl());
  97. }
  98. if (logger.isDebugEnabled()) {
  99. logger.debug("Located RMI stub with URL [" + getServiceUrl() + "]");
  100. }
  101. return stub;
  102. }
  103. //对查找RMI stub过程中异常处理
  104. catch (MalformedURLException ex) {
  105. throw new RemoteLookupFailureException("Service URL [" + getServiceUrl() + "] is invalid", ex);
  106. }
  107. catch (NotBoundException ex) {
  108. throw new RemoteLookupFailureException(
  109. "Could not find RMI service [" + getServiceUrl() + "] in RMI registry", ex);
  110. }
  111. catch (RemoteException ex) {
  112. throw new RemoteLookupFailureException("Lookup of RMI stub failed", ex);
  113. }
  114. }
  115. //获取RMI stub
  116. protected Remote getStub() throws RemoteLookupFailureException {
  117. //如果没有配置缓存RMI stub,或者设置了启动时查找RMI stub或当连接失败时
  118. //不刷新RMI stub
  119. if (!this.cacheStub || (this.lookupStubOnStartup && !this.refreshStubOnConnectFailure)) {
  120. //如果缓存的RMI stub不为null,则直接返回,否则,查找RMI stub
  121. return (this.cachedStub != null ? this.cachedStub : lookupStub());
  122. }
  123. //如果设置了缓存RMI stub,且设置了启动时查找RMI stub或者当连接失败时刷新
  124. //RMI stub
  125. else {
  126. //线程同步
  127. synchronized (this.stubMonitor) {
  128. //如果缓存的RMI stub为null
  129. if (this.cachedStub == null) {
  130. //则将查找的RMI stub缓存
  131. this.cachedStub = lookupStub();
  132. }
  133. //返回缓存的RMI stub
  134. return this.cachedStub;
  135. }
  136. }
  137. }
  138. //拦截器对客户端远程调用方法的拦截入口
  139. public Object invoke(MethodInvocation invocation) throws Throwable {
  140. //获取RMI stub
  141. Remote stub = getStub();
  142. try {
  143. //拦截客户端远程调用方法
  144. return doInvoke(invocation, stub);
  145. }
  146. catch (RemoteConnectFailureException ex) {
  147. return handleRemoteConnectFailure(invocation, ex);
  148. }
  149. catch (RemoteException ex) {
  150. if (isConnectFailure(ex)) {
  151. return handleRemoteConnectFailure(invocation, ex);
  152. }
  153. else {
  154. throw ex;
  155. }
  156. }
  157. }
  158. //判断是否连接失败
  159. protected boolean isConnectFailure(RemoteException ex) {
  160. return RmiClientInterceptorUtils.isConnectFailure(ex);
  161. }
  162. //处理远程连接失败
  163. private Object handleRemoteConnectFailure(MethodInvocation invocation, Exception ex) throws Throwable {
  164. //如果设置了当连接失败时,刷新RMI stub
  165. if (this.refreshStubOnConnectFailure) {
  166. String msg = "Could not connect to RMI service [" + getServiceUrl() + "] - retrying";
  167. if (logger.isDebugEnabled()) {
  168. logger.warn(msg, ex);
  169. }
  170. else if (logger.isWarnEnabled()) {
  171. logger.warn(msg);
  172. }
  173. //刷新查找远程调用stub
  174. return refreshAndRetry(invocation);
  175. }
  176. else {
  177. throw ex;
  178. }
  179. }
  180. //刷新RMI stub
  181. protected Object refreshAndRetry(MethodInvocation invocation) throws Throwable {
  182. Remote freshStub = null;
  183. //线程同步
  184. synchronized (this.stubMonitor) {
  185. this.cachedStub = null;
  186. //查找RMI stub
  187. freshStub = lookupStub();
  188. //如果设置了缓存RMI stub
  189. if (this.cacheStub) {
  190. //将刷新查找的RMI stub缓存
  191. this.cachedStub = freshStub;
  192. }
  193. }
  194. return doInvoke(invocation, freshStub);
  195. }
  196. //具体RMI调用的地方
  197. protected Object doInvoke(MethodInvocation invocation, Remote stub) throws Throwable {
  198. //如果RMI stub是RmiInvocationHandler类型
  199. if (stub instanceof RmiInvocationHandler) {
  200. //调用RmiInvocationHandler的RMI
  201. try {
  202. return doInvoke(invocation, (RmiInvocationHandler) stub);
  203. }
  204. catch (RemoteException ex) {
  205. throw RmiClientInterceptorUtils.convertRmiAccessException(
  206. invocation.getMethod(), ex, isConnectFailure(ex), getServiceUrl());
  207. }
  208. catch (InvocationTargetException ex) {
  209. Throwable exToThrow = ex.getTargetException();
  210. RemoteInvocationUtils.fillInClientStackTraceIfPossible(exToThrow);
  211. throw exToThrow;
  212. }
  213. catch (Throwable ex) {
  214. throw new RemoteInvocationFailureException("Invocation of method [" + invocation.getMethod() +
  215. "] failed in RMI service [" + getServiceUrl() + "]", ex);
  216. }
  217. }
  218. //如果RMI stub不是RmiInvocationHandler类型
  219. else {
  220. //使用传统的RMI调用方式
  221. try {
  222. return RmiClientInterceptorUtils.invokeRemoteMethod(invocation, stub);
  223. }
  224. catch (InvocationTargetException ex) {
  225. Throwable targetEx = ex.getTargetException();
  226. if (targetEx instanceof RemoteException) {
  227. RemoteException rex = (RemoteException) targetEx;
  228. throw RmiClientInterceptorUtils.convertRmiAccessException(
  229. invocation.getMethod(), rex, isConnectFailure(rex), getServiceUrl());
  230. }
  231. else {
  232. throw targetEx;
  233. }
  234. }
  235. }
  236. }
  237. //调用RmiInvocationHandler的RMI
  238. protected Object doInvoke(MethodInvocation methodInvocation, RmiInvocationHandler invocationHandler)
  239. throws RemoteException, NoSuchMethodException, IllegalAccessException, InvocationTargetException {
  240. //如果客户端远程调用请求是toString()方法
  241. if (AopUtils.isToStringMethod(methodInvocation.getMethod())) {
  242. return "RMI invoker proxy for service URL [" + getServiceUrl() + "]";
  243. }
  244. //使用RmiInvocationHandler处理RMI调用
  245. return invocationHandler.invoke(createRemoteInvocation(methodInvocation));
  246. }
  247. }

通过上面对RmiClientInterceptor源码分析,我们看到Spring对RMI远程调用使用以下两种方式:

(1).RMI调用器方式:

这种方式和Spring HTTP调用器非常类似,即使用RemoteInvocation来封装调用目标对象、目标方法、参数类型等信息,RMI服务器端接收到RMI请求之后直接调用目标对象的匹配方法。

(2).传统RMI调用方式:

使用JDK的反射机制,直接调用远程调用stub的方法。

5.RMI的服务端配置:

在Spring RMI服务端需要进行类似如下的配置:

[xhtml] view plaincopy
  1. <bean id=”rmiService” class=”org.springframework.remoting.rmi.RmiServiceExporter”>
  2. <property name=”service”>
  3. <ref bean=”RMI服务端对象”/>
  4. </property>
  5. <property name=”serviceInterface”>
  6. <value>RMI服务接口</value>
  7. </property>
  8. <property name=”serviceName”>
  9. <value>RMI服务导出名称</value>
  10. </property>
  11. <property name=”registerPort”>
  12. <value>1099</value>
  13. </property>
  14. </bean>

RMI中,基于TCP/IP协议,而不是HTTP协议来实现底层网络通信,由于RMI的网络通信已由Java RMI实现,所以这里不再使用Spring MVC的DispatcherServlet来转发客户端配置的远程调用请求URL,只需要指定RMI的TCP/.IP监听端口和服务导出的名称即可。

6.RmiServiceExporter导出RMI远程调用对象:

RmiServiceExporter主要功能是将服务端远程对象提供的服务导出供客户端请求调用,同时将导出的远程对象和注册器绑定起来供客户端查询,其主要源码如下:

[java] view plaincopy
  1. public class RmiServiceExporter extends RmiBasedExporter implements InitializingBean, DisposableBean {
  2. //导出的RMI服务名称
  3. private String serviceName;
  4. //RMI服务端口
  5. private int servicePort = 0;
  6. //RMI客户端socket工厂
  7. private RMIClientSocketFactory clientSocketFactory;
  8. //RMI服务端socket工厂
  9. private RMIServerSocketFactory serverSocketFactory;
  10. //注册器
  11. private Registry registry;
  12. //注册主机
  13. private String registryHost;
  14. //注册端口
  15. private int registryPort = Registry.REGISTRY_PORT;
  16. //客户端注册socket工厂
  17. private RMIClientSocketFactory registryClientSocketFactory;
  18. //服务端注册socket工厂
  19. private RMIServerSocketFactory registryServerSocketFactory;
  20. //总是创建时注册
  21. private boolean alwaysCreateRegistry = false;
  22. //替换已有的绑定
  23. private boolean replaceExistingBinding = true;
  24. //导出的远程对象
  25. private Remote exportedObject;
  26. //创建注册
  27. private boolean createdRegistry = false;
  28. //注入服务端配置的RMI导出服务名称,格式为:“rmi://host:post/NAME”
  29. public void setServiceName(String serviceName) {
  30. this.serviceName = serviceName;
  31. }
  32. //设置服务端口
  33. public void setServicePort(int servicePort) {
  34. this.servicePort = servicePort;
  35. }
  36. //设置RMI客户端socket工厂
  37. public void setClientSocketFactory(RMIClientSocketFactory clientSocketFactory) {
  38. this.clientSocketFactory = clientSocketFactory;
  39. }
  40. //设置RMI服务端socket工厂
  41. public void setServerSocketFactory(RMIServerSocketFactory serverSocketFactory) {
  42. this.serverSocketFactory = serverSocketFactory;
  43. }
  44. //设置RMI注册器
  45. public void setRegistry(Registry registry) {
  46. this.registry = registry;
  47. }
  48. //设置RMI注册主机
  49. public void setRegistryHost(String registryHost) {
  50. this.registryHost = registryHost;
  51. }
  52. //设置RMI注册端口
  53. public void setRegistryPort(int registryPort) {
  54. this.registryPort = registryPort;
  55. }
  56. //设置用于注册的RMI客户端socket工厂
  57. public void setRegistryClientSocketFactory(RMIClientSocketFactory registryClientSocketFactory) {
  58. this.registryClientSocketFactory = registryClientSocketFactory;
  59. }
  60. //设置用于注册的RMI服务端socket工厂
  61. public void setRegistryServerSocketFactory(RMIServerSocketFactory registryServerSocketFactory) {
  62. this.registryServerSocketFactory = registryServerSocketFactory;
  63. }
  64. //设置是否总是创建注册,而不是试图查找指定端口上已有的注册
  65. public void setAlwaysCreateRegistry(boolean alwaysCreateRegistry) {
  66. this.alwaysCreateRegistry = alwaysCreateRegistry;
  67. }
  68. //设置是否提供已绑定的RMI注册
  69. public void setReplaceExistingBinding(boolean replaceExistingBinding) {
  70. this.replaceExistingBinding = replaceExistingBinding;
  71. }
  72. //IoC容器依赖注入完成之后的回调方法
  73. public void afterPropertiesSet() throws RemoteException {
  74. prepare();
  75. }
  76. //初始化RMI服务导出器
  77. public void prepare() throws RemoteException {
  78. //调用其父类RmiBasedExporter的方法,检查服务引用是否被设置
  79. checkService();
  80. //如果服务导出名称为null
  81. if (this.serviceName == null) {
  82. throw new IllegalArgumentException("Property 'serviceName' is required");
  83. }
  84. //检查socket工厂
  85. if (this.clientSocketFactory instanceof RMIServerSocketFactory) {
  86. this.serverSocketFactory = (RMIServerSocketFactory) this.clientSocketFactory;
  87. }
  88. if ((this.clientSocketFactory != null && this.serverSocketFactory == null) ||
  89. (this.clientSocketFactory == null && this.serverSocketFactory != null)) {
  90. throw new IllegalArgumentException(
  91. "Both RMIClientSocketFactory and RMIServerSocketFactory or none required");
  92. }
  93. //检查RMI注册的socket工厂
  94. if (this.registryClientSocketFactory instanceof RMIServerSocketFactory) {
  95. this.registryServerSocketFactory = (RMIServerSocketFactory) this.registryClientSocketFactory;
  96. }
  97. if (this.registryClientSocketFactory == null && this.registryServerSocketFactory != null) {
  98. throw new IllegalArgumentException(
  99. "RMIServerSocketFactory without RMIClientSocketFactory for registry not supported");
  100. }
  101. this.createdRegistry = false;
  102. //获取RMI注册器
  103. if (this.registry == null) {
  104. this.registry = getRegistry(this.registryHost, this.registryPort,
  105. this.registryClientSocketFactory, this.registryServerSocketFactory);
  106. this.createdRegistry = true;
  107. }
  108. //获取要被导出的服务端远程对象
  109. this.exportedObject = getObjectToExport();
  110. if (logger.isInfoEnabled()) {
  111. logger.info("Binding service '" + this.serviceName + "' to RMI registry: " + this.registry);
  112. }
  113. //导出远程服务对象
  114. if (this.clientSocketFactory != null) {
  115. UnicastRemoteObject.exportObject(
  116. this.exportedObject, this.servicePort, this.clientSocketFactory, this.serverSocketFactory);
  117. }
  118. else {
  119. UnicastRemoteObject.exportObject(this.exportedObject, this.servicePort);
  120. }
  121. //将RMI对象绑定到注册器
  122. try {
  123. if (this.replaceExistingBinding) {
  124. this.registry.rebind(this.serviceName, this.exportedObject);
  125. }
  126. else {
  127. this.registry.bind(this.serviceName, this.exportedObject);
  128. }
  129. }
  130. //异常处理
  131. catch (AlreadyBoundException ex) {
  132. unexportObjectSilently();
  133. throw new IllegalStateException(
  134. "Already an RMI object bound for name '"  + this.serviceName + "': " + ex.toString());
  135. }
  136. catch (RemoteException ex) {
  137. unexportObjectSilently();
  138. throw ex;
  139. }
  140. }
  141. ……
  142. }

7.RemoteInvocationBasedExporter处理RMI远程调用请求:

RmiServiceExporter的父类RmiBasedExporter的父类RemoteInvocationBasedExporter负责对RMI远程调用请求进行处理,并将处理的结果封装返回,其源码如下:

[java] view plaincopy
  1. public abstract class RemoteInvocationBasedExporter extends RemoteExporter {
  2. //RMI远程调用处理器,RMI远程调用请求是由DefaultRemoteInvocationExecutor处理
  3. private RemoteInvocationExecutor remoteInvocationExecutor = new DefaultRemoteInvocationExecutor();
  4. //设置RMI远程调用处理器
  5. public void setRemoteInvocationExecutor(RemoteInvocationExecutor remoteInvocationExecutor) {
  6. this.remoteInvocationExecutor = remoteInvocationExecutor;
  7. }
  8. //获取RMI远程调用处理器
  9. public RemoteInvocationExecutor getRemoteInvocationExecutor() {
  10. return this.remoteInvocationExecutor;
  11. }
  12. //对RMI远程调用请求进行处理的地方
  13. protected Object invoke(RemoteInvocation invocation, Object targetObject)
  14. throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
  15. if (logger.isTraceEnabled()) {
  16. logger.trace("Executing " + invocation);
  17. }
  18. try {
  19. //调用DefaultRemoteInvocationExecutor对RMI远程调用请求进行处理
  20. return getRemoteInvocationExecutor().invoke(invocation, targetObject);
  21. }
  22. catch (NoSuchMethodException ex) {
  23. if (logger.isDebugEnabled()) {
  24. logger.warn("Could not find target method for " + invocation, ex);
  25. }
  26. throw ex;
  27. }
  28. catch (IllegalAccessException ex) {
  29. if (logger.isDebugEnabled()) {
  30. logger.warn("Could not access target method for " + invocation, ex);
  31. }
  32. throw ex;
  33. }
  34. catch (InvocationTargetException ex) {
  35. if (logger.isDebugEnabled()) {
  36. logger.debug("Target method failed for " + invocation, ex.getTargetException());
  37. }
  38. throw ex;
  39. }
  40. }
  41. //获取RMI远程调用请求的处理结果
  42. protected RemoteInvocationResult invokeAndCreateResult(RemoteInvocation invocation, Object targetObject) {
  43. try {
  44. Object value = invoke(invocation, targetObject);
  45. return new RemoteInvocationResult(value);
  46. }
  47. catch (Throwable ex) {
  48. return new RemoteInvocationResult(ex);
  49. }
  50. }
  51. }

RMI远程调用请求最终由DefaultRemoteInvocationExecutor处理。

8.DefaultRemoteInvocationExecutor处理RMI远程调用请求:

DefaultRemoteInvocationExecutor用于处理RMI远程调用请求,并返回处理后的结果,其源码如下:

[java] view plaincopy
  1. public class DefaultRemoteInvocationExecutor implements RemoteInvocationExecutor {
  2. //处理RMI远程调用请求
  3. public Object invoke(RemoteInvocation invocation, Object targetObject)
  4. throws NoSuchMethodException, IllegalAccessException, InvocationTargetException{
  5. Assert.notNull(invocation, "RemoteInvocation must not be null");
  6. Assert.notNull(targetObject, "Target object must not be null");
  7. //调用RemoteInvocation处理RMI远程调用请求
  8. return invocation.invoke(targetObject);
  9. }
  10. }

9.RemoteInvocation处理RMI远程调用请求:

RemoteInvocation的invoke方法处理RMI远程调用请求,并返回远程调用处理后的结果,其源码如下:

[java] view plaincopy
  1. public Object invoke(Object targetObject)
  2. throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
  3. //使用JDK反射机制获取远程调用服务端目标对象的方法
  4. Method method = targetObject.getClass().getMethod(this.methodName, this.parameterTypes);
  5. //使用JDK反射机制调用目标对象的方法
  6. return method.invoke(targetObject, this.arguments);
  7. }

《Spring技术内幕》学习笔记19——Spring RMI实现远程调用相关推荐

  1. 资深架构师推荐Spring技术内幕:深入了解Spring的底层机制

    程序员都很崇拜技术大神,很大一部分是因为他们发现和解决问题的能力,特别是线上出现紧急问题时,总是能够快速定位和解决. 一方面,他们有深厚的技术基础,对应用的技术知其所以然,另一方面,在采坑的过程中不断 ...

  2. MAC OS X 技术内幕 学习笔记之四 MAC OS系统的启动引导

    MAC OS X 技术内幕 学习笔记之四 MAC OS系统的启动引导 MAC OS的启动非常快,同样的运行硬件环境,运行MAC系统感觉比运行windows系统要快不少.在使用笔记本时,同样的电池容量, ...

  3. Spring 技术内幕读书笔记

    Spring的设计理念和整体架构 1.1 spring的各个子项目 1.1.1 spring framwork 核心, IoC容器设计,控制反转,AOP ,MVC ,JDBC ,事务处理 1.1.2 ...

  4. Spring源码学习笔记:Spring设计模式对比和Spring的OOB,BOP,AOP,IOC,DI/DL

    1.博客内容均出自于咕泡学院架构师第三期 2.架构师系列内容:架构师学习笔记(持续更新) 1.GOF 23总设计模式归纳 分类 设计模式 创建型 工厂方法模式(Factory Method).抽象工厂 ...

  5. Spring Boot基础学习笔记19:自定义RedisTemplate与RedisCacheManager

    文章目录 零.学习目标 一.为什么要采用自定义Redis缓存序列化机制 二.自定义RedisTemplate (一)Redis API 默认序列化机制 (二)自定义RedisTemplate序列化机制 ...

  6. Spring技术内幕(3)Spring AOP的实现

    本章内容 Spring AOP概述.Spring AOP的设计与实现.建立AopProxy代理对象.Spring AOP拦截器调用的实现.Spring AOP的高级特性. 3.1 Spring AOP ...

  7. C#技术内幕 学习笔记

    引用类型是类型安全的指针,它们的内存是分配在堆(保存指针地址)上的. String.数组.类.接口和委托都是引用类型. 强制类型转换与as类型转换的区别:当类型转换非法时,强制类型转换将抛出一个Sys ...

  8. 深入立即Linux网络技术内幕学习笔记第十六章:桥接:Linux实现

    网桥设备抽象: 对Linux而言,网桥是虚拟设备,要想传输或接收数据,需要将真实设备绑定到虚拟网桥上. 上图中,有几点需要注意: LAN1和LAN2通过网桥连接在一起,子网都是一样的. 网桥连接到路由 ...

  9. 深入理解Linux网路技术内幕学习笔记第四章:通知链

    第四章:通知链 内核很多子系统之间具有很强的依赖性,其中一个子系统侦测到的或者产生的事件,其他子系统可能都感兴趣,为了实现这种需求,Linux使用了通知链.通知链只在内核子系统之间使用. 通知链就是一 ...

最新文章

  1. 这些知名制药跨国企业都实施了SAP系统
  2. 简单借还书管理系统c语言,急求程序!!!简单图书馆借/还书管理子系统
  3. 使用flexible适配移动端h5页面
  4. 2017年9月2日普级组T1 正方形
  5. Android之Bitmap的内存优化方案总结
  6. JsonData响应工具类封装
  7. sqli-lab———writeup(11~17)
  8. 你可以分配多大的内存
  9. 两种不同编码规则的查询
  10. supports-screens
  11. java实现5 4 3 2 1递归_递归及递归的使用
  12. delphi 安装控件时提示系统找不到指定的模块的解决
  13. G1调优实践日记--G1HeapWastePercent和InitiatingHeapOccupancyPercent的应用
  14. C++入门:让计算机“开口说话”
  15. 设计模式(一):简介
  16. 一、Require函数
  17. 安卓手机使用Termux运行java环境
  18. 可溶性变色配体(PCLs)-光致变色-杂环偶氮苯/螺噁嗪光致变色材料/二氧化钛溶胶凝胶光致变色材料
  19. 为什么onenote一直在加载_超好用的笔记软件,Onenote是我的最爱
  20. Flutter 2 渲染原理和如何实现视频渲染

热门文章

  1. 特征选择,归一化以及交叉验证中应当注意的问题
  2. AEG 3P400-650HF ASM
  3. css字体导入和应用
  4. 哪一款免费的文字转语音软件最好用?
  5. 怎么把几个gif图片合成一个gif?一键gif合成的方法
  6. 9月27日云栖精选夜读:阿里云首推免费人脸识别SDK 让每个APP轻松拥有短视频AR特效
  7. 人人商城手机端添加控制器
  8. android合并 工具下载,m3u8合并工具安卓版
  9. 59空格超简单数独题
  10. HTML怎么让文本在一个div上下左右居中呢?