Java RMI 指的是远程方法调用 (Remote Method Invocation)。它是一种机制,能够让在某个 Java 虚拟机上的对象调用另一个 Java 虚拟机中的对象上的方法。可以用此方法调用的任何对象必须实现该远程接口。
在spring整合Rmi中:
服务端使用了org.springframework.remoting.rmi.RmiServiceExporter
RmiServiceExporter把任何Spring管理的Bean输出成一个RMI服务。通过把Bean包装在一个适配器类中工作。适配器类被绑定到RMI注册表中,并且将请求代理给服务类。
客户端使用了org.springframework.remoting.rmi.RmiProxyFactoryBean
客户端的核心是RmiProxyFactoryBean,包含serviceURL属性和serviceInterface属性。 通过JRMP访问服务。 JRMP:Java remote method protocol,Java特有的,基于流的协议。
服务端代码(需要使用spring的jar包和日志相关jar包):
接口
package com.rmi;
/**
* 接口
* @author edgewalk
* @date 2017年6月11日
*/
public interface RmiServer {
public boolean test();
}
实现类
package com.rmi.impl;
import com.rmi.RmiServer;
/**
* 实现类
* @author edgewalk
* @date 2017年6月11日
*/
public class RmiServerImpl implements RmiServer {
@Override
public boolean test() {
System.out.println("服务端test方法执行了.....");
return true;
}
}
配置文件rmi-server.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN 2.5//EN" "file:/usr/local/tomcat_report/lib/spring-beans-2.0.dtd">
<beans>
<!-- 定义接口实现类-->
<bean id="rmiService" class="com.rmi.impl.RmiServerImpl"/>
<bean id="remoteRmiService" class="org.springframework.remoting.rmi.RmiServiceExporter">
<!-- service接口 -->
<property name="serviceInterface" value="com.rmi.RmiServer"/>
<!-- 调用Service -->
<property name="service" ref="rmiService" />
<!-- value值是提供给客户端调用 -->
<property name="serviceName" value="remoteService"/>
<!-- 注册端口 -->
<property name="registryPort" value="9400"/>
<!-- 服务端口 -->
<property name="servicePort" value="9401"/>
</bean>
</beans>
服务端启动类
package com.rmi;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
* 服务端启动类
* @author edgewalk
* @date 2017年6月11日
*/
public class MainServer {
public static void main(String[] args) {
System.out.println("rmi服务端启动...");
ApplicationContext ac = new ClassPathXmlApplicationContext("rmi-server.xml");
System.out.println("rmi服务端启动完成...");
}
}
客户端代码
接口
package com.rmi;
/**
* 在客户端使用服务端的接口文件
* @author edgewalk
* @date 2017年6月11日
*/
public interface RmiServer {
public boolean test();
}
socket连接工厂(可选配置)
package com.rmi;
import java.io.IOException;
import java.net.Socket;
import java.rmi.server.RMIClientSocketFactory;
/**
* 自定义的socket连接工厂
*
* @author edgewalk
* @date 2017年6月11日
*/
public class RMICustomClientSocketFactory implements RMIClientSocketFactory {
private int timeout = 1000; // 读超时时间
public void setTimeout(int timeout) {
this.timeout = timeout;
}
public Socket createSocket(String host, int port) throws IOException {
Socket socket = new Socket(host, port);
/**
* 调用setSoTimeout(int
* timeout)可以设置超时时间,如果到了超时时间仍没有数据,read会抛出一个SocketTimeoutException,
* 程序需要捕获这个异常,但是当前的socket连接仍然是有效的。
*/
socket.setSoTimeout(timeout);
return socket;
}
}
配置文件(rmi-server.xml)
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN 2.5//EN" "file:/usr/local/tomcat_report/lib/spring-beans-2.0.dtd">
<beans>
<!-- 自定一个SCOKECT连接,可配置读超时时间 -->
<bean id="rmiClientSocketFactory" class="com.rmi.RMICustomClientSocketFactory">
<property name="timeout" value="1000"></property>
</bean>
<!-- rmi远程调用 -->
<bean id="clientRmiService" class="org.springframework.remoting.rmi.RmiProxyFactoryBean">
<!-- rmiServer是调用服务端serviceName的value,rmiIp是服务端ip,rmiPort是服务端注册的端口 -->
<property name="serviceUrl" value="rmi://127.0.0.1:9400/remoteService" />
<!-- service接口 -->
<property name="serviceInterface" value="com.rmi.RmiServer" />
<!-- 客户端自动重连 -->
<!-- lookupStubOnStartup : false表示,不在容器启动的时候创建与Server端的连接; -->
<property name="lookupStubOnStartup" value="true" />
<!-- refreshStubOnConnectFailure : 这个属性是表示是否连接出错时自动重连; -->
<property name="refreshStubOnConnectFailure" value="true" />
<!-- registryClientSocketFactory : 这个是客户端与服务端创建SOCKECT的一个工厂。 -->
<property name="registryClientSocketFactory" ref="rmiClientSocketFactory" />
</bean>
</beans>
测试类
package com.rmi.client;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.rmi.RmiServer;
/**
* 客户端测试调用服务端程序
* @author edgewalk
* @date 2017年6月11日
*/
public class TestRmi {
public static void main(String[] arg) {
System.out.println("rmi客户端开始调用...");
ApplicationContext ctx = new ClassPathXmlApplicationContext("rmi-client.xml");
RmiServer rmi=(RmiServer)ctx.getBean("clientRmiService");
//rmi.test();
System.out.println("rmi客户端调用完成...");
}
}
输出结果
服务端
rmi服务端启动...
log4j:WARN No appenders could be found for logger (org.springframework.context.support.ClassPathXmlApplicationContext).
log4j:WARN Please initialize the log4j system properly.
rmi服务端启动完成...
服务端test方法执行了.....
客户端
rmi客户端开始调用...
log4j:WARN No appenders could be found for logger (org.springframework.context.support.ClassPathXmlApplicationContext).
log4j:WARN Please initialize the log4j system properly.
rmi客户端调用完成...
时间: 2024-10-22 21:28:06