代理模式的基本介绍
- 代理模式:为一个对象提供一个替身,以控制对这个对象的访问
- 被代理的对象可以是远程对象、创建开销大的对象或需要安全控制的对象(动态代理)
- 代理模式有不同的形式(比如 远程代理,静态代理,动态代理),都是为了控制与管理对象访问
举个例子: 远程对象的本地代表
远程代理:远程对象的本地代表,通过它可以把远程对象
当本地对象
来调用。
远程代理通过网络和真正的远程对象沟通信息。
涉及到一个核心的技术 RMI
啥是RMI ?
- RMI 指的是
远程方法调用
(Remote Method Invocation)。它是一种机制. - 能够让在某个 Java 虚拟 机上的对象调用
另一个 Java 虚拟机
中的对象上的方法。 - 使用 RMI 机制,一台计算机上的对象可以调用另外 一台计算机上的对象来获取远程数据。
- 用此方法调用的任何对象必须实现该远 程接口,
- 不同与
RPC(远程过程调用)
RMI 被设计成一种面向对象开发方式,更强大, 允许程序员使用远程对象来实现通信. - RMI 可以将底层的 socket 编程封装,简化操作。(如图)
开发步骤
- 制作远程接口:接口文件
- 远程接口的实现:Service 文件
- RMI服务端注册,开启服务
- RMI代理端通过RMI查询到服务端,建立联系,通过接口调用远程方法
代码示例:
远程被调用端需要实现Remote接口: 注意 这里我们都要本地端, 远程端, 都要拥有
这个接口.
//这是一个接口文件.该文件会给远程端和本地端是使用
trait MyRemote extends Remote{
//一个抽象方法
@throws(classOf[RemoteException])
def sayHello(): String //throws RemoteException
}
将即将要被远程代理调用的类注册到RMI机制
内部:
//这里就是实现了MyRemote trait
class MyRemoteImpl extends UnicastRemoteObject with MyRemote {
@throws(classOf[RemoteException])
override def sayHello(): String = {
"Hello World!~"
}
}
//这里我们完成对服务(sayHello)注册任务->对服务管理
object MyRemoteImpl {
def main(args: Array[String]): Unit = {
val service: MyRemote = new MyRemoteImpl()
//准备把服务绑定到9999端口【第一种注册方式】
//LocateRegistry.createRegistry(9999)
//Naming.rebind("RemoteHello", service)
//准备把服务绑定到9999端口【第二种注册方式】
Naming.rebind("rmi://127.0.0.1:9999/RemoteHello", service)
println("远程服务开启,在127.0.0.1 的 9999端口监听,服务名 RemoteHello")
}
}
本地直接调用
class MyRemoteClient {
def go() = {
val service = Naming.lookup("rmi://127.0.0.1:9999/RemoteHello").asInstanceOf[MyRemote]
val str = service.sayHello()
println("str = " + str)
}
}
object MyRemoteClient {
def main(args: Array[String]): Unit = {
new MyRemoteClient().go()
}
}
几种常见的代理模式介绍 — 几种变体
防火墙代理
内网通过代理穿透防火墙,实现对公网的访问。缓存代理
比如:当请求图片文件等资源时,先到缓存代理取,如果取到资源则 ok,如果取不到资源,再到公网或 者数据库取,然后缓存。静态代理
静态代理通常用于对原有业务逻辑的扩充。比如持有第二方包的某个类,并调用了其中的某些方法。比如记录日志、打印工作等。可以创建一个 代理类实现和第二方方法相同的方法,通过让代理类持有真实对象,调用代理类方法,来达到增加业 务逻辑的目的。Cglib代理
使用 cglib[Code Generation Library]实现动态代理,并不要求委托类必须实现接口,底层采用 asm 字节码生成框架生成代理类的字节码。同步代理
主要使用在多线程编程中,完成多线程间同步工作