RMI demo
package org.example.rmi.test;
import java.rmi.*;
public interface MyRemote extends Remote {
public String sayHello() throws RemoteException;
}
package org.example.rmi.test;
import java.rmi.Naming;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.server.UnicastRemoteObject;
/**
* 1:制作远程接口 定义接口继承remote, 声明所有方法抛出RemoteException 变量以及返回值属于原语类型或可序列化
* 2:制作远程实现实现接口,成为远程服务对象简单继承UnicastRemoteObject
* UnicastRemoteObject构造器会抛出异常,所以实现类提供构造抛出异常
* 实例化后,注册Naming.rebind,RMI注册的是stub(需要提前启动RMI Registry)
* 3:产生stub和skeleton:rmic MyRemoteImpl
* 4:执行:rmiregistry
* 5:启动服务:java MyRemoteImpl
* 6:客户根据stub对象调用代理方法,需要stub类,之前利用rmic产生的
* MyRemote service = (MyRemote)Naming.lookup("rmi://127.0.0.1/RemoteHello");
* 工作方式 从RMIregistry中找Naming.lookup("rmi://127.0.0.1/RemoteHello"); 返回stub对象调用stub方法,获取结果
*
* 扩展获取stub方法:动态类下载,本地下不到从url下
*/
public class MyRemoteImpl extends UnicastRemoteObject implements MyRemote {
private static final long serialVersionUID = 1L;
protected MyRemoteImpl() throws RemoteException {
}
// 不需要声明异常
public String sayHello() throws RemoteException {
return "hello";
}
public static void main(String[] args) {
try {
MyRemote service = new MyRemoteImpl();
//一定要注册表创建端口
LocateRegistry.createRegistry(6600);
// 服务名,注册实例
//Naming.rebind("rmi://192.168.30.1:6600/MyRemote", service);
Naming.rebind("rmi://192.168.2.106:6600/MyRemote", service);
/*
Context namingContext = new InitialContext();
namingContext.rebind("//127.0.0.1:6600/MyRemote",
service);*/
} catch (Exception e) {
e.printStackTrace();
}
}
}
package org.example.rmi.test;
import java.rmi.Naming;
public class MyRemoteClient {
public static void main(String[] args) {
new MyRemoteClient().go();
}
private void go() {
try {
MyRemote service = (MyRemote) Naming
.lookup("rmi://127.0.0.1:6600/MyRemote");
String s = service.sayHello();
System.out.println(s);
} catch (Exception e) {
e.printStackTrace();
}
}
}
spring整合RMI
service端
package org.example.rmi.spring;
import org.example.rmi.test.MyRemote;
import java.rmi.Naming;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.server.UnicastRemoteObject;
public class MyRemoteServiceImpl implements MyRemoteService {
@Override
public String sayHello() {
return "hello";
}
}
package org.example.rmi.spring;
import java.rmi.Remote;
import java.rmi.RemoteException;
public interface MyRemoteService {
public String sayHello();
}
package org.example.rmi.spring;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
* Hello world!
*/
public class ServiceApp {
public static void main(String[] args) {
ApplicationContext bf2 = new ClassPathXmlApplicationContext("rmi/rmi-service.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:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<bean id="myRemoteService" class="org.example.rmi.spring.MyRemoteServiceImpl"/>
<bean name="rmiServiceExporter" class="org.springframework.remoting.rmi.RmiServiceExporter">
<!--服务类-->
<property name="service" ref="myRemoteService"></property>
<!--服务接口-->
<property name="serviceInterface" value="org.example.rmi.spring.MyRemoteService"></property>
<!--服务名-->
<property name="serviceName" value="hello"></property>
<!--暴露端口-->
<property name="registryPort" value="6600"></property>
</bean>
</beans>
client端
<?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:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<bean name="client" class="org.springframework.remoting.rmi.RmiProxyFactoryBean">
<property name="serviceUrl" value="rmi://127.0.0.1:6600/hello"></property>
<property name="serviceInterface" value="org.example.rmi.spring.MyRemoteService"></property>
</bean>
</beans>
package org.example.rmi.spring;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
* Hello world!
*/
public class ClientApp {
public static void main(String[] args) {
ApplicationContext bf2 = new ClassPathXmlApplicationContext("rmi/rmi-client.xml");
MyRemoteService bean = bf2.getBean("client", MyRemoteService.class);
System.out.println(bean.sayHello());
}
}
服务端解析
查看RmiServiceExporter接口继承层次
可以看到分别继承了
InitializingBean:初始化时调用
DisposableBean:销毁时调用
BeanClassLoaderAware:注入类加载器
绑定,注册
查看初始化调用方法
@Override
public void afterPropertiesSet() throws RemoteException {
prepare();
}
/*
验证
处理用户自定义4个属性
确定使用的RMI-registry
初始化以及缓存导出的对象
导出RMI对象
绑定服务名到RMI object
*/
public void prepare() throws RemoteException {
//验证service
checkService();
if (this.serviceName == null) {
throw new IllegalArgumentException("Property 'serviceName' is required");
}
// Check socket factories for exported object.
//导出远程对象
//如果clientSocketFactory实现了RMIServerSocketFactory
// 则覆盖serverSocketFactory采用clientSocketFactory代替
if (this.clientSocketFactory instanceof RMIServerSocketFactory) {
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");
}
// Check socket factories for RMI registry.
//用于主机与RMI服务器之间连接
//如果registryClientSocketFactory实现了RMIServerSocketFactory
//则覆盖registryServerSocketFactory采用registryClientSocketFactory代替
if (this.registryClientSocketFactory instanceof RMIServerSocketFactory) {
this.registryServerSocketFactory = (RMIServerSocketFactory) this.registryClientSocketFactory;
}
//registryServerSocketFactory不为空,registryClientSocketFactory为空则异常
if (this.registryClientSocketFactory == null && this.registryServerSocketFactory != null) {
throw new IllegalArgumentException(
"RMIServerSocketFactory without RMIClientSocketFactory for registry not supported");
}
this.createdRegistry = false;
// Determine RMI registry to use.
//确定使用的RMI-registry
if (this.registry == null) {
this.registry = getRegistry(this.registryHost, this.registryPort,
this.registryClientSocketFactory, this.registryServerSocketFactory);
this.createdRegistry = true;
}
// Initialize and cache exported 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:进行远程对象调用的客户端socket工厂
serverSocketFactory:接收远程对象调用的服务端socket工厂
*/
UnicastRemoteObject.exportObject(
this.exportedObject, this.servicePort, this.clientSocketFactory, this.serverSocketFactory);
}
else {
//导出RMI对象,以便能接受特定端口调用
UnicastRemoteObject.exportObject(this.exportedObject, this.servicePort);
}
// Bind RMI object to registry.
try {
if (this.replaceExistingBinding) {
this.registry.rebind(this.serviceName, this.exportedObject);
}
else {
//绑定服务名到 RMI object
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;
}
}
protected Registry getRegistry(String registryHost, int registryPort,
@Nullable RMIClientSocketFactory clientSocketFactory, @Nullable RMIServerSocketFactory serverSocketFactory)
throws RemoteException {
if (registryHost != null) {
// Host explicitly specified: only lookup possible.
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) {
logger.debug("Creating new RMI registry");
//使用clientSocketFactory新建
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 {
// Retrieve existing registry.
//复用
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 {
//直接根据端口调用
return getRegistry(registryPort);
}
}
/*
采用自定义实现Remote类调用
采用spring封装RmiInvocationWrapper然后经过代理对象调用
*/
protected Remote getObjectToExport() {
// determine remote object
//如果配置的service属性继承了Remote接口且没配置serviceInterface属性
if (getService() instanceof Remote &&
(getServiceInterface() == null || Remote.class.isAssignableFrom(getServiceInterface()))) {
// conventional RMI service
//直接使用service作为处理类
return (Remote) getService();
}
else {
// RMI invoker
if (logger.isDebugEnabled()) {
logger.debug("RMI service [" + getService() + "] is an RMI invoker");
}
//对service的代理类和当前类RMIServiceExporter封装
//当调用的时候,会执行invoke,invoke调用代理方法,代理方法调用service,之所以添加代理是为了更高的灵活性
return new RmiInvocationWrapper(getProxyForService(), this);
}
}
protected Object getProxyForService() {
//验证service
checkService();
//验证service接口
checkServiceInterface();
//使用JDK代理
ProxyFactory proxyFactory = new ProxyFactory();
//添加代理接口
proxyFactory.addInterface(getServiceInterface());
if (this.registerTraceInterceptor != null ? this.registerTraceInterceptor : this.interceptors == null) {
//加入代理的拦截器
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());
}
调用
RmiInvocationWrapper.invoke
@Override
@Nullable
public Object invoke(RemoteInvocation invocation)
throws RemoteException, NoSuchMethodException, IllegalAccessException, InvocationTargetException {
return this.rmiExporter.invoke(invocation, this.wrappedObject);
}
@Override
protected Object invoke(RemoteInvocation invocation, Object targetObject)
throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
return super.invoke(invocation, targetObject);
}
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;
}
}
@Override
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 Object invoke(Object targetObject)
throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
//根据方法名获得代理中对应方法
Method method = targetObject.getClass().getMethod(this.methodName, this.parameterTypes);
//执行代理方法
return method.invoke(targetObject, this.arguments);
}
客户端解析
@Override
public void afterPropertiesSet() {
super.afterPropertiesSet();
Class<?> ifc = getServiceInterface();
Assert.notNull(ifc, "Property 'serviceInterface' is required");
//使用当前类作为代理类拦截器
this.serviceProxy = new ProxyFactory(ifc, this).getProxy(getBeanClassLoader());
}
@Override
public void afterPropertiesSet() {
super.afterPropertiesSet();
prepare();
}
public void afterPropertiesSet() {
if (getServiceUrl() == null) {
throw new IllegalArgumentException("Property 'serviceUrl' is required");
}
}
public void prepare() throws RemoteLookupFailureException {
// Cache RMI stub on initialization?
//如果配置了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;
}
}
}
protected Remote lookupStub() throws RemoteLookupFailureException {
try {
Remote stub = null;
if (this.registryClientSocketFactory != null) {
// RMIClientSocketFactory specified for registry access.
// Unfortunately, due to RMI API limitations, this means
// that we need to parse the RMI URL ourselves and perform
// straight LocateRegistry.getRegistry/Registry.lookup calls.
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);
}
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);
}
}
执行
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;
}
}
}
/*
如果是RmiInvocationHandler类型,采用spring方式执行
不是,则采用反射执行
*/
protected Object doInvoke(MethodInvocation invocation, Remote stub) throws Throwable {
//如果是RmiInvocationHandler类型,则spring管理,则采用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 {
// traditional RMI stub
try {
//如果是其他第三方的插件生成的remote,则直接反射调用
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;
}
}
}
}
由于继承了FactoryBean,所以最终调用getObject获取对象
@Override
public Object getObject() {
return this.serviceProxy;
}