需要实现remote接口
- 下面我来演示一个 规范的 开发RMI接口的方法规范
package com.czxy.mapreduce.demo01;
import java.rmi.RemoteException;
import java.rmi.Remote;
/**
* @author 550894211@qq.com
* @version v 1.0
* @date 2019/12/31
* 远程过程调用必须声明为 public
* 远程过程必须继承自 java.rmi.Remote
*/
public interface RMIQueryStatus extends Remote {
/**
* 远程接口中的函数必须将java.rmi.RemoteException声明于其throws子句中
* */
RMIQueryStatus getStatus() throws RemoteException;
}
如何获得本地存根对象
客户端如果要访问一个远程对象,必须获得一个本地的存根对象,java引用了RMI远程对象注册点(registry)解决了这个问题
注意JDK 5.0版本以前,用户需奏通过rmic工具生成客户端存根,在夏.早的Java版本
JDK1.1中,服务専膏兼也必須由rmic产生。
从包和类名可以知道,java.lang.reflect.Proxy和Java反射有关,同时也和代理模式有关.
代理(Proxy)在《现代汉语词典》里的解释是:受当事人委托,代表他进行某种活动,如
贸易、诉讼、纳税、签订合同等。如果把这个解释应用到面向对象领域,应垓是:代理对象,
代表另一个对象(目标对象,Target),执行相关活动。也就是说,在实际应用中使用代理对
象作为中介,代替目标对象.
代理对象的两个重要任务
- 实现代理接口
- 调用转发
上面两点,缺一不可
proxy接口
package com.czxy.mapreduce.demo01;
import sun.reflect.CallerSensitive;
import sun.reflect.Reflection;
import java.lang.reflect.Proxy;
/**
* @author 550894211@qq.com
* @version v 1.0
* @date 2019/12/31
*/
public class demo {
/**
*返回代理类的{@code java.lang.Class}对象
*给定一个类加载器和一个接口数组。代理类
*将由指定的类加载器定义并实现
*所有提供的接口。如果有任何给定的接口
*是非公开的,代理类将是非公开的。如果是代理类
*对于接口的相同排列,已经由
*类加载器,然后将返回现有的代理类;除此以外,
*这些接口的代理类将动态生成
*并由类加载器定义。
*
* <p>可能对参数有一些限制
*传递给{@code Proxy.getProxyClass}:
*
* <ul>
* <li>所有{@code Class}对象
* {@code interfaces}数组必须表示接口,而不是
*类或原始类型。
*
* <li> {@ code interfaces}数组中不能有两个元素
* 指相同的{@code Class}对象。
*
* <li>所有接口类型必须通过名称按名称可见
*指定的类加载器。换句话说,对于类加载器
* {@code cl}和每个接口{@code i},以下
*表达式必须为真:
* <pre>
* Class.forName(i.getName(),false,cl)==我
* </ pre>
*
* <li>所有非公共接口必须位于同一程序包中;
*否则,代理类将无法
*实现所有接口,而不管它是什么包
*定义于。
*
* <li>对于指定接口的任何成员方法集
*具有相同签名:
* <ul>
* <li>如果任何方法的返回类型是原始类型
*类型或无效,则所有方法必须具有相同的
*返回类型。
* <li>否则,方法之一必须具有返回类型,该返回类型应为
*可分配给其余部分的所有返回类型
* 方法。
* </ ul>
*
* <li>生成的代理类不得超过任何限制
*在虚拟机的类上。例如,虚拟机可能会限制
*一个类可以实现的接口数量为65535;在
*在这种情况下,{@ code interfaces}数组的大小不得
*超过65535。
* </ ul>
*
* <p>如果违反了任何这些限制,
* {@code Proxy.getProxyClass}将抛出一个
* {@code IllegalArgumentException}。如果{@code接口}
*数组参数或其任何元素为{@code null},
* {@code NullPointerException}将被抛出。
*
* <p>请注意,指定代理接口的顺序为
*重大:具有相同组合的两个代理类请求
*接口,但顺序不同将导致两个不同
*代理类。
*
* @param loader类加载器定义代理类
* @param interfaces代理类的接口列表
*实施
* @返回在指定的类加载器中定义的代理类
*并实现指定的接口
* @throws IllegalArgumentException如果对
*可能传递给{@code getProxyClass}的参数
*被违反
* @throws SecurityException如果存在安全管理器<em> s </ em>
*并且满足以下任何条件:
* <ul>
* <li>给定的{@code loader}为{@code null},
*调用者的类加载器不是{@code null},并且
*调用{@link SecurityManager#checkPermission
* s.checkPermission}与
* {@code RuntimePermission(“ getClassLoader”)}权限
*拒绝访问。</ li>
* <li>每个代理接口{@code intf},
*调用者的类加载器与或
* {@code intf}的类加载器的祖先,并且
*调用{@link SecurityManager#checkPackageAccess
* s.checkPackageAccess()}拒绝访问{@code intf}。</ li>
* </ ul>
*如果{@code interfaces}数组,则抛出NullPointerException
*参数或其任何元素均为{@code null}
*/
//获取代理类的class对象
@CallerSensitive
public static Class<?> getProxyClass(ClassLoader loader,
Class<?>... interfaces)
throws IllegalArgumentException
{
final Class<?>[] intfs = interfaces.clone();
final SecurityManager sm = System.getSecurityManager();
if (sm != null) {
checkProxyAccess(Reflection.getCallerClass(), loader, intfs);
}
return getProxyClass0(loader, intfs);
}
}
调用转发 java.lang.reflect.Invocationhandeler
这个接口中只有一个方法
/**
*
* @param proxy 代理对象本身
* @param method 调用的代理对象上的方法
* @param args 传递给该方法的参数
* @return 结果
* @throws Throwable
*/
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable;