Spring Rmi远程方法调用

Appsflyer Web2App实战指南:OneLink与Web SDK深度对比 本文深入对比了Appsflyer实现Web2App的两大核心工具:OneLink智能链接与Web SDK。OneLink提供开箱即用的智能跳转,部署快捷,适合快速推广;Web SDK则支持高度自定义的用户行为追踪,适合深度分析与精细化运营。文章提供了详细的配置指南、场景化选型建议及实战避坑技巧,帮助营销与开发团队根据自身需求选择最佳方案,有效提升从网页到应用的转化率与归因精度。 阅读详情

http://blog.youkuaiyun.com/java2000_wl/article/details/7407073

http://zcjl.iteye.com/blog/36336

一: 服务端  暴露服务

  1. package com.xx.service;  
  2.   
  3. /** 
  4.  * 定义远程服务接口  
  5.  * 1.可以不继承java.rmi.Remote接口 
  6.  * 2.方法可以不抛出java.rmi.RemoteException异常 
  7.  *  
  8.  */  
  9. public interface ISayHelloService {  
  10.       
  11.     public String doSayHello(String name);  
  12. }  
package com.xx.service;

/**
 * 定义远程服务接口 
 * 1.可以不继承java.rmi.Remote接口
 * 2.方法可以不抛出java.rmi.RemoteException异常
 * 
 */
public interface ISayHelloService {
	
	public String doSayHello(String name);
}

 

  1. package com.xx.service.impl;  
  2.   
  3. import com.xx.service.ISayHelloService;  
  4.   
  5. /** 
  6.  * 远程接口实现 
  7.  */  
  8. public class ChinaSayHelloServiceImpl implements ISayHelloService {  
  9.   
  10.     public String doSayHello(String name) {  
  11.         return "hello " + name;  
  12.     }  
  13. }  
package com.xx.service.impl;

import com.xx.service.ISayHelloService;

/**
 * 远程接口实现
 */
public class ChinaSayHelloServiceImpl implements ISayHelloService {

	public String doSayHello(String name) {
		return "hello " + name;
	}
}
  1. package com.xx.service;  
  2.   
  3. import org.springframework.context.ApplicationContext;  
  4. import org.springframework.context.support.ClassPathXmlApplicationContext;  
  5.   
  6. /** 
  7.  * 服务端   
  8.  * 暴露远程服务 
  9.  */  
  10. public class ServerMain {  
  11.       
  12.     public static void main(String[] args) {  
  13.         ApplicationContext context = new ClassPathXmlApplicationContext(new String[]{"classpath:applicationContext-server.xml"}, true);  
  14.         System.out.println("==============服务启动成功 ==============");  
  15.     }  
  16. }  
package com.xx.service;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 * 服务端  
 * 暴露远程服务
 */
public class ServerMain {
	
	public static void main(String[] args) {
		ApplicationContext context = new ClassPathXmlApplicationContext(new String[]{"classpath:applicationContext-server.xml"}, true);
		System.out.println("==============服务启动成功 ==============");
	}
}
  1. spring配置文件 applicationContext-server.xml  
  2.   
  3. <?xml version="1.0" encoding="UTF-8"?>  
  4. <beans xmlns="http://www.springframework.org/schema/beans"  
  5.     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"   
  6.     xmlns:context="http://www.springframework.org/schema/context"  
  7.     xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd  
  8.         http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd">  
  9.           
  10.         <bean id="chinaSayHelloService" class="com.xx.service.impl.ChinaSayHelloServiceImpl" />  
  11.           
  12.         <bean id="chinaSayHelloServiceRmi" class="org.springframework.remoting.rmi.RmiServiceExporter" >  
  13.             <property name="serviceName"         value="chinaSayHelloService" />  
  14.             <property name="service"             ref="chinaSayHelloService"/>  
  15.             <property name="serviceInterface"    value="com.xx.service.ISayHelloService"/>  
  16.             <property name="registryPort"        value="9999"/>  
  17.         </bean>  
  18. </beans>  
spring配置文件 applicationContext-server.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
	xmlns:context="http://www.springframework.org/schema/context"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
		http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd">
		
		<bean id="chinaSayHelloService" class="com.xx.service.impl.ChinaSayHelloServiceImpl" />
		
		<bean id="chinaSayHelloServiceRmi" class="org.springframework.remoting.rmi.RmiServiceExporter" >
			<property name="serviceName" 		value="chinaSayHelloService" />
			<property name="service" 			ref="chinaSayHelloService"/>
			<property name="serviceInterface" 	value="com.xx.service.ISayHelloService"/>
			<property name="registryPort" 		value="9999"/>
		</bean>
</beans>


二:客户端  远程方法调用

  1. package com.xx.service;  
  2.   
  3. import java.net.UnknownHostException;  
  4.   
  5. import org.springframework.context.ApplicationContext;  
  6. import org.springframework.context.support.ClassPathXmlApplicationContext;  
  7.   
  8. /** 
  9.  *  客户端 
  10.  */  
  11. public class ClientMain {  
  12.       
  13.     public static void main(String[] args) throws UnknownHostException {  
  14.         ApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:applicationContext-client.xml");  
  15.         ISayHelloService object = applicationContext.getBean("chinaSayHelloServiceRmi", ISayHelloService.class);  
  16.         System.out.println(object.doSayHello("张三"));  
  17.     }  
  18. }  
package com.xx.service;

import java.net.UnknownHostException;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 *  客户端
 */
public class ClientMain {
	
	public static void main(String[] args) throws UnknownHostException {
		ApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:applicationContext-client.xml");
		ISayHelloService object = applicationContext.getBean("chinaSayHelloServiceRmi", ISayHelloService.class);
		System.out.println(object.doSayHello("张三"));
	}
}
  1. spring配置文件 applicationContext-client.xml  
  2.   
  3. <?xml version="1.0" encoding="UTF-8"?>  
  4. <beans xmlns="http://www.springframework.org/schema/beans"  
  5.     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"   
  6.     xmlns:context="http://www.springframework.org/schema/context"  
  7.     xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd   
  8.         http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd">   
  9.           
  10.         <bean id="chinaSayHelloServiceRmi" class="org.springframework.remoting.rmi.RmiProxyFactoryBean" >  
  11.             <property name="serviceUrl" value="rmi://192.168.3.104:9999/chinaSayHelloService" />  
  12.             <property name="serviceInterface"    value="com.xx.service.ISayHelloService"/>  
  13.         </bean>  
  14. </beans>  

 

 

看了《J2EE without EJB》的remote章节,忍不住写点代码试试,看看Spring的实现到底多巧妙。

1.先测试RMI服务的发布,测试代码如下:

java 代码
  1. //MyService.java: remote interface for RMI   
  2. package test.spring.remote.rmi;   
  3.   
  4. public interface MyService extends java.rmi.Remot {   
  5.     public void doSomething() throws java.rmi.RemoteException;   
  6. }   
  7.   
  8.   
  9. //MyBusinessInterface.java: My own business interface, must has the same methods as MyService   
  10. package test.spring.remote.rmi;   
  11.   
  12. public interface MyBusinessInterface {   
  13.     public void doSomething();   
  14. }   
  15.   
  16.   
  17. //MyServiceImpl.java: the service implement class   
  18. package test.spring.remote.rmi;   
  19.   
  20. public class MyServiceImpl implements MyService, MyBusinessInterface {   
  21.     public void doSomething() {   
  22.         System.out.println("MyServiceImpl.doSomething()");   
  23.     }   
  24. }  


Spring的context配置文件如下:

xml 代码
  1. //spring-remote.xml   
  2. <?xml version="1.0" encoding="UTF-8"?>  
  3. <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN"   
  4.     "http://www.springframework.org/dtd/spring-beans.dtd">  
  5.   
  6. <beans>  
  7.     <bean id="myService" class="test.spring.remote.rmi.MyServiceImpl" />  
  8.     <bean id="serviceExporter" class="org.springframework.remoting.rmi.RmiServiceExporter">  
  9.         <property name="serviceName">  
  10.             <value>myService</value>  
  11.         </property>  
  12.         <property name="service">  
  13.             <ref bean="myService" />  
  14.         </property>  
  15.         <property name="serviceInterface">  
  16.             <value>test.spring.remote.rmi.MyService</value>  
  17.         </property>  
  18.         <property name="registryPort">  
  19.             <value>1199</value>  
  20.         </property>  
  21.     </bean>  
  22. </beans>  


再写一个测试程序,如下:

java 代码
  1. //TestSpringRmi.java   
  2. package test.spring.remote.rmi;   
  3.   
  4. import org.springframework.context.ApplicationContext;   
  5. import org.springframework.context.support.ClassPathXmlApplicationContext;   
  6.   
  7. public class TestSpringRmi {   
  8.     public static void main(String[] args) {   
  9.         ApplicationContext context = new ClassPathXmlApplicationContext("spring-remote.xml");   
  10.     }   
  11. }  


运行TestSpringRmi,报错如下:

org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'serviceExporter' defined in class path resource [spring-remote.xml]: Initialization of bean failed; nested exception is java.rmi.StubNotFoundException: Stub class not found: test.spring.remote.rmi.MyServiceImpl_Stub; nested exception is:
 java.lang.ClassNotFoundException: test.spring.remote.rmi.MyServiceImpl_Stub
java.rmi.StubNotFoundException: Stub class not found: test.spring.remote.rmi.MyServiceImpl_Stub; nested exception is:
 java.lang.ClassNotFoundException: test.spring.remote.rmi.MyServiceImpl_Stub

咦?Spring不是号称不需要自己生成stub么?怎么会出现“Stub class not found”呢?
祭出google,从spring官方论坛搜到一个帖子:http://forum.springframework.org/showthread.php?t=19185,里面有条回复是:

I found the answer:
The class org.springframework.remoting.rmi.RmiInvocationWrap per_Stub is present in spring.jar, but not in the source tree as a Java file. Since I was running against the compiled Spring Java files, rather than the jar, it did not find it.

晕倒,Spring不会这么弱智吧,难道我以后使用的时候还得把jar包解压到class目录下?
不甘心,再搜,找到这个帖子:http://forum.springframework.org/showthread.php?t=12685

在Juergen Hoeller的回复提示下,我再去看了jpetstore的配置文件,原来用以发布rmi的接口应该是pojo形式的MyBusinessInterface,而不是那个继承自Remote的MyService,修改自己的context配置文件:

xml 代码
  1. //spring-remote.xml   
  2. <?xml version="1.0" encoding="UTF-8"?>  
  3. <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN"   
  4.     "http://www.springframework.org/dtd/spring-beans.dtd">  
  5.   
  6. <beans>  
  7.     <bean id="myService" class="test.spring.remote.rmi.MyServiceImpl" />  
  8.     <bean id="serviceExporter" class="org.springframework.remoting.rmi.RmiServiceExporter">  
  9.         <property name="serviceName">  
  10.             <value>myService</value>  
  11.         </property>  
  12.         <property name="service">  
  13.             <ref bean="myService" />  
  14.         </property>  
  15.         <property name="serviceInterface">  
  16.             <!-- <value>test.spring.remote.rmi.MyService</value> -->  
  17.             <value>test.spring.remote.rmi.MyBusinessInterface</value>  
  18.         </property>  
  19.         <property name="registryPort">  
  20.             <value>1199</value>  
  21.         </property>  
  22.     </bean>  
  23. </beans>  

再运行TestSpringRmi,成功了。console打印:
03-02 14:51:56 INFO  [RmiServiceExporter.java:236] Binding RMI service 'myService' to registry at port '1199'


2.再继续测试客户端调用,先修改context配置如下:

xml 代码
  1. //spring-remote.xml   
  2. <?xml version="1.0" encoding="UTF-8"?>  
  3. <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN"   
  4.     "http://www.springframework.org/dtd/spring-beans.dtd">  
  5.   
  6. <beans>  
  7.     <bean id="rmiService"  
  8.         class="org.springframework.remoting.rmi.RmiProxyFactoryBean">  
  9.         <property name="serviceInterface">  
  10.             <value>test.spring.remote.rmi.MyBusinessInterface</value>  
  11.         </property>  
  12.         <property name="serviceUrl">  
  13.             <value>rmi://localhost:1199/myService</value>  
  14.         </property>  
  15.     </bean>  
  16.     <bean id="myService" class="test.spring.remote.rmi.MyServiceImpl" />  
  17.     <bean id="serviceExporter" class="org.springframework.remoting.rmi.RmiServiceExporter">  
  18.         <property name="serviceName">  
  19.             <value>myService</value>  
  20.         </property>  
  21.         <property name="service">  
  22.             <ref bean="myService" />  
  23.         </property>  
  24.         <property name="serviceInterface">  
  25.             <!-- <value>test.spring.remote.rmi.MyService</value> -->  
  26.             <value>test.spring.remote.rmi.MyBusinessInterface</value>  
  27.         </property>  
  28.         <property name="registryPort">  
  29.             <value>1199</value>  
  30.         </property>  
  31.     </bean>  
  32. </beans>  

再修改测试代码,添加客户端调用:

java 代码
  1. //TestSpringRmi.java   
  2. package test.spring.remote.rmi;   
  3.   
  4. import org.springframework.context.ApplicationContext;   
  5. import org.springframework.context.support.ClassPathXmlApplicationContext;   
  6.   
  7. public class TestSpringRmi {   
  8.     public static void main(String[] args) {   
  9.         ApplicationContext context = new ClassPathXmlApplicationContext("spring-remote.xml");   
  10.         MyBusinessInterface service = (MyBusinessInterface) context.getBean("rmiService");   
  11.         service.doSomething();   
  12.     }   
  13. }  

运行TestSpringRmi,报错如下:

org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'rmiService' defined in class path resource [spring-remote.xml]: Initialization of bean failed; nested exception is java.rmi.ConnectException: Connection refused to host: localhost; nested exception is:
 java.net.ConnectException: Connection refused: connect
java.rmi.ConnectException: Connection refused to host: localhost; nested exception is:
 java.net.ConnectException: Connection refused: connect

仔细检查,原来自己把生成rmi客户端的bean映射放到了发布rmi服务的serviceExporter之前了,调换一下顺序:

    xml 代码

  1. //spring-remote.xml   
  2. <?xml version="1.0" encoding="UTF-8"?>  
  3. <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN"   
  4.     "http://www.springframework.org/dtd/spring-beans.dtd">  
  5.   
  6. <beans>  
  7.     <bean id="myService" class="test.spring.remote.rmi.MyServiceImpl" />  
  8.     <bean id="serviceExporter" class="org.springframework.remoting.rmi.RmiServiceExporter">  
  9.         <property name="serviceName">  
  10.             <value>myService</value>  
  11.         </property>  
  12.         <property name="service">  
  13.             <ref bean="myService" />  
  14.         </property>  
  15.         <property name="serviceInterface">  
  16.             <!-- <value>test.spring.remote.rmi.MyService</value> -->  
  17.             <value>test.spring.remote.rmi.MyBusinessInterface</value>  
  18.         </property>  
  19.         <property name="registryPort">  
  20.             <value>1199</value>  
  21.         </property>  
  22.     </bean>  
  23.     <bean id="rmiService"  
  24.         class="org.springframework.remoting.rmi.RmiProxyFactoryBean">  
  25.         <property name="serviceInterface">  
  26.             <value>test.spring.remote.rmi.MyBusinessInterface</value>  
  27.         </property>  
  28.         <property name="serviceUrl">  
  29.             <value>rmi://localhost:1199/myService</value>  
  30.         </property>  
  31.     </bean>  
  32. </beans>  

运行TestSpringRmi,结果如下:
03-02 15:01:24 INFO  [RmiServiceExporter.java:236] Binding RMI service 'myService' to registry at port '1199'
03-02 15:01:24 INFO  [RmiClientInterceptor.java:128] RMI stub [rmi://localhost:1199/myService] is an RMI invoker
MyServiceImpl.doSomething()


经过一番浅尝辄止,初步得出几个结论:
1.Spring对RMI的支持果然很不错,在Cglib等工具的支持下,使用RMI终于可以同Naming、rmic和stub告别了。
2.用以发布RMI的接口不能从java.rmi.Remote继承而来,否则就会出现“Stub class not found”的错误,原因有待深究。
3.Spring的BeanFactory创建bean实例是有序的,向RMI、JNDI、WebService等注册服务性质的应用,同一应用中的客户端要根据其依赖性调整配置顺序。

 

JNDI的使用方式

服务端注册

 	<bean class="org.springframework.remoting.rmi.JndiRmiServiceExporter">
		<property name="service" ref="creditService" />
		<property name="serviceInterface" value="com.common.CreditRemoteService" />
		<property name="jndiName" value="CreditService" />
	</bean>


客户端调用xml配置

	<bean id="creditService" class="org.springframework.remoting.rmi.JndiRmiProxyFactoryBean"
			scope="prototype" lazy-init="true">
		<property name="serviceInterface" value="com.common.CreditRemoteService" />
	    <property name="lookupStubOnStartup" value="false"/>
	    <property name="refreshStubOnConnectFailure" value="true"/>
		<property name="jndiName" value="CreditService" /> 
		<property name="jndiEnvironment">
			<props>
				<prop key="java.naming.provider.url">${com.jndi.creditServiceUrl}</prop>
				<prop key ="java.naming.factory.initial">weblogic.jndi.WLInitialContextFactory</prop>
			</props>
		</property>
	</bean>


 

 

Spring RMI 源码浅析-RmiServiceExporter 导出服务

分类: 源码学习 317人阅读 评论(0) 收藏 举报

Java Rmi

1.接口必须继承java.rmi.Remote接口

2.方法必须抛出java.rmi.RemoteException异常

Spring Rmi

1.可以不实现java.rmi.Remote接口 

2.方法可以不抛出异常  

问题:在Spring 内部是怎么实现的?

在Spring中 是通过org.springframework.remoting.rmi.RmiServiceExporte 在服务端导出一个服务

RmiServiceExporter定义

  1. public class RmiServiceExporter extends RmiBasedExporter implements InitializingBean, DisposableBean {  
  2. }  
public class RmiServiceExporter extends RmiBasedExporter implements InitializingBean, DisposableBean {
}

实现了 InitializingBean接口  Spring会在bean的实例化阶段 调用 InitializingBean 的afterPropertiesSet 方法

bean的实例化 会在什么时候触发 取决于配置 例如lazy-init 

RmiServiceExporter afterPropertiesSet 方法实现

  1. public void afterPropertiesSet() throws RemoteException {  
  2.     prepare();  
  3. }  
	public void afterPropertiesSet() throws RemoteException {
		prepare();
	}

prepare方法

  1. public void prepare() throws RemoteException {  
  2.     //检查配置中的 service对象   如果为null 抛出异常    
  3.     checkService();  
  4.     //检查服务名称   
  5.     if (this.serviceName == null) {  
  6.         throw new IllegalArgumentException("Property 'serviceName' is required");  
  7.     }  
  8.     // Check socket factories for exported object.   
  9.     // 略....   
  10.   
  11.     // Determine RMI registry to use.   
  12.     if (this.registry == null) {  
  13.         //获得注册器   
  14.         this.registry = getRegistry(this.registryHost, this.registryPort,  
  15.             this.registryClientSocketFactory, this.registryServerSocketFactory);  
  16.     }  
  17.     // 获得要导出的服务对象   
  18.     // getObjectToExport方法  在父类RmiBasedExporter中定义    
  19.     // 1.如果实现了jdk Remote接口 那就是一个标准的RMI 类型转换后 直接返回   
  20.     // 2.没有实现jdk Remote接口  返回spring包装对象RmiInvocationWrapper调用器  RmiInvocationWrapper实现了jdk Remote接口   
  21.     // RmiInvocationWrapper 中有两个属性  1.wrappedObject 自己定义的远程对象[service属性]     
  22.     // 2.RmiBasedExporter 也就是当前导出对象 this 在客户端调用的时候  会触发invoke方法   
  23.     this.exportedObject = getObjectToExport();  
  24.   
  25.     // 导出服务对象   jdk UnicastRemoteObject实现   
  26.     if (this.clientSocketFactory != null) {  
  27.         UnicastRemoteObject.exportObject(  
  28.                 this.exportedObject, this.servicePort, this.clientSocketFactory, this.serverSocketFactory);  
  29.     }  
  30.     else {  
  31.         UnicastRemoteObject.exportObject(this.exportedObject, this.servicePort);  
  32.     }  
  33.   
  34.     // Bind RMI object to registry.   
  35.     // 把RMI远程服务对象和注册器绑定 jdk实现   
  36.     try {  
  37.         if (this.replaceExistingBinding) {  
  38.             //替换指定serviceName的远程对象   
  39.             this.registry.rebind(this.serviceName, this.exportedObject);  
  40.         }  
  41.         else {  
  42.             //绑定对象   
  43.             this.registry.bind(this.serviceName, this.exportedObject);  
  44.         }  
  45.     }  
  46.     catch (AlreadyBoundException ex) {  
  47.         // Already an RMI object bound for the specified service name...   
  48.         unexportObjectSilently();  
  49.         throw new IllegalStateException(  
  50.                 "Already an RMI object bound for name '"  + this.serviceName + "': " + ex.toString());  
  51.     }  
  52.     catch (RemoteException ex) {  
  53.         // Registry binding failed: let's unexport the RMI object as well.   
  54.         unexportObjectSilently();  
  55.         throw ex;  
  56.     }  
  57. }  
	public void prepare() throws RemoteException {
		//检查配置中的 service对象   如果为null 抛出异常 
		checkService();
		//检查服务名称
		if (this.serviceName == null) {
			throw new IllegalArgumentException("Property 'serviceName' is required");
		}
		// Check socket factories for exported object.
		// 略....

		// Determine RMI registry to use.
		if (this.registry == null) {
			//获得注册器
			this.registry = getRegistry(this.registryHost, this.registryPort,
				this.registryClientSocketFactory, this.registryServerSocketFactory);
		}
		// 获得要导出的服务对象
		// getObjectToExport方法  在父类RmiBasedExporter中定义 
		// 1.如果实现了jdk Remote接口 那就是一个标准的RMI 类型转换后 直接返回
		// 2.没有实现jdk Remote接口  返回spring包装对象RmiInvocationWrapper调用器  RmiInvocationWrapper实现了jdk Remote接口
		// RmiInvocationWrapper 中有两个属性  1.wrappedObject 自己定义的远程对象[service属性]  
		// 2.RmiBasedExporter 也就是当前导出对象 this 在客户端调用的时候  会触发invoke方法
		this.exportedObject = getObjectToExport();

		// 导出服务对象   jdk UnicastRemoteObject实现
		if (this.clientSocketFactory != null) {
			UnicastRemoteObject.exportObject(
					this.exportedObject, this.servicePort, this.clientSocketFactory, this.serverSocketFactory);
		}
		else {
			UnicastRemoteObject.exportObject(this.exportedObject, this.servicePort);
		}

		// Bind RMI object to registry.
		// 把RMI远程服务对象和注册器绑定 jdk实现
		try {
			if (this.replaceExistingBinding) {
				//替换指定serviceName的远程对象
				this.registry.rebind(this.serviceName, this.exportedObject);
			}
			else {
				//绑定对象
				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;
		}
	}

checkService方法 

  1. protected void checkService() throws IllegalArgumentException {  
  2.     if (getService() == null) {  
  3.         throw new IllegalArgumentException("Property 'service' is required");  
  4.     }  
  5. }  
	protected void checkService() throws IllegalArgumentException {
		if (getService() == null) {
			throw new IllegalArgumentException("Property 'service' is required");
		}
	}
  1. protected Remote getObjectToExport() {  
  2.     //自定义的远程对象 实现了 jdk Remote   
  3.     if (getService() instanceof Remote &&  
  4.             (getServiceInterface() == null || Remote.class.isAssignableFrom(getServiceInterface()))) {              return (Remote) getService();  
  5.     }  
  6.     else {  
  7.         //  没有实现  Remote接口  spring在此处包装了我们自定义的远程服务对象   
  8.         // getProxyForService方法 返回一个代理对象   
  9.         return new RmiInvocationWrapper(getProxyForService(), this);  
  10.     }  
  11. }  
	protected Remote getObjectToExport() {
		//自定义的远程对象 实现了 jdk Remote
		if (getService() instanceof Remote &&
				(getServiceInterface() == null || Remote.class.isAssignableFrom(getServiceInterface()))) {				return (Remote) getService();
		}
		else {
			//  没有实现  Remote接口  spring在此处包装了我们自定义的远程服务对象
			// getProxyForService方法 返回一个代理对象
			return new RmiInvocationWrapper(getProxyForService(), this);
		}
	}

RmiInvocationWrapper定义  实现了RmiInvocationHandler接口  而RmiInvocationHandler接口继承了Remote 接口

  1. class RmiInvocationWrapper implements RmiInvocationHandler {  
  2.   
  3.     private final Object wrappedObject;  
  4.   
  5.     private final RmiBasedExporter rmiExporter;  
  6.   
  7.     public RmiInvocationWrapper(Object wrappedObject, RmiBasedExporter rmiExporter) {  
  8.         Assert.notNull(wrappedObject, "Object to wrap is required");  
  9.         Assert.notNull(rmiExporter, "RMI exporter is required");  
  10.         this.wrappedObject = wrappedObject;  
  11.         this.rmiExporter = rmiExporter;  
  12.     }  
  13.   
  14.   
  15.     public String getTargetInterfaceName() {  
  16.         Class ifc = this.rmiExporter.getServiceInterface();  
  17.         return (ifc != null ? ifc.getName() : null);  
  18.     }  
  19.   
  20.     /*** 
  21.      * 非标准的RMI调用远程方法的中转站 
  22.      * invocation封装了方法名 参数名 
  23.      */  
  24.     public Object invoke(RemoteInvocation invocation)  
  25.         throws RemoteException, NoSuchMethodException, IllegalAccessException, InvocationTargetException {  
  26.         //会在客户端调用远程方法时触发,chuwrappedObject是 我们定义的远程对象    
  27.         return this.rmiExporter.invoke(invocation, this.wrappedObject);  
  28.     }  
  29. }  
class RmiInvocationWrapper implements RmiInvocationHandler {

	private final Object wrappedObject;

	private final RmiBasedExporter rmiExporter;

	public RmiInvocationWrapper(Object wrappedObject, RmiBasedExporter rmiExporter) {
		Assert.notNull(wrappedObject, "Object to wrap is required");
		Assert.notNull(rmiExporter, "RMI exporter is required");
		this.wrappedObject = wrappedObject;
		this.rmiExporter = rmiExporter;
	}


	public String getTargetInterfaceName() {
		Class ifc = this.rmiExporter.getServiceInterface();
		return (ifc != null ? ifc.getName() : null);
	}

	/***
	 * 非标准的RMI调用远程方法的中转站
	 * invocation封装了方法名 参数名
	 */
	public Object invoke(RemoteInvocation invocation)
	    throws RemoteException, NoSuchMethodException, IllegalAccessException, InvocationTargetException {
		//会在客户端调用远程方法时触发,chuwrappedObject是 我们定义的远程对象 
		return this.rmiExporter.invoke(invocation, this.wrappedObject);
	}
}

RmiInvocationHandler接口继承了 jdk Remote

  1. public interface RmiInvocationHandler extends Remote {  
  2. }  
public interface RmiInvocationHandler extends Remote {
}
  1. protected Object getProxyForService() {  
  2.         //检查配置中的 service对象   如果为null 抛出异常   
  3.         checkService();  
  4.         //检查serviceInterface属性     
  5.         checkServiceInterface();  
  6.         ProxyFactory proxyFactory = new ProxyFactory();  
  7.         proxyFactory.addInterface(getServiceInterface());  
  8.         if (this.registerTraceInterceptor != null ?  
  9.                 this.registerTraceInterceptor.booleanValue() : this.interceptors == null) {  
  10.             proxyFactory.addAdvice(new RemoteInvocationTraceInterceptor(getExporterName()));  
  11.         }  
  12.         if (this.interceptors != null) {  
  13.             AdvisorAdapterRegistry adapterRegistry = GlobalAdvisorAdapterRegistry.getInstance();  
  14.             for (int i = 0; i < this.interceptors.length; i++) {  
  15.                 proxyFactory.addAdvisor(adapterRegistry.wrap(this.interceptors[i]));  
  16.             }  
  17.         }  
  18.         proxyFactory.setTarget(getService());  
  19.         // 生成代理对象  到底是jdk实现 还是cglib实现  取决于 到底有没有实现接口   
  20.         return proxyFactory.getProxy(getBeanClassLoader());  
  21.     }  
protected Object getProxyForService() {
		//检查配置中的 service对象   如果为null 抛出异常
		checkService();
		//检查serviceInterface属性  
		checkServiceInterface();
		ProxyFactory proxyFactory = new ProxyFactory();
		proxyFactory.addInterface(getServiceInterface());
		if (this.registerTraceInterceptor != null ?
				this.registerTraceInterceptor.booleanValue() : this.interceptors == null) {
			proxyFactory.addAdvice(new RemoteInvocationTraceInterceptor(getExporterName()));
		}
		if (this.interceptors != null) {
			AdvisorAdapterRegistry adapterRegistry = GlobalAdvisorAdapterRegistry.getInstance();
			for (int i = 0; i < this.interceptors.length; i++) {
				proxyFactory.addAdvisor(adapterRegistry.wrap(this.interceptors[i]));
			}
		}
		proxyFactory.setTarget(getService());
		// 生成代理对象  到底是jdk实现 还是cglib实现  取决于 到底有没有实现接口
		return proxyFactory.getProxy(getBeanClassLoader());
	}

总结:1.spring 容器发布一个远程服务 是通过InitializingBean接口驱动起来的

            2.spring 包装了JDK Rmi  也就是说 服务端是spring暴露   客户端也可以用Jdk rmi调用 没有任何问题

            3,spring对没有实现Remote接口的远程服务 用RmiInvocationWrapper做了包装  RmiInvocationWrapper实现了Remote接口

 

【用unity实现100个游戏之16】Unity程序化生成随机2D地牢游戏1(附项目源码) 关于使用TileMap生成随机2D地图,其实之前已经有做过类似的,感兴趣可以看看 但是随着学习深入,发现之前做的比较粗糙和不够全面,最近又在外网看到 阅读详情

相关推荐

【MFRC522】STM32与MFRC522的SPI通信优化及常见问题解析

本文深入解析了STM32与MFRC522进行SPI通信的优化方法与常见问题。从基础的硬件连接到SPI时序优化,再到关键的寄存器配置(如RFCfgReg设为0x4F以提升读卡稳定性),文章提供了详细的调试技巧和实战排坑指南,帮助开发者实现稳定高效的IC读卡应用。

yhn45678901的博客 841

java.lang.ClassNotFoundException: org.springframework.remoting.rmi.RmiInvocationWrapper_Stub

org.springframework.remoting.RemoteLookupFailureException: Lookup of RMI stub failed; nested exception is java.rmi.UnmarshalException: error unmarshalling return; nested exception is: java.lang.Class...

weixin_30821731的博客 795

保姆级教程:用Comsol Multiphysics仿真你的第一个SAW滤波器(含压电材料参数设置)

本文提供了一份详细的COMSOL Multiphysics教程,指导读者完成表面声波滤波器(SAW)的压电仿真全流程。从压电材料参数设置、叉指换能器建模到多物理场耦合分析,特别强调了实际应用中容易出错的细节和解决方案,帮助工程师快速掌握SAW滤波器仿真技术。

weixin_42665255的博客 592

spring集成rmi的注意事项

服务端用spring2发布服务 客户端用spring3调用rmi接口 就会报下面的错误: java.lang.ClassNotFoundException: org.springframework.remoting.rmi.RmiInvocationWrapper_Stub (no security manager: RMI class loader disabled) spr

fifa_016的专栏 1211

精益六西格玛Python数字化应用开发-Day18 应用场景:家电企业生产效率优化

本文将重点介绍专门针对精益六西格玛黑带使用场景的 Python 库,这些库功能侧重于数据分析和流程优化,特别适用于 DMAIC 方法论和看板管理。考虑到读者具备中高级Python 使用经验,我们将深入探讨各库的高级功能和实际应用应用场景。 某家电企业生产线自动化程度高,数据量巨大,希望通过精益管理提升生产效率。企业借助 Python 脚本,打通各类数据源(MES、ERP、设备日志),自动归集生产数据,分析各工序的生产节拍、设备停机、效率损失,快速定位瓶颈环节

m0_56592100的博客 905

HTTPS接口测试翻车实录:为什么浏览器能访问而curl报证书错误?

本文深入分析了HTTPS接口测试中浏览器访问正常而curl报证书错误的典型问题。通过对比浏览器、Postman和curl的工具行为差异,结合Nginx日志与Wireshark抓包,揭示了问题根源在于网络架构中HTTPS请求被意外“降级”为HTTP传输,导致SSL握手失败。文章重点探讨了curl工具严格验证机制暴露的`Peer's Certificate issuer is not recognized`错误,并提供了网络配置修正方案与标准化测试流程。

u9v0w的博客 278

java.lang.ClassNotFoundException异常问题原因总结

常会遇到报找不到类的问题,有时是没有引入相关类,但很多时候明明是有的,现把原因简单总结如下: 1、java.lang.ClassNotFoundException: com.alibaba.nacos.client.logging.NacosLogging 调试spring cloud alibaba总报这个错,查到对应包nacos-client-2.0.3有此类,双击无法打开,果断判断是包下载问题,去仓库删除下载包,maven重新下载,搞定! 2、还有一种常见的报错原因是引入了不同版本的包,两个包都

u011017880的专栏 5万+

Meta-World环境实战解析:pick-place-v2中的状态观测与动作控制

本文深入解析了Meta-World中pick-place-v2环境的强化学习实战要点。文章详细拆解了39维状态观测向量的构成与意义,包括机械臂末端、物体位置及目标坐标,并揭示了默认部分可观测设置的潜在影响。同时,阐述了4维动作空间的控制逻辑与奖励函数的分阶段设计,为训练高效稳定的抓放策略提供了核心指导与实用调优技巧。

weixin_29184371的博客 77

@java.lang.ClassNotFoundException:org.springframework.web.context.ContextLoaderListener错误解决方法[TOC](t

@java.lang.ClassNotFoundException:org.springframework.web.context.ContextLoaderListener错误解决方法TOC 12-Mar-2018 12:08:02.345 严重 [RMI TCP Connection(2)-127.0.0.1] org.apache.catalina.core.StandardContext....

wu274899434的博客 649

神经形态芯片:IBM TrueNorth技术详解以及应用案例

2018年的一项演示中,机器人使用TrueNorth处理了复杂的路径规划,功耗仅为传统系统的1/10。它通过模仿人脑的结构,解决了传统芯片在功耗和并行性上的痛点,并在图像识别、物联网和机器人等领域展现了强大潜力。:不同于传统芯片的时钟驱动,TrueNorth是事件驱动的。例如,工厂中的振动传感器使用TrueNorth检测设备故障的早期迹象,实现了更高效的维护策略,避免了停机时间。:在医疗领域,TrueNorth可以用于可穿戴设备,比如一个智能助听器,它能过滤噪音并增强特定声音,功耗低到可以用纽扣电池供电。

远程部署调试 运行安装 项目调试 二次开发 项目技术新 持续迭代 部分源码免费分享 2477

Unitree G1仿人机器人协同搬箱:从仿真搭建到多机协同部署完整指南

Unitree G1仿人机器人协同搬箱技术方案摘要 本文提供了一套完整的Unitree G1人形机器人协同搬箱解决方案,涵盖从仿真环境搭建到多机协同部署的全流程。核心内容包括: 双仿真环境配置:同时搭建Gazebo+ROS Noetic基础仿真环境与Isaac Gym+Mujoco高性能RL训练环境,支持Sim2Sim迁移验证 训练框架搭建:详细配置unitree_rl_gym框架,提供PPO算法定制化训练流程和参数优化方案 数据集应用:整合宇树开源真机数据集(UnifoLM-WBT-Dataset)~~~

huanghm88的专栏 471

Maven构建SpringMVC环境报错“java.lang.ClassNotFoundException: org.springframework.web.servlet. DispatcherSe

今天朋友发了个maven项目给我看,问我为什么启动不了。说实话,一直用Jfinal都快不会用spring了… 还是决定看看。接收了文件,是maven构建的,打开eclipse,导入maven项目,然后部署到tomcat,启动tomcat,就报错了:“java.lang.ClassNotFoundException: org.springframework.web. servlet.Dispatche

Hitvz的博客 1万+

百万 Token 压力实测:1M Context 的真实能力边界在哪里?

本文揭示了长上下文模型的性能衰减规律:1M上下文存在"容量曲线"与"质量曲线"的分歧,512K是可靠拐点。通过MRCR测试发现,不同任务类型衰减差异显著——检索任务在512K后性能下降30.6%,而生成任务仅下降5%。研究提出三阶段补偿策略:三明治注入(首尾指令强化)、语义面包屑(位置标记)、引用检查(强制溯源),可将512K-1M区间的可用性提升20%。工程实践表明,中段区域(30-70%位置)是注意力薄弱区,需要特殊处理。最终建议:关键检索任务控制在512K内,关联推理任务可扩展至

liuzhupeng的专栏 338

spring整合RMI - Java远程方法调用

一. 开篇语 上一篇RMI - Java远程方法调用, 它使用的是JDK原生类进行操作, 本篇文章使用spring提供的API进行整合, 希望能给您带来帮助. 二. 核心API 1. 客户端: 客户端的核心是RmiProxyFactoryBean, 它包含两个属性serviceUrl(远程调用地址), serviceInterface(远程调用接口)

技术人生 2250

TMS_WebGMaps_1.9.8.0_Full_Source

TMS_WebGMaps_1.9.8.0_Full_Source 全源码 delphi cbuilder

SIMATIC S7-1200, S7-1500 PID 控制[手册]

SIMATIC S7-1200, S7-1500 PID 控制[手册]

Spring实现RMI远程方法调用

RMI(Remote Method Invocation,远程方法调用)它是一种机制,能够让在某个 Java 虚拟机上的对象调用另一个 Java 虚拟机中的对象上的方法。JVM 可以位于相同或不同计算机上,在多个 JVM 中,一个 JVM 可以调用存储在其它 JVM 的对象的方法。 实现RMI有两种方式,即通过Java和Spring,相比使用Java实现RMI远程方法调用,使用 Spring实现...

U2的博客 495

win10 跳过U8环境检测的IE WebControls.rar

win10 安装u8的时候 提示IE WebControls 不通过,这个工具可以欺骗u8的检查。 跳过U8环境检测的IE WebControls。提示导入失败后,重新检测通过。

使用Spring RMI调用远程方法

Spring有多种调用远程的方式,今天学习了一下远程方法调用(RMI)。 RMI需要服务端和客户端 我们先从服务器开始 我的代码结构 package rmi; public interface ServerRmiI { public String sayHi(String name); } package rmi; public class Ser

我的编程之路 6558

Data-Structures-and-Algorithm-Analysis-in-Java.pdf

作者: Weiss, Mark A. 出版社: Addison Wesley Data Structures and Algorithm Analysis in Java is an “advanced algorithms” book that fits between traditional CS2 and Algorithms Analysis courses. In the old ACM Curriculum Guidelines, this course was known as CS7. This text is for readers who want to learn good programming and algorithm analysis skills simultaneously so that they can develop such programs with the maximum amo...

RMI远程方法调用示例【基于Spring配置文件】

上篇博客,介绍了RMI远程方法调用示例,通过示例,可以总结到,其实,也就是被调用则发布服务,称谓服务端,主动调用则是调用服务,称谓客户端。           既然是远程调用,因此,服务器端要提供发布的标签,让别人能够找到你这个服务对象,比如webservice,服务端要发布成wsdl地址,客户端通过wsdl可以找到此服务对象。服务器一旦发布服务标签,客户端只要根据此即可。     所以无论

3615

Java RMI 远程方法调用 和 Spring 封装

Java RMI 的基本使用 RMI(remote method invocation,远程方法调用)Java 的 RPC 解决方法调用,用于不同 JVM 虚拟机的通信,这些虚拟机可以位于不同主机,或者同一个主机上面,由一个 JVM 上的对象调用另一个 JVM 上的对象的方法,是分布式系统通信的解决方案之一; 以下通过一个示例,来演示 RMI 远程调用方法的过程; 完整示

Al_assad的博客 638

Spring RMI调用远程方法

Spring有多种调用远程的方式,今天学习了一下远程方法调用(RMI)。 RMI需要服务端和客户端 我们先从服务器开始 我的代码结构 [java] view plaincopyprint? package rmi;    public interface ServerRmiI {        public String s

shixiaoguo90的专栏 511

Java远程方法调用(Remote Method Invocation,RMI);Dubbo、spring远程原理

Java远程方法调用(Remote Method Invocation,RMI) 一、什么是RMI 1、概念 RMI又叫做远程方法调用。在java中表示一台java虚拟机上的程序调用另外一台java虚拟机上的程序。QQ里面有一个远程控制别人电脑,其实就是基于这个原理。这一篇只是讲解一些基础的使用,如果深入进去,你也可以写一个远程控制器,去控制别人的电脑。 2、原理...

阿里渣渣java研发组-群主 753

spring整合RMI实现Java远程方法调用

使用Spring对RMI的支持,可以非常容易地构建你的分布式应用。 在服务端,可以通过Spring的org.springframework.remoting.rmi.RmiServiceExporter可以暴露你的服务; 在客户端,通过org.springframework.remoting.rmi.RmiProxyFactoryBean可以使用服务端暴露的服务,非常方便。 这种C/S模型的访

Achiberx 575

Spring Rmi远程方法调用 例子2

 一: 服务端  暴露服务 [java] view plaincopyprint? package com.xx.service;    /**  * 定义远程服务接口   * 1.可以不继承java.rmi.Remote接口  * 2.方法可以不抛出java.rmi.RemoteException异常  *   */  public interface ISayHe

shixiaoguo90的专栏 662

Spring使用RMI进行远程方法调用

(1)。我新建了三个项目,SpringRmiApi(存放提供者和消费者共有的xx,例如实体类以及服务接口等等)、SpringRmiService(服务提供者)、SpringRmiProvider(服务消费者) 以下是SpringRmiApi一些代码 1 package cn.coreqi.entities; 2 3 import java.io.Serializabl...

weixin_30652879的博客 59
上一篇: Java GC 日志分析
下一篇: 使用BufferedReader和BufferedWriter按行读写文件
feiyu8607
博客等级 码龄18年 26粉丝 51原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值