一、简介
1、基本介绍
1. 代理模式:为一个对象提供一个替身,以控制对这个对象的访问;
2. 被代理的对象可以是远程对象、创建开销大的对象或需要安全控制的对象;
3. 代理模式有不同的形式(比如 远程代理,静态代理,动态代理),都是为了控制与管理对象访问。
2、提出需求
糖果机项目,具体要求如下:
1. 某公司需要将销售糖果的糖果机放置到本地(本地监控)和外地(远程监控),进行糖果销售;
2. 给糖果机插入硬币,转动手柄,这样就可以购买糖果;
3. 可以监控糖果机的状态和销售情况。
3、完成监控本地糖果机
对本地糖果机的状态和销售情况进行监控,相对比较简单,代码实现该功能。
1. 代码结构图
2. 代码实现
=================================trait State=================================
package com.lj.akka.proxymode.locally
trait State {
def insertCoin() // 插入硬币
def returnCoin() // 退回硬币
def turnCrank() // 转动手柄
def printState() // 输出状态
def getStateName(): String // 返回状态的名字
def dispense() // 分配状态,比如:卖出一块糖后,就看看当前糖果机应该进入哪个状态.
}
=================================class CandyMachine=================================
package com.lj.akka.proxymode.locally
class CandyMachine {
private var soldOutState: State = _ // 售空状态
private var onReadyState: State = _ // 准备待售状态
private var hasCoin: State = _ // 投入硬币状态
private var soldState: State = _ // 正在售出状态
private var winnerState: State = _ // 奖励状态
private var location: String = _ // 糖果机位置
private var state: State = _ // 状态
private var count: Int = _ // Candy数量
// 辅助构造器
def this(location: String, count: Int) {
this
this.location = location
this.count = count
this.soldOutState = new SoldOutState(this)
this.onReadyState = new OnReadyState(this)
this.hasCoin = new HasCoin(this)
this.soldState = new SoldState(this)
this.winnerState = new WinnerState(this)
if (count > 0) {
state = onReadyState
} else {
state = soldOutState
}
}
def insertCoin() = {
state.insertCoin()
}
def returnCoin(): Unit = {
state.returnCoin()
}
def turnCrank(): Unit = {
state.turnCrank()
state.dispense()
}
def releaseCandy(): Unit = {
if (count > 0) {
count -= 1
println("A Candy Rolling Out!")
}
}
def _soldOutState: State = soldOutState
def _soldOutState_=(value: State): Unit = {
soldOutState = value
}
def _onReadyState: State = onReadyState
def _onReadyState_=(value: State): Unit = {
onReadyState = value
}
def _hasCoin: State = hasCoin
def _hasCoin_=(value: State): Unit = {
hasCoin = value
}
def _soldState: State = soldState
def _soldState_=(value: State): Unit = {
soldState = value
}
def _winnerState: State = winnerState
def _winnerState_=(value: State): Unit = {
winnerState = value
}
def _location: String = location
def _location_=(value: String): Unit = {
location = value
}
def _state: State = state
def _state_=(value: State): Unit = {
state = value
}
def _count: Int = count
def _count_=(value: Int): Unit = {
count = value
}
}
=============================class SoldOutState extends State=============================
package com.lj.akka.proxymode.locally
class SoldOutState extends State {
//说明:@transient注解将字段标记为瞬态的,即表示一个域不是该对象串行化的一部分
@transient private var candyMachine: CandyMachine = _
def this(candyMachine: CandyMachine) {
this
this.candyMachine = candyMachine
}
override def insertCoin(): Unit = {
println("Candy已经售空,禁止投入硬币购买糖果.")
}
override def returnCoin(): Unit = {
println("Candy Machine 还没有投入硬币,没有要返还的硬币.")
}
override def turnCrank(): Unit = {
println("Candy已经售空,转动手柄无任何效果.")
}
override def printState(): Unit = {
println("Candy已经售空.")
}
override def getStateName(): String = {
"Candy Sold Out State."
}
override def dispense(): Unit = {
}
}
=============================class OnReadyState extends State=============================
package com.lj.akka.proxymode.locally
class OnReadyState extends State {
@transient private var candyMachine: CandyMachine = _
def this(candyMachine: CandyMachine) {
this
this.candyMachine = candyMachine
}
override def insertCoin(): Unit = {
println("投入硬币成功,接下来请转动手柄(turn crank)..")
// 设置Candy Machine为有硬币的状态
this.candyMachine._state_=(candyMachine._hasCoin)
}
override def returnCoin(): Unit = {
println("你还没有投入硬币,没有硬币需要退回..")
}
override def turnCrank(): Unit = {
println("请投入硬币购买Candy..")
// 此时就不需要出Candy
this.candyMachine._state_=(candyMachine._soldState)
}
override def printState(): Unit = {
println("On Ready State")
}
override def getStateName(): String = {
"On Ready State.."
}
override def dispense(): Unit = {
// 出一个糖果
candyMachine.releaseCandy()
// 检查Candy数量
if (candyMachine._count == 0) {
candyMachine._state_=(candyMachine._soldOutState)
} else {
candyMachine._state_=(candyMachine._onReadyState)
}
}
}
=============================class HasCoin extends State=============================
package com.lj.akka.proxymode.locally
class HasCoin extends State {
private val random = new java.util.Random()
@transient private var candyMachine: CandyMachine = _
def this(candyMachine: CandyMachine) {
this
this.candyMachine = candyMachine
}
override def insertCoin(): Unit = {
println("你已经投入了硬币,无需再次投入硬币......")
}
override def returnCoin(): Unit = {
println("投入的硬币已退回,欢迎下次光临......")
candyMachine._state_=(candyMachine._onReadyState)
}
override def turnCrank(): Unit = {
println("手柄正在转动,等待出Candy......")
// 奖励机制
val num = random.nextInt(10)
if (num == 0) {
candyMachine._state_=(candyMachine._winnerState)
} else {
candyMachine._state_=(candyMachine._onReadyState)
}
}
override def printState(): Unit = {
println("Has Coin......")
}
override def getStateName(): String = {
"Has Coin......"
}
override def dispense(): Unit = {}
}
============================class SoldState extends State============================
package com.lj.akka.proxymode.locally
class SoldState extends State {
@transient private var candyMachine: CandyMachine = _
def this(candyMachine: CandyMachine) {
this
this.candyMachine = candyMachine
}
override def insertCoin(): Unit = {
println("等待投入硬币,Candy Machine正在出Candy....")
}
override def returnCoin(): Unit = {
println("目前正在出Candy,无法退出硬币....")
}
override def turnCrank(): Unit = {
println("Candy Machine正在出Candy,不能转动手柄....")
}
override def printState(): Unit = {
println("Sold State...")
}
override def getStateName(): String = {
"Sold State..."
}
// 这里不做任何操作,不出糖果
override def dispense(): Unit = {}
}
=============================class WinnerState extends State=============================
package com.lj.akka.proxymode.locally
class WinnerState extends State {
@transient private var candyMachine: CandyMachine = _
def this(candyMachine: CandyMachine) {
this
this.candyMachine = candyMachine
}
override def insertCoin(): Unit = {
println("Candy Machine正在出Candy,你不能投入硬币....")
}
override def returnCoin(): Unit = {
println("Candy Machine正在出Candy,不能退出硬币.....")
}
override def turnCrank(): Unit = {
println("Candy Machine正在出Candy,不能转动手柄.....")
}
override def printState(): Unit = {
println("Winner State.....")
}
override def getStateName(): String = {
"Winner State....."
}
override def dispense(): Unit = {
// 出一个Candy
this.candyMachine.releaseCandy()
if (candyMachine._count == 0) {
candyMachine._state_=(candyMachine._soldOutState)
} else {
println("恭喜你,再次获得一个Candy的奖励")
candyMachine.releaseCandy()
if (candyMachine._count > 0) {
candyMachine._state_=(candyMachine._onReadyState)
} else {
candyMachine._state_=(candyMachine._soldOutState)
}
}
}
}
=================================class Monitor=================================
package com.lj.akka.proxymode.locally
import scala.collection.mutable.ListBuffer
class Monitor {
private val candyMachines: ListBuffer[CandyMachine] = ListBuffer()
// add candy machine
def addCandyMachine(candyMachine: CandyMachine): Unit = {
candyMachines.append(candyMachine)
}
def report(): Unit = {
for (ele <- candyMachines) {
println("----------------------------------------")
println("Machine local:" + ele._location)
println("Candy还剩余数量:" + ele._count)
println("Candy Machine State:" + ele._state.getStateName())
}
}
}
=================================object Test=================================
package com.lj.akka.proxymode
import com.lj.akka.proxymode.locally.{CandyMachine, Monitor}
object Test {
def main(args: Array[String]): Unit = {
val monitor = new Monitor()
var candyMachine = new CandyMachine("上海-徐家汇001", 30)
monitor.addCandyMachine(candyMachine)
candyMachine = new CandyMachine("上海-浦东001", 1)
candyMachine.insertCoin()
candyMachine.turnCrank()
monitor.addCandyMachine(candyMachine)
monitor.report()
}
}
=========================================运行结果=========================================
投入硬币成功,接下来请转动手柄(turn crank)..
手柄正在转动,等待出Candy......
A Candy Rolling Out!
----------------------------------------
Machine local:上海-徐家汇001
Candy还剩余数量:30
Candy Machine State:On Ready State..
----------------------------------------
Machine local:上海-浦东001
Candy还剩余数量:8
Candy Machine State:On Ready State..
=========================================运行结果=========================================
二、完成监控远程糖果机
1、对远程糖果机的状态和销售情况进行监控,相对麻烦些,我们先分析一下
1. 方式1:因为远程糖果机不在本地,比如在另外的城市,国家,这时可以使用socket编程来进行网络编程
控制(缺点:麻烦);
2. 方案2:在远程放置web服务器,通过web编程来实现远程监控;
3. 方案3:使用RMI(Remote Method Invocation)远程方法调用来完成对远程糖果机的监控,因为RMI将socket
的底层封装起来,对外提供调用方法接口即可,这样比较简单,这样我们就可以实现远程代理模式开发。
2、远程代理模式监控方案
远程代理:远程对象的本地代表,通过它可以把远程对象当本地对象来调用,远程代理通过网络和真正的远程
对象沟通信息。(如下图)
三、Java RMI实现远程代理
1、简介
RMI指的是远程方法调用 (Remote Method Invocation)。它是一种机制,能够让在某个Java虚拟机上的对象调用
另一个Java虚拟机中的对象上的方法。可以用此方法调用的任何对象必须实现该远程接口,RMI可以将底层的socket
编程封装,简化操作。(如下图)
2、介绍
1. RMI远程方法调用是计算机之间通过网络实现对象调用的一种通讯机制;
2. 使用RMI机制,一台计算机上的对象可以调用另外 一台计算机上的对象来获取远程数据;
3. RMI被设计成一种面向对象开发方式,允许程序员使用远程对象来实现通信。
3、Java RMI的开发应用案例-说明
请编写一个JavaRMI的案例,代理端(客户端)可以通过rmi远程调用 远程端注册的一个服务的sayHello的方法,并且返回结果。
4、Java RMI的开发应用案例-开发步骤
1. 制作远程接口:接口文件;
2. 远程接口的实现:Service文件;
3. RMI服务端注册,开启服务;
4. RMI代理端通过RMI查询到服务端,建立联系,通过接口调用远程方法。
5、Java RMI的开发应用案例-程序框架
6、RMI代码实现
代码结构:
示例代码:
============================trait MyRemote extends Remote============================
package com.lj.akka.rmi
import java.rmi.{Remote, RemoteException}
// 代理端(客户端)共用的接口文件
trait MyRemote extends Remote {
@throws(classOf[RemoteException])
def sayHello(): String
}
================class MyRemoteImpl extends UnicastRemoteObject with MyRemote================
package com.lj.akka.rmi
import java.rmi.registry.LocateRegistry
import java.rmi.server.UnicastRemoteObject
import java.rmi.{Naming, RemoteException}
class MyRemoteImpl extends UnicastRemoteObject with MyRemote {
@throws(classOf[RemoteException])
override def sayHello(): String = {
"Service sayHello() exec..."
}
}
object MyRemoteImplService {
def main(args: Array[String]): Unit = {
val service: MyRemote = new MyRemoteImpl()
// 把服务绑定到端口13331上
// 两种写法,根据系统的支持
LocateRegistry.createRegistry(13331)
// Naming.rebind("RemoteHello", service)
Naming.rebind("rmi://127.0.0.1:13331/RemoteHello", service)
println("远程服务已开启,在127.0.0.1的13331端口监听,服务名:RemoteHello")
}
}
============================class MyRemoteClient============================
package com.lj.akka.rmi
import java.rmi.Naming
class MyRemoteClient {
def go(): Unit = {
val service = Naming.lookup("rmi://127.0.0.1:13331/RemoteHello").asInstanceOf[MyRemote]
// 设置代理调用远程的方法
val service_def = service.sayHello()
println("res:" + service_def)
}
}
object MyRemoteClient {
def main(args: Array[String]): Unit = {
val client = new MyRemoteClient()
client.go()
}
}
四、使用远程代理模式完成远程糖果机监控
1、类结构图
2、功能代码实现
代码结构图:
说明:我的客户端直接使用了server的类和接口,在实际开发中,需要给客户端/代理端拷贝一份。
示例代码:
====================trait CandyMachineRemote extends Remote====================
package com.lj.akka.proxymode.remotecandymachine.server
import java.rmi.{Remote, RemoteException}
trait CandyMachineRemote extends Remote {
@throws(classOf[RemoteException])
def getLocation(): String // 获取Candy Machine 的位置
@throws(classOf[RemoteException])
def getCount(): Int // 获取Candy数量
@throws(classOf[RemoteException])
def setState(state: State) // 设置Candy Machine 的状态
@throws(classOf[RemoteException])
def getState(): State // 获取Candy Machine 的状态
}
====================trait State extends Serializable====================
package com.lj.akka.proxymode.remotecandymachine.server
//因为需要在网络传输,因此需要继承Serializable,即序列化
trait State extends Serializable {
def insertCoin() // 投入硬币
def returnCoin() // 退回硬币
def turnCrank() // 转动手柄
def printState() // 输出当前状态
def getStateName(): String // 返回当前状态
def dispense() // 分配糖果
}
===========class CandyMachine extends UnicastRemoteObject with CandyMachineRemote==========
package com.lj.akka.proxymode.remotecandymachine.server
import java.rmi.RemoteException
import java.rmi.server.UnicastRemoteObject
class CandyMachine extends UnicastRemoteObject with CandyMachineRemote {
private var mSoldOutState: State = _
private var mOnReadyState: State = _
private var mHasCoinState: State = _
private var mSoldState: State = _
private var mWinnerState: State = _
private var state: State = _
private var location: String = _
private var count: Int = _
@throws(classOf[RemoteException])
def this(location: String, count: Int) {
this
this.location = location
this.count = count
this.mSoldOutState = new SoldOut(this)
this.mOnReadyState = new OnReady(this)
this.mHasCoinState = new HasCoin(this)
this.mSoldState = new Sold(this)
this.mWinnerState = new WinnerState(this)
if (count > 0) {
this.state = mOnReadyState
} else {
this.state = mSoldOutState
}
}
override def getLocation(): String = location
override def getCount(): Int = this.count
override def setState(state: State) = {
this.state = state
}
override def getState()= {
this.state
}
def insertCoin(): Unit = { // 投入硬币
state.insertCoin()
}
def returnCoin(): Unit = { // 退回硬币
state.returnCoin()
}
def turnCrank(): Unit = { // 转动手柄
state.turnCrank()
state.dispense()
}
def releaseCandy(): Unit = {
if (count > 0) {
count -= 1
println("A Candy Rolling Out!")
}
}
def _mSoldOutState: State = mSoldOutState
def _mSoldOutState_=(value: State): Unit = {
mSoldOutState = value
}
def _mOnReadyState: State = mOnReadyState
def _mOnReadyState_=(value: State): Unit = {
mOnReadyState = value
}
def _mHasCoinState: State = mHasCoinState
def _mHasCoinState_=(value: State): Unit = {
mHasCoinState = value
}
def _mSoldState: State = mSoldState
def _mSoldState_=(value: State): Unit = {
mSoldState = value
}
def _mWinnerState: State = mWinnerState
def _mWinnerState_=(value: State): Unit = {
mWinnerState = value
}
}
====================class OnReady extends State====================
package com.lj.akka.proxymode.remotecandymachine.server
class OnReady extends State {
@transient private var candyMachine: CandyMachine = _
def this(candyMachine: CandyMachine) {
this
this.candyMachine = candyMachine
}
override def insertCoin(): Unit = {
println("投入硬币成功,接下来请转动手柄(turn crank)..")
// 设置Candy Machine为有硬币的状态
this.candyMachine.setState(candyMachine._mHasCoinState)
}
override def returnCoin(): Unit = {
println("你还没有投入硬币,没有硬币需要退回..")
}
override def turnCrank(): Unit = {
println("请投入硬币购买Candy..")
// 此时就不需要出Candy
this.candyMachine.setState(candyMachine._mSoldState)
}
override def printState(): Unit = {
println("On Ready State")
}
override def getStateName(): String = {
"On Ready State.."
}
override def dispense(): Unit = {
// 出一个糖果
candyMachine.releaseCandy()
// 检查Candy数量
if (candyMachine.getCount() == 0) {
candyMachine.setState(candyMachine._mSoldOutState)
} else {
candyMachine.setState(candyMachine._mOnReadyState)
}
}
}
====================class HasCoin extends State====================
package com.lj.akka.proxymode.remotecandymachine.server
class HasCoin extends State {
private val random = new java.util.Random
@transient private var candyMachine: CandyMachine = _
def this(candyMachine: CandyMachine) {
this
this.candyMachine = candyMachine
}
override def insertCoin(): Unit = {
println("你已经投入了硬币,无需再次投入硬币......")
}
override def returnCoin(): Unit = {
println("投入的硬币已退回,欢迎下次光临......")
candyMachine.setState(candyMachine._mOnReadyState)
}
override def turnCrank(): Unit = {
println("手柄正在转动,等待出Candy......")
// 奖励机制
val num = random.nextInt(10)
if (num == 0) {
candyMachine.setState(candyMachine._mWinnerState)
} else {
candyMachine.setState(candyMachine._mOnReadyState)
}
}
override def printState(): Unit = {
println("Has Coin......")
}
override def getStateName(): String = {
"Has Coin......"
}
override def dispense(): Unit = {}
}
====================class Sold extends State====================
package com.lj.akka.proxymode.remotecandymachine.server
class Sold extends State {
@transient private var candyMachine: CandyMachine = _
def this(candyMachine: CandyMachine) {
this
this.candyMachine = candyMachine
}
override def insertCoin(): Unit = {
println("等待投入硬币,Candy Machine正在出Candy....")
}
override def returnCoin(): Unit = {
println("目前正在出Candy,无法退出硬币....")
}
override def turnCrank(): Unit = {
println("Candy Machine正在出Candy,不能转动手柄....")
}
override def printState(): Unit = {
println("Sold State...")
}
override def getStateName(): String = {
"Sold State..."
}
// 这里不做任何操作,不出糖果
override def dispense(): Unit = {}
}
====================class SoldOut extends State====================
package com.lj.akka.proxymode.remotecandymachine.server
class SoldOut extends State {
@transient private var candyMachine: CandyMachine = _
def this(candyMachine: CandyMachine) {
this
this.candyMachine = candyMachine
}
override def insertCoin(): Unit = {
println("Candy已经售空,禁止投入硬币购买糖果.")
}
override def returnCoin(): Unit = {
println("Candy Machine 还没有投入硬币,没有要返还的硬币.")
}
override def turnCrank(): Unit = {
println("Candy已经售空,转动手柄无任何效果.")
}
override def printState(): Unit = {
println("Candy已经售空.")
}
override def getStateName(): String = {
"Candy Sold Out State."
}
override def dispense(): Unit = {}
}
====================object RemoteMain====================
package com.lj.akka.proxymode.remotecandymachine.server
import java.rmi.Naming
import java.rmi.registry.LocateRegistry
import com.lj.akka.proxymode.remotecandymachine.client.Monitor
object RemoteMain {
def main(args: Array[String]): Unit = {
try {
val monitor: Monitor = new Monitor
var service: CandyMachine = new CandyMachine("北京-西郊01", 30)
monitor.addCandyMachine(service)
service = new CandyMachine("上海-徐家汇01", 13)
monitor.addCandyMachine(service)
service = new CandyMachine("深圳-自贸区01", 8)
monitor.addCandyMachine(service)
LocateRegistry.createRegistry(13332)
Naming.rebind("rmi://127.0.0.1:13332/CandyMachine", service)
println(s"服务端有${monitor._candyMachines.size}台Candy Machine开始运行,在端口13332监听,信息如下:")
while (true) {
monitor.report()
Thread.sleep(15000)
println("==================华丽分隔符=====================")
// 监控客户端信息变化
val clientCandyMachineRemote = Naming.lookup("rmi://127.0.0.1:13332/ClientCandyMachine")
.asInstanceOf[CandyMachineRemote]
monitor.update(clientCandyMachineRemote.getLocation(), clientCandyMachineRemote.getCount())
}
} catch {
case ex: Exception => ex.printStackTrace()
}
}
}
==============================class Monitor===============================
package com.lj.akka.proxymode.remotecandymachine.client
import com.lj.akka.proxymode.remotecandymachine.server.{CandyMachine, CandyMachineRemote}
import scala.collection.mutable.ListBuffer
class Monitor {
private val candyMachines: ListBuffer[CandyMachineRemote] = ListBuffer()
def _candyMachines: ListBuffer[CandyMachineRemote] = candyMachines
// add candy machine
def addCandyMachine(candyMachine: CandyMachineRemote): Unit = {
candyMachines.append(candyMachine)
}
def report(): Unit = {
for (ele <- candyMachines) {
println("----------------------------------------")
println("Machine local:" + ele.getLocation())
println("Candy还剩余数量:" + ele.getCount())
println("Candy Machine State:" + ele.getState().getStateName())
}
}
// 更新
def update(location: String, count: Int): Unit = {
for (ele <- candyMachines) {
if (ele.getLocation() == location) {
candyMachines -= ele
candyMachines.append(new CandyMachine(location, count))
}
}
}
}
====================trait CandyMachineRemote extends Remote====================
package com.lj.akka.proxymode.remotecandymachine.client
import java.rmi.Naming
import com.lj.akka.proxymode.remotecandymachine.server.{CandyMachine, CandyMachineRemote}
object RemoteClient {
def main(args: Array[String]): Unit = {
val monitor = new Monitor
try {
val mCandyMachineRemote = Naming.lookup("rmi://127.0.0.1:13332/CandyMachine").asInstanceOf[CandyMachineRemote]
monitor.addCandyMachine(mCandyMachineRemote)
println(s"客户端Candy Machine(位置:${mCandyMachineRemote.getLocation()})在运行,情况如下:")
monitor.report()
println("客户对Candy Machine操作......")
val clientCandyMachine = new CandyMachine(mCandyMachineRemote.getLocation(), mCandyMachineRemote.getCount())
// LocateRegistry.createRegistry(13332)
while (true) {
clientCandyMachine.insertCoin()
clientCandyMachine.turnCrank()
// 更新数据到远程监控
Naming.rebind("rmi://127.0.0.1:13332/ClientCandyMachine", clientCandyMachine)
Thread.sleep(10000)
}
} catch {
case ex: Exception => ex.printStackTrace()
}
}
}
五、动态代理
动态代理:运行时动态的创建代理类(对象),并将方法调用转发到指定类(对象)。
1、类图结构
2、类图结构说明
1. Proxy和InvocationHandler组合充当代理的角色;
2. RealSubject是一个实际对象,它实现接口Subject;
3. 在使用时,我们不希望直接访问RealSubject的对象,比如:我们对这个对象的访问是有控制的;
4. 使用动态代理,在程序中通过动态代理创建RealSubject,并完成调用;
5. 动态代理可以根据需要,创建多种组合;
6. Proxy也会实现Subject接口的方法,因此,使用Proxy+Invocation可以完成对RealSubject的动态调用;
7. 但是通过Proxy调用RealSubject方法是否成功,是由InvocationHandler来控制的。(这里其实就是保护代理);
8. 理解:创建一个代理对象替代被调用的真实对象,使用反射实现控制。
3、保护代理
通过前面的分析:大家可以看出动态代理其实就体现出保护代理,即代理时,对被代理的对象(类)的
哪些方法可以调用,哪些方法不能调用在InvocationHandler可以控制。因此动态代理就体现(实现)了保护
代理的效果。
4、动态代理的应用案例
有一个婚恋网项目,女友/男友有个人信息、兴趣爱好和总体评分,要求:
1. 不能自己给自己评分;
2. 其它用户可以评分,但是不能设置信息,兴趣爱好;
3. 请使用动态代理实现保护代理的效果;
4. 分析这里我们需要写两个代理。一个是自己使用,一个是提供给其它用户使用。
5、应用案例示意图
6、应用案例代码实现
代码结构图:
示例代码:
================================trait PersonBean================================
package com.lj.akka.dynproxymode
// 这个就是Subject(是一个trait/Java中interface)
trait PersonBean {
def getName(): String
def getGender(): String
def getInterests(): String
def getScore(): Int
def setName(name: String)
def setInterests(interests: String)
def setScore(score: Int)
def setGender(gender: String)
}
========================class PersonBeanImpl extends PersonBean========================
package com.lj.akka.dynproxymode
// 这个是要被调用的对象,相当于RealSubject
class PersonBeanImpl extends PersonBean {
var name: String = _
var gender: String = _
var interests: String = _
var score: Int = _
override def getName(): String = {
this.name
}
override def getGender(): String = {
this.gender
}
override def getInterests(): String = {
this.interests
}
override def getScore(): Int = {
this.score
}
override def setName(name: String): Unit = {
this.name = name
}
override def setInterests(interests: String): Unit = {
this.interests = interests
}
override def setScore(score: Int): Unit = {
this.score = score
}
override def setGender(gender: String): Unit = {
this.gender = gender
}
}
==================class OwnerInvocationHandler extends InvocationHandler==================
package com.lj.akka.dynproxymode
import java.lang.reflect.{InvocationHandler, Method}
// 自己调用的代理,继承java.lang.reflect.InvocationHandler
class OwnerInvocationHandler extends InvocationHandler {
var person: PersonBean = _
def this(person: PersonBean) {
this
this.person = person
}
//说明
//1.这里的proxy就是和OwnerInvocationHandler合作的代理
@throws(classOf[Throwable])
override def invoke(proxy: scala.Any, method: Method, objects: Array[AnyRef]): AnyRef = {
if (method.getName.startsWith("get")) {
/**
* 说明:method.invoke(person, objects)中objects为什么不能传入进去
* 原因:底层传的是一个可变参数,写上会导致运行不起来,实际在底层它自己就会获取这个objects
*/
method.invoke(person)
//自己不能调用setHotOrNotRating,给自己评分
} else if (method.getName.equals("setScore")) {
//返回一个异常,同时invoke throws掉了
new IllegalAccessException("无权限修改自己的分数...")
} else if (method.getName.equals("set")) {
method.invoke(person, objects(0).toString)
} else {
null
}
}
}
==================class NonOwnerInvocationHandler extends InvocationHandler==================
package com.lj.akka.dynproxymode
import java.lang.reflect.{InvocationHandler, Method}
//其它用户调用的代理
class NonOwnerInvocationHandler extends InvocationHandler {
var person: PersonBean = _
def this(person: PersonBean) {
this
this.person = person
}
//说明
//1.这里的proxy就是和OwnerInvocationHandler合作的代理
@throws(classOf[Throwable])
override def invoke(proxy: scala.Any, method: Method, objects: Array[AnyRef]): AnyRef = {
if (method.getName.startsWith("get")) {
method.invoke(person)
} else if (method.getName.equals("setScore")) {
method.invoke(person, Integer.valueOf(objects(0).toString))
} else if (method.getName.equals("set")) {
//其它用户不能调用set方法
new IllegalAccessException("其他用户无权限修改他/她人的信息...")
} else {
null
}
}
}
================================class MatchService================================
package com.lj.akka.dynproxymode
import java.lang.reflect.Proxy
class MatchService {
// 设置第一个人的信息
val tom = getPersonInfo("tom", "男", "爱好编程")
// 获取自己的代理
val ownerProxy = getOwnerProxy(tom)
// 给自己设置爱好
ownerProxy.setInterests("爱好淘宝~")
// 自己给自己设置评分,通过代理控制,不能成功,分数仍然为0
ownerProxy.setScore(100)
println(s"第一个人的信息:Name:${ownerProxy.getName()}" +
s",Interests:${ownerProxy.getInterests()}" +
s",setScore:${ownerProxy.getInterests()}")
println("=====================测试NonOwnerInvocationHandler=====================")
// 设置第二个人的信息
val marry = getPersonInfo("marry", "女", "爱好购物...")
// 获取别人的代理
val nonOwnerProxy = getNonOwnerProxy(marry)
// 其它人不能修改兴趣,通过代理进行控制不能调用setInterests
nonOwnerProxy.setInterests("爱好小猫咪~~")
nonOwnerProxy.setScore(68) //其它人可以评分
println(s"第二个人的信息:Name:${ownerProxy.getName()}" +
s",Interests:${ownerProxy.getInterests()}" +
s",setScore:${ownerProxy.getInterests()}")
// 设置个人信息
def getPersonInfo(name: String, gender: String, interests: String): PersonBean = {
val person = new PersonBeanImpl()
person.setName(name)
person.setGender(gender)
person.setInterests(interests)
person
}
// 获取自己的代理
def getOwnerProxy(person: PersonBean): PersonBean = {
Proxy.newProxyInstance(person.getClass().getClassLoader()
, person.getClass().getInterfaces()
, new OwnerInvocationHandler(person)).asInstanceOf[PersonBean]
}
def getNonOwnerProxy(person: PersonBean): PersonBean = {
Proxy.newProxyInstance(person.getClass()
.getClassLoader(), person.getClass().getInterfaces(),
new NonOwnerInvocationHandler(person)).asInstanceOf[PersonBean]
}
}
==============================object MainTest============================
package com.lj.akka.dynproxymode
object MainTest {
def main(args: Array[String]): Unit = {
new MatchService()
}
}
=================================运行结果==================================
第一个人的信息:Name:tom,Interests:爱好编程,setScore:爱好编程
=====================测试NonOwnerInvocationHandler=====================
第二个人的信息:Name:tom,Interests:爱好编程,setScore:爱好编程
=================================运行结果==================================
7、几种常见的代理模式介绍— 几种变体
1. 防火墙代理:内网通过代理穿透防火墙,实现对公网的访问;
2. 缓存代理:比如,当请求图片文件等资源时,先到缓存代理取,如果取到资源则ok,如果取不到资源,再到公网
或者数据库取,然后缓存;
3. 静态代理:静态代理通常用于对原有业务逻辑的扩充。比如:
持有第二方包的某个类,并调用了其中的某些方法;
记录日志、打印工作等。可以创建一个代理类实现和第二方方法相同的方法,通过让代理类持有真实对象,
调用代理类方法,来达到增加业务逻辑的目的;
4. Cglib代理:使用cglib[Code Generation Library]实现动态代理,并不要求委托类必须实现接口,底层采用
asm字节码生成框架生成代理类的字节码;
5. 同步代理:主要使用在多线程编程中,完成多线程间同步工作
对以前的知识回顾,加深基础知识!
学习来自:北京尚硅谷韩顺平老师—尚硅谷大数据技术之Scala
每天进步一点点,也许某一天你也会变得那么渺小!!!