一、概述
代理模式是Java常见的设计模式之一。所谓代理模式是指客户端并不直接调用实际的对象,而是通过调用代理,来间接的调用实际的对象。
举例:购买保险,不直接购买而是通过代理人购买
购买火车票,自己不去窗口、12306购买 通过黄牛/美团 购买
为什么要采用这种间接的形式来调用对象呢?
1.因为客户端不想直接访问实际的对象,或者访问实际的对象存在困难,因此通过一个代理对象来完成间接的访问。
2.不改变原程序代码的前提下,对功能进行扩充。通过代理模式,我们可以很方便的给代码添加日志记录,事务控制,权限控制等一系列功能。
对应目标方法增强的公共代码:日志记录,事务控制,权限控制 类似于过滤器
二、静态代理
静态代理:代理只能代理某一类,不能代理多个类
火车票例子:
/**
* 火车票
*/
public interface Ticket {
/**
* 购买火车票
*/
void buyTicket();
}
public class TicketBy12306 implements Ticket {
public void buyTicket() {
System.out.println("12306 购买火车票");
}
}
/**
* 黄牛购买火车票
*
* 黄牛:就是一个代理,只能代理 购买火车票
* 此黄牛为静态代理 对应目标方法的增强 增加日志 多收费用
*/
public class TicketByHuangNiu implements Ticket {
private Ticket ticket ;
public void setTicket(Ticket ticket) {
this.ticket = ticket;
}
/**
* 黄牛购买火车票 也要通过 12306 购买
*/
public void buyTicket() {
System.out.println("黄牛开始抢票");
ticket.buyTicket();
System.out.println("黄牛抢票成功,收费200");
}
}
测试:
public class Test {
public static void main(String[] args) {
Ticket ticket =new TicketBy12306();
// 通过12306 购买火车票
// ticket.buyTicket();
TicketByHuangNiu ticketByHuangNiu = new TicketByHuangNiu();
ticketByHuangNiu.setTicket(ticket);
//黄牛代理购买火车票
ticketByHuangNiu.buyTicket();
}
}
三、动态代理
一物多用
动态代理就是一个代理可以代理多种 目标对象,对目标对象的方法进行增强
jdk动态代理:
只能代理目标对象实现的接口 不能代理没有接口的目标对象
1、创建目标对象
// 目标对象
final Ticket ticket =new TicketBy12306();
2、创建代理对象
// 创建带代理对象
// TicketByHuangNiu ticketByHuangNiu = new TicketByHuangNiu();
// 使用jdk 动态创建代理对象 ********
// ClassLoader loader, 类加载器 类加载器 将class 加载到内存中,
// Class<?>[] interfaces, 目标对象 实现的接口
// InvocationHandler h 当代理对象要 对应的接口方法时 ,会回调(触发invoke方法) ,然后 调用 目标对象的方法
// 代理对象 只能代理 目标对象对应的接口 Proxy.newProxyInstance
Ticket ticketHuangNiu = (Ticket) Proxy.newProxyInstance(ticket.getClass().getClassLoader(),
ticket.getClass().getInterfaces(), new InvocationHandler() {
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// Object proxy, 当前代理对象
// Method method, 执行的方法名
// Object[] args 执行方法的参数
// 完成 代理 ,对应目标方法的调用
System.out.println(" 代理对象开始 调用目标对象");
// 让目标对象反射执行
Object result = method.invoke(ticket,args);
System.out.println(" 代理对象完成 调用目标对象对应方法并返回结果");
return result;
// return null;
}
}
);
3、调用代理对象方法
// 代理对象 调用对应的接口 触发 InvocationHandler 回调
ticketHuangNiu.buyTicket();