- Java RMI(Remote Method Invocation)远程方法调用
【1】定义:远程方法调用允许一个JVM的中的对象调用另一个JVM中对象。(客户端——服务器模型)
【2】优点:使用RMI,可以不用亲自写任何网络或者I/O代码。
【3】RMI将客户辅助对象称为stub(桩),将服务辅助对象称为skeleton(骨架)。
1.在远程方法调用中需要一个代理对象,作为身处不同地址空间的两个对象的中间人。
2.客户端调用服务器的某个方法时,实际上调用的是本地代理对象的方法,代理对象将信息(变量,方法名等)打包通过网络发给服务端的本地代理对象。
3.服务端的本地代理对象解析信息,传给服务端真正的对象,该对象通过这些信息,做出相应的动作,把返回信息传给服务端的代理对象,
4.服务端代理对象打包信息,回给客户端的代理对象。
5.客户端代理对象解析信息,发给客户端对象。
6.客户端对象得到结果,仿佛自己只和服务端对象在交流一样。
【1】在远程方法调用时,需要确定远程方法的变量和返回值必须是原语类型或者Serializable类型。
【2】序列化:就是将对象转换为字节序列。
反序列化就是相反的操作。
【3】原语:所谓原语,一般是指由若干条指令组成的程序段。
【4】如果使用原语类型,字符串和许多API内定义的类型(包括数组和集合)都不会有问题。如果传送自己定义的类,必须实现Serializable接口。
java5之后就不需要rmic了,但是可以了解下幕后处理的原理。
1.创建服务端接口
2.创建服务端实现
3.书写客户端代码
4.生成Stub和Skeleton
【注】:先cd到以上代码文件的目录,使用javac生成class文件
然后使用rmic命令生成stub。需要特别注意执行该命令的执行位置。
如:
【1】.java文件和.class文件都在/design/design-mode-demo/src/pattern/proxy/rmi目录下
【2】此时执行该命令前,需要cd到src目录下再执行 rmic -keep pattern.proxy.rmi.MyRemoteImpl
【3】不是rmic -keep MyRemoteImpl,直接执行这句会报错找不到MyRemoteImpl。
【4】因为.java和.class文件的包名都是package pattern.proxy.rmi,需要退到该目录的上一层(猜想)
5.启动rmiregistry
【注】:此时也需要退到src目录下,不然启动真正的服务时,会报错找不到stub
6.编译器中启动服务端和客户端(先启动服务端)
/design-mode-demo/src/pattern/proxy/rmi
定义:为另一个对象(服务端对象)提供一个替身或者占位符(代理对象)以控制对这个对象的访问。
【1】代理模式有许多变体,而这些变体几乎都和“控制访问”的做法有关。
远程代理控制访问远程对象。
虚拟代理控制访问创建开销大的资源
保护代理基于权限控制对资源的访问
【2】代码示例
/design-mode-demo/src/pattern/proxy/virtual
1.相似点:用一个对象包装真实对象,然后将调用委托给真实对象。
2.差异:意图不同
装饰者是增强对象的行为。
代理是控制对象的访问。
1.相似点:都是用一个对象挡在真实对象前面。
2.不同:适配器会改变目标对象的接口。代理需要实现和被代理者相同的接口。
- Java API 的代理(动态代理)
动态代理的动态是指:运行时才创建proxy类。
【1】如上图所示:java的动态代理的代理类包含两个类,Proxy和InvocationHandler
【2】Proxy由java产生,并且完整实现了subject接口。我们需要提供InvocationHandler类。Proxy上的任何方法调用都会传入该类。该类控制对RealSubject的访问。
【3】java会创建Proxy类,我们需要告诉Proxy类要干什么。此时代码不再是写在Proxy中,而是InvocationHandler中。
【4】InvocationHandler中的invoke方法用了反射的原理,可以知道proxy被调用 的是什么。
invoke(Object proxy, Method method, Object[] args)
Method是java 反射API的一部分,通过它的getName方法就可以知道proxy被调用的是什么方法。
代码示例:/design-mode-demo/src/pattern/proxy/protect
防火墙代理
智能引用代理
缓存代理
同步代理
复杂隐藏代理
写入时复制代理