Spring RMI

DEMO

服务提供方

  • 服务提供方需要准备接口接口实现泪
  • 接口
  1. public interface IDemoRmiService {
  2. int add(int a, int b);
  3. }
  • 接口实现
  1. public class IDemoRmiServiceImpl implements IDemoRmiService {
  2. @Override
  3. public int add(int a, int b) {
  4. return a + b;
  5. }
  6. }
  • xml 配置文件
  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  3. xmlns="http://www.springframework.org/schema/beans"
  4. xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
  5. <bean id="demoRmiService" class="com.huifer.source.spring.rmi.impl.IDemoRmiServiceImpl"/>
  6. <bean id="demoRmi" class="org.springframework.remoting.rmi.RmiServiceExporter">
  7. <!-- 服务-->
  8. <property name="service" ref="demoRmiService"/>
  9. <!-- 服务名称-->
  10. <property name="serviceName" value="springRmi"/>
  11. <!-- 服务接口-->
  12. <property name="serviceInterface" value="com.huifer.source.spring.rmi.IDemoRmiService"/>
  13. <!-- 注册端口-->
  14. <property name="registryPort" value="9999"/>
  15. </bean>
  16. </beans>
  • 运行
  1. public class RMIServerSourceCode {
  2. public static void main(String[] args) throws Exception {
  3. ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("rmi/RMISourceCode.xml");
  4. }
  5. }

服务调用方

  • xml 配置
  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <beans xmlns="http://www.springframework.org/schema/beans"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
  5. <bean id="rmiClient" class="org.springframework.remoting.rmi.RmiProxyFactoryBean">
  6. <property name="serviceUrl" value="rmi://localhost:9999/springRmi"/>
  7. <property name="serviceInterface" value="com.huifer.source.spring.rmi.IDemoRmiService"/>
  8. </bean>
  9. </beans>

注意:rmi 使用小写 大写报错信息:

  1. Exception in thread "main" org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'rmiClient' defined in class path resource [rmi/RMIClientSourceCode.xml]: Invocation of init method failed; nested exception is org.springframework.remoting.RemoteLookupFailureException: Service URL [RMI://localhost:9999/springRmi] is invalid; nested exception is java.net.MalformedURLException: invalid URL scheme: RMI://localhost:9999/springRmi
  2. at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1795)
  3. at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:559)
  4. at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:478)
  5. at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:309)
  6. at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:272)
  7. at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:306)
  8. at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:176)
  9. at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:877)
  10. at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:953)
  11. at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:579)
  12. at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:163)
  13. at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:90)
  14. at com.huifer.source.spring.rmi.RMIClientSourceCode.main(RMIClientSourceCode.java:7)
  15. Caused by: org.springframework.remoting.RemoteLookupFailureException: Service URL [RMI://localhost:9999/springRmi] is invalid; nested exception is java.net.MalformedURLException: invalid URL scheme: RMI://localhost:9999/springRmi
  16. at org.springframework.remoting.rmi.RmiClientInterceptor.lookupStub(RmiClientInterceptor.java:209)
  17. at org.springframework.remoting.rmi.RmiClientInterceptor.prepare(RmiClientInterceptor.java:147)
  18. at org.springframework.remoting.rmi.RmiClientInterceptor.afterPropertiesSet(RmiClientInterceptor.java:134)
  19. at org.springframework.remoting.rmi.RmiProxyFactoryBean.afterPropertiesSet(RmiProxyFactoryBean.java:68)
  20. at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1868)
  21. at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1791)
  22. ... 12 more
  23. Caused by: java.net.MalformedURLException: invalid URL scheme: RMI://localhost:9999/springRmi
  24. at java.rmi.Naming.intParseURL(Naming.java:290)
  25. at java.rmi.Naming.parseURL(Naming.java:237)
  26. at java.rmi.Naming.lookup(Naming.java:96)
  27. at org.springframework.remoting.rmi.RmiClientInterceptor.lookupStub(RmiClientInterceptor.java:201)
  28. ... 17 more
  • 运行
  1. public class RMIClientSourceCode {
  2. public static void main(String[] args) {
  3. ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("rmi/RMIClientSourceCode.xml");
  4. IDemoRmiService rmiClient = context.getBean("rmiClient", IDemoRmiService.class);
  5. int add = rmiClient.add(1, 2);
  6. System.out.println(add);
  7. }
  8. }

服务端初始化

  • org.springframework.remoting.rmi.RmiServiceExporter,该类定义了 spring 的远程服务信息

RmiServiceExporter

  • 基础属性如下
  1. public class RmiServiceExporter extends RmiBasedExporter implements InitializingBean, DisposableBean {
  2. /**
  3. * 服务名称,rmi的服务名,在Spring中使用ref指向impl实现类
  4. */
  5. private String serviceName;
  6. /**
  7. *
  8. */
  9. private int servicePort = 0; // anonymous port
  10. private RMIClientSocketFactory clientSocketFactory;
  11. private RMIServerSocketFactory serverSocketFactory;
  12. private Registry registry;
  13. /**
  14. * 注册的IP地址
  15. */
  16. private String registryHost;
  17. /**
  18. * 注册的端口
  19. */
  20. private int registryPort = Registry.REGISTRY_PORT;
  21. /**
  22. * 进行远程对象调用的Socket工厂
  23. */
  24. private RMIClientSocketFactory clientSocketFactory;
  25. /**
  26. * 接收远程调用服务端的Socket工厂
  27. */
  28. private RMIServerSocketFactory serverSocketFactory;
  29. /**
  30. * true: 该参数在获取{@link Registry}时测试是否建立连接,如果建立连接则直接使用,否则创建新连接
  31. * 是否总是创建{@link Registry}
  32. */
  33. private boolean alwaysCreateRegistry = false;
  34. /**
  35. * 设置替换RMI注册表中的绑定关系
  36. */
  37. private boolean replaceExistingBinding = true;
  38. private Remote exportedObject;
  39. /**
  40. * 创建{@link Registry}
  41. */
  42. private boolean createdRegistry = false;
  43. }
  • 属性设置不说了,看接口实现了那些
    1. InitializingBean: 初始化 bean 调用afterPropertiesSet方法
    2. DisposableBean: 摧毁 bean 调用destroy方法
  1. @Override
  2. public void afterPropertiesSet() throws RemoteException {
  3. prepare();
  4. }
  5. public void prepare() throws RemoteException {
  6. // 校验service
  7. checkService();
  8. // 服务名称校验
  9. if (this.serviceName == null) {
  10. throw new IllegalArgumentException("Property 'serviceName' is required");
  11. }
  12. // Check socket factories for exported object.
  13. if (this.clientSocketFactory instanceof RMIServerSocketFactory) {
  14. this.serverSocketFactory = (RMIServerSocketFactory) this.clientSocketFactory;
  15. }
  16. if ((this.clientSocketFactory != null && this.serverSocketFactory == null) ||
  17. (this.clientSocketFactory == null && this.serverSocketFactory != null)) {
  18. throw new IllegalArgumentException(
  19. "Both RMIClientSocketFactory and RMIServerSocketFactory or none required");
  20. }
  21. // Check socket factories for RMI registry.
  22. if (this.registryClientSocketFactory instanceof RMIServerSocketFactory) {
  23. this.registryServerSocketFactory = (RMIServerSocketFactory) this.registryClientSocketFactory;
  24. }
  25. if (this.registryClientSocketFactory == null && this.registryServerSocketFactory != null) {
  26. throw new IllegalArgumentException(
  27. "RMIServerSocketFactory without RMIClientSocketFactory for registry not supported");
  28. }
  29. this.createdRegistry = false;
  30. // Determine RMI registry to use.
  31. if (this.registry == null) {
  32. // registry 获取
  33. this.registry = getRegistry(this.registryHost, this.registryPort,
  34. this.registryClientSocketFactory, this.registryServerSocketFactory);
  35. this.createdRegistry = true;
  36. }
  37. // Initialize and cache exported object.
  38. // 初始化并且获取缓存的object
  39. this.exportedObject = getObjectToExport();
  40. if (logger.isDebugEnabled()) {
  41. logger.debug("Binding service '" + this.serviceName + "' to RMI registry: " + this.registry);
  42. }
  43. // Export RMI object.
  44. // 导出RMI object
  45. if (this.clientSocketFactory != null) {
  46. UnicastRemoteObject.exportObject(
  47. this.exportedObject, this.servicePort, this.clientSocketFactory, this.serverSocketFactory);
  48. }
  49. else {
  50. UnicastRemoteObject.exportObject(this.exportedObject, this.servicePort);
  51. }
  52. // Bind RMI object to registry.
  53. // 对象绑定,把serviceName 和 到处的RMI对象进行绑定,JDK实现
  54. try {
  55. if (this.replaceExistingBinding) {
  56. this.registry.rebind(this.serviceName, this.exportedObject);
  57. }
  58. else {
  59. this.registry.bind(this.serviceName, this.exportedObject);
  60. }
  61. }
  62. catch (AlreadyBoundException ex) {
  63. // Already an RMI object bound for the specified service name...
  64. unexportObjectSilently();
  65. throw new IllegalStateException(
  66. "Already an RMI object bound for name '" + this.serviceName + "': " + ex.toString());
  67. }
  68. catch (RemoteException ex) {
  69. // Registry binding failed: let's unexport the RMI object as well.
  70. unexportObjectSilently();
  71. throw ex;
  72. }
  73. }

checkService

  • 校验 service 是否为空
  1. /**
  2. * Check whether the service reference has been set.
  3. *
  4. * 校验service
  5. * @see #setService
  6. */
  7. protected void checkService() throws IllegalArgumentException {
  8. Assert.notNull(getService(), "Property 'service' is required");
  9. }

getRegistry

  • 获取 Registry 实例
    • 简单说就是通过 host 和 port 创建 socket
  1. protected Registry getRegistry(String registryHost, int registryPort,
  2. @Nullable RMIClientSocketFactory clientSocketFactory, @Nullable RMIServerSocketFactory serverSocketFactory)
  3. throws RemoteException {
  4. if (registryHost != null) {
  5. // Host explicitly specified: only lookup possible.
  6. if (logger.isDebugEnabled()) {
  7. logger.debug("Looking for RMI registry at port '" + registryPort + "' of host [" + registryHost + "]");
  8. }
  9. // 通过 host port socket创建
  10. Registry reg = LocateRegistry.getRegistry(registryHost, registryPort, clientSocketFactory);
  11. testRegistry(reg);
  12. return reg;
  13. }
  14. else {
  15. return getRegistry(registryPort, clientSocketFactory, serverSocketFactory);
  16. }
  17. }

getObjectToExport

  • 初始化并且获取缓存的 object
  1. protected Remote getObjectToExport() {
  2. // determine remote object
  3. if (getService() instanceof Remote &&
  4. (getServiceInterface() == null || Remote.class.isAssignableFrom(getServiceInterface()))) {
  5. // conventional RMI service
  6. // 获取service
  7. return (Remote) getService();
  8. }
  9. else {
  10. // RMI invoker
  11. if (logger.isDebugEnabled()) {
  12. logger.debug("RMI service [" + getService() + "] is an RMI invoker");
  13. }
  14. // RMI 包装类
  15. /**
  16. * 1. getProxyForService() 获取代理的接口
  17. * 2. 创建RMI包装对象 RmiInvocationWrapper
  18. */
  19. return new RmiInvocationWrapper(getProxyForService(), this);
  20. }
  21. }

getProxyForService

  • 获取代理服务
  1. protected Object getProxyForService() {
  2. // service 校验
  3. checkService();
  4. // 校验接口
  5. checkServiceInterface();
  6. // 代理工厂
  7. ProxyFactory proxyFactory = new ProxyFactory();
  8. // 添加代理接口
  9. proxyFactory.addInterface(getServiceInterface());
  10. if (this.registerTraceInterceptor != null ? this.registerTraceInterceptor : this.interceptors == null) {
  11. // 添加切面
  12. proxyFactory.addAdvice(new RemoteInvocationTraceInterceptor(getExporterName()));
  13. }
  14. if (this.interceptors != null) {
  15. AdvisorAdapterRegistry adapterRegistry = GlobalAdvisorAdapterRegistry.getInstance();
  16. for (Object interceptor : this.interceptors) {
  17. proxyFactory.addAdvisor(adapterRegistry.wrap(interceptor));
  18. }
  19. }
  20. // 设置代理类
  21. proxyFactory.setTarget(getService());
  22. proxyFactory.setOpaque(true);
  23. // 获取代理对象
  24. return proxyFactory.getProxy(getBeanClassLoader());
  25. }
  • 这里要注意,切片方法的invoke调用
  • RmiInvocationWrapperinvoke方法会在调用方调用接口时候触发

rebind 和 bind

  • 绑定和重新绑定
  • 这部分源码在: sun.rmi.registry.RegistryImpl
  1. public void rebind(String var1, Remote var2) throws RemoteException, AccessException {
  2. checkAccess("Registry.rebind");
  3. this.bindings.put(var1, var2);
  4. }
  1. public void bind(String var1, Remote var2) throws RemoteException, AlreadyBoundException, AccessException {
  2. checkAccess("Registry.bind");
  3. synchronized(this.bindings) {
  4. Remote var4 = (Remote)this.bindings.get(var1);
  5. if (var4 != null) {
  6. throw new AlreadyBoundException(var1);
  7. } else {
  8. this.bindings.put(var1, var2);
  9. }
  10. }
  11. }
  • 共同维护private Hashtable<String, Remote> bindings = new Hashtable(101);这个对象

unexportObjectSilently

  • 出现异常时候调用方法
  1. private void unexportObjectSilently() {
  2. try {
  3. UnicastRemoteObject.unexportObject(this.exportedObject, true);
  4. }
  5. catch (NoSuchObjectException ex) {
  6. if (logger.isInfoEnabled()) {
  7. logger.info("RMI object for service '" + this.serviceName + "' is not exported anymore", ex);
  8. }
  9. }
  10. }

客户端初始化

RmiProxyFactoryBean

image-20200225104850528

  • 该类实现了InitializingBean接口直接看afterPropertiesSet方法

  • org.springframework.remoting.rmi.RmiProxyFactoryBean

      1. @Override
      2. public void afterPropertiesSet() {
      3. super.afterPropertiesSet();
      4. Class<?> ifc = getServiceInterface();
      5. Assert.notNull(ifc, "Property 'serviceInterface' is required");
      6. this.serviceProxy = new ProxyFactory(ifc, this).getProxy(getBeanClassLoader());
      7. }
    • org.springframework.remoting.rmi.RmiClientInterceptor#afterPropertiesSet

        1. @Override
        2. public void afterPropertiesSet() {
        3. super.afterPropertiesSet();
        4. prepare();
        5. }
      • org.springframework.remoting.support.UrlBasedRemoteAccessor#afterPropertiesSet

          1. @Override
          2. public void afterPropertiesSet() {
          3. if (getServiceUrl() == null) {
          4. throw new IllegalArgumentException("Property 'serviceUrl' is required");
          5. }
          6. }

org.springframework.remoting.support.UrlBasedRemoteAccessor#afterPropertiesSet

  • 该方法对 serviceUrl进行空判断,如果是空的抛出异常
  1. /**
  2. * 判断服务地址是否为空
  3. */
  4. @Override
  5. public void afterPropertiesSet() {
  6. if (getServiceUrl() == null) {
  7. throw new IllegalArgumentException("Property 'serviceUrl' is required");
  8. }
  9. }

org.springframework.remoting.rmi.RmiClientInterceptor#afterPropertiesSet

  1. @Override
  2. public void afterPropertiesSet() {
  3. super.afterPropertiesSet();
  4. prepare();
  5. }
  1. 调用父类的afterPropertiesSet方法判断serviceUrl是否为空
  2. 执行prepare()方法
  1. public void prepare() throws RemoteLookupFailureException {
  2. // Cache RMI stub on initialization?
  3. if (this.lookupStubOnStartup) {
  4. // 获取remote对象
  5. Remote remoteObj = lookupStub();
  6. if (logger.isDebugEnabled()) {
  7. if (remoteObj instanceof RmiInvocationHandler) {
  8. logger.debug("RMI stub [" + getServiceUrl() + "] is an RMI invoker");
  9. }
  10. else if (getServiceInterface() != null) {
  11. // 是否接口
  12. boolean isImpl = getServiceInterface().isInstance(remoteObj);
  13. logger.debug("Using service interface [" + getServiceInterface().getName() +
  14. "] for RMI stub [" + getServiceUrl() + "] - " +
  15. (!isImpl ? "not " : "") + "directly implemented");
  16. }
  17. }
  18. if (this.cacheStub) {
  19. this.cachedStub = remoteObj;
  20. }
  21. }
  22. }

org.springframework.remoting.rmi.RmiClientInterceptor#lookupStub

  1. protected Remote lookupStub() throws RemoteLookupFailureException {
  2. try {
  3. Remote stub = null;
  4. if (this.registryClientSocketFactory != null) {
  5. // RMIClientSocketFactory specified for registry access.
  6. // Unfortunately, due to RMI API limitations, this means
  7. // that we need to parse the RMI URL ourselves and perform
  8. // straight LocateRegistry.getRegistry/Registry.lookup calls.
  9. // 通过 serviceUrl 创建 URL
  10. URL url = new URL(null, getServiceUrl(), new DummyURLStreamHandler());
  11. // url 的协议
  12. String protocol = url.getProtocol();
  13. if (protocol != null && !"rmi".equals(protocol)) {
  14. throw new MalformedURLException("Invalid URL scheme '" + protocol + "'");
  15. }
  16. // 获取host
  17. String host = url.getHost();
  18. // 获取port
  19. int port = url.getPort();
  20. // 获取serviceName
  21. String name = url.getPath();
  22. if (name != null && name.startsWith("/")) {
  23. name = name.substring(1);
  24. }
  25. // 创建 Registry
  26. Registry registry = LocateRegistry.getRegistry(host, port, this.registryClientSocketFactory);
  27. // 获取Remote
  28. stub = registry.lookup(name);
  29. }
  30. else {
  31. // Can proceed with standard RMI lookup API...
  32. stub = Naming.lookup(getServiceUrl());
  33. }
  34. if (logger.isDebugEnabled()) {
  35. logger.debug("Located RMI stub with URL [" + getServiceUrl() + "]");
  36. }
  37. return stub;
  38. }
  39. catch (MalformedURLException ex) {
  40. throw new RemoteLookupFailureException("Service URL [" + getServiceUrl() + "] is invalid", ex);
  41. }
  42. catch (NotBoundException ex) {
  43. throw new RemoteLookupFailureException(
  44. "Could not find RMI service [" + getServiceUrl() + "] in RMI registry", ex);
  45. }
  46. catch (RemoteException ex) {
  47. throw new RemoteLookupFailureException("Lookup of RMI stub failed", ex);
  48. }
  49. }

org.springframework.remoting.rmi.RmiProxyFactoryBean#afterPropertiesSet

  1. @Override
  2. public void afterPropertiesSet() {
  3. super.afterPropertiesSet();
  4. // 获取 服务提供的接口
  5. Class<?> ifc = getServiceInterface();
  6. // 如果服务接口不为空
  7. Assert.notNull(ifc, "Property 'serviceInterface' is required");
  8. // 创建服务代理
  9. this.serviceProxy = new ProxyFactory(ifc, this).getProxy(getBeanClassLoader());
  10. }

增强调用

  • 通过类图我们可以知道RmiProxyFactoryBean实现了MethodInterceptor,具体实现方法在org.springframework.remoting.rmi.RmiClientInterceptor#invoke
  1. @Override
  2. public Object invoke(MethodInvocation invocation) throws Throwable {
  3. // 获取remote
  4. Remote stub = getStub();
  5. try {
  6. // 真正的invoke调用
  7. return doInvoke(invocation, stub);
  8. }
  9. catch (RemoteConnectFailureException ex) {
  10. return handleRemoteConnectFailure(invocation, ex);
  11. }
  12. catch (RemoteException ex) {
  13. if (isConnectFailure(ex)) {
  14. return handleRemoteConnectFailure(invocation, ex);
  15. }
  16. else {
  17. throw ex;
  18. }
  19. }
  20. }
  1. protected Remote getStub() throws RemoteLookupFailureException {
  2. if (!this.cacheStub || (this.lookupStubOnStartup && !this.refreshStubOnConnectFailure)) {
  3. // 如果缓存stub存在直接获取,否则创建
  4. return (this.cachedStub != null ? this.cachedStub : lookupStub());
  5. }
  6. else {
  7. synchronized (this.stubMonitor) {
  8. if (this.cachedStub == null) {
  9. this.cachedStub = lookupStub();
  10. }
  11. return this.cachedStub;
  12. }
  13. }
  14. }
  • org.springframework.remoting.rmi.RmiClientInterceptor#doInvoke(org.aopalliance.intercept.MethodInvocation, org.springframework.remoting.rmi.RmiInvocationHandler)
  1. @Nullable
  2. protected Object doInvoke(MethodInvocation methodInvocation, RmiInvocationHandler invocationHandler)
  3. throws RemoteException, NoSuchMethodException, IllegalAccessException, InvocationTargetException {
  4. if (AopUtils.isToStringMethod(methodInvocation.getMethod())) {
  5. return "RMI invoker proxy for service URL [" + getServiceUrl() + "]";
  6. }
  7. /**
  8. * 1. 参数组装成对象{@link RemoteInvocationBasedAccessor#createRemoteInvocation(org.aopalliance.intercept.MethodInvocation)}
  9. * 2. invoke 执行 简单来说就是调用{@link RmiInvocationHandler#invoke(RemoteInvocation)}方法
  10. */
  11. return invocationHandler.invoke(createRemoteInvocation(methodInvocation));
  12. }
  • RmiInvocationHandler类图

image-20200226082614312

最后的invoke方法

  • org.springframework.remoting.rmi.RmiInvocationWrapper#invoke

    1. /**
    2. * Delegates the actual invocation handling to the RMI exporter.
    3. *
    4. *
    5. * 远程调用的时候会执行
    6. * @see RmiBasedExporter#invoke(org.springframework.remoting.support.RemoteInvocation, Object)
    7. */
    8. @Override
    9. @Nullable
    10. public Object invoke(RemoteInvocation invocation)
    11. throws RemoteException, NoSuchMethodException, IllegalAccessException, InvocationTargetException {
    12. return this.rmiExporter.invoke(invocation, this.wrappedObject);
    13. }
    • 继续跟踪org.springframework.remoting.rmi.RmiBasedExporter#invoke

      1. @Override
      2. protected Object invoke(RemoteInvocation invocation, Object targetObject)
      3. throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
      4. return super.invoke(invocation, targetObject);
      5. }
      • 继续跟踪org.springframework.remoting.support.RemoteInvocationBasedExporter#invoke

        1. protected Object invoke(RemoteInvocation invocation, Object targetObject)
        2. throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
        3. if (logger.isTraceEnabled()) {
        4. logger.trace("Executing " + invocation);
        5. }
        6. try {
        7. return getRemoteInvocationExecutor().invoke(invocation, targetObject);
        8. }
        9. catch (NoSuchMethodException ex) {
        10. if (logger.isDebugEnabled()) {
        11. logger.debug("Could not find target method for " + invocation, ex);
        12. }
        13. throw ex;
        14. }
        15. catch (IllegalAccessException ex) {
        16. if (logger.isDebugEnabled()) {
        17. logger.debug("Could not access target method for " + invocation, ex);
        18. }
        19. throw ex;
        20. }
        21. catch (InvocationTargetException ex) {
        22. if (logger.isDebugEnabled()) {
        23. logger.debug("Target method failed for " + invocation, ex.getTargetException());
        24. }
        25. throw ex;
        26. }
        27. }
  • 关键语句return getRemoteInvocationExecutor().invoke(invocation, targetObject);

类图

image-20200226083247784

  1. public class DefaultRemoteInvocationExecutor implements RemoteInvocationExecutor {
  2. @Override
  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. return invocation.invoke(targetObject);
  8. }
  9. }
  1. public Object invoke(Object targetObject)
  2. throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
  3. Method method = targetObject.getClass().getMethod(this.methodName, this.parameterTypes);
  4. return method.invoke(targetObject, this.arguments);
  5. }
  • 这部分流程相对清晰,从对象中获取函数,调用这个函数

服务端 debug

  • org.springframework.remoting.rmi.RmiServiceExporter#afterPropertiesSet打上断点

image-20200226084056993

可以看到此时的数据字段和我们的 xml 配置中一致

  • org.springframework.remoting.rmi.RmiServiceExporter#prepare断点

    image-20200226084200428

    往下一直走

    image-20200226084400939

    ​ 这一行是 jdk 的就不进去看了

    执行完成就创建出了 Registry

    image-20200226084514795

  • org.springframework.remoting.rmi.RmiBasedExporter#getObjectToExport

    直接看结果对象

    image-20200226084640683

  • 执行 bind

    image-20200226084923783

    image-20200226084914000

  • 此时服务端信息已经成功记录并且启动

客户端 debug

image-20200226085433130

image-20200226085440865

remote 对象

image-20200226085727426

  • 服务提供接口

image-20200226085839496

  • serviceProxy

    image-20200226090042946

  • 方法调用

    • 使用的是 AOP 技术进行的,AOP 相关技术不在此处展开

image-20200226090315865

stub 对象

image-20200226090432052

image-20200226090650154

  • invocation

    image-20200226090719108

  • targetObject

    image-20200226090827849

  • 反射执行method结束整个调用

    image-20200226090945418

    此时得到结果 RMI 调用结束