Proxy学习记录
一、代理模式
代理是基于反射机制,使用代理对象,是为了在不修改目标对象的基础上,增强主业务逻辑
1、什么是代理
举例:
代购, 中介,换ip,商家等等
比如有一家美国的大学, 可以对全世界招生。 留学中介(代理)
留学中介(代理): 帮助这家美国的学校招生, 中介是学校的代理, 中介是代替学校完成招生功能。
代理特点:
1. 中介和代理他们要做的事情是一致的: 招生。
2. 中介是学校代理, 学校是目标。
3. 家长---中介(学校介绍,办入学手续)----美国学校。
4. 中介是代理,不能白干活,需要收取费用。
5. 代理不让你访问到目标。
为什么要找中介 ?
1. 中介是专业的, 方便
2. 家长现在不能自己去找学校。 家长没有能力访问学校。 或者美国学校不接收个人来访。
买东西都是商家卖, 商家是某个商品的代理, 你个人买东西, 肯定不会让你接触到厂家的。
2、需要代理的原因
例如: 有 A,B,C 三个类, A 原来可以调用 C 类的方法, 现在因为某种原因 C 类不允许A 类调用其方法,但 B 类可以调用 C 类的方法。
A 类通过 B 类调用 C 类的方法。这里 B 是 C的代理。
A 通过代理 B 访问 C.
3、代理的作用
1.功能增强: 在你原有的功能上,增加了额外的功能。 新增加的功能,叫做功能增强。
2.控制访问: 代理类不让你访问目标,例如商家不让用户访问厂家。
4、代理模式分类
静态代理和动态代理
二、静态代理实现
静态代理是指,代理类在程序运行前就已经定义好.java 源文件,其与目标类的关系在
程序运行前就已经确立。
在程序运行前代理类已经编译为.class 文件。
1、静态代理
1)代理类是自己手工实现的,自己创建一个java类,表示代理类。
2)同时你所要代理的目标类是确定的。
2、优点/缺点
1)优点:实现简单;容易理解
2)缺点:当目标类增加了, 代理类可能也需要成倍的增加,最终代理类数量过多;
当你的接口中功能增加或修改,会影响众多的实现类、厂家类,代理都需要修改
3、举例
模拟一个用户购买u盘的行为。
用户是客户端类
商家:代理,代理某个品牌的u盘。
厂家:目标类。
三者的关系: 用户(客户端)---商家(代理)---厂家(目标)
商家和厂家都是卖u盘的,他们完成的功能是一致的,都是卖u盘。
1)创建一个接口,定义卖u盘的方法, 表示你的厂家和商家做的事情。
// UsbSell.java
package com.bjpowernode.service;
public interface UsbSell {
float sell(int amount);
}
2)创建厂家类,实现1步骤的接口
// UsbKingFactory.java
package com.bjpowernode.factory;
import com.bjpowernode.service.UsbSell;
public class UsbKingFactory implements UsbSell {
@Override
public float sell(int amount){
System.out.println("King's USB disk");
return 85.0f;
}
}
3)创建商家,就是代理,也需要实现1步骤中的接口。
// TaoBao.java
package com.bjpowernode.Saler;
import com.bjpowernode.factory.UsbKingFactory;
import com.bjpowernode.service.UsbSell;
public class TaoBao implements UsbSell {
private UsbKingFactory factory = new UsbKingFactory();
@Override
public float sell(int amount) {
float price = factory.sell(1);
price = price + 25;
System.out.println("感谢购买,赠送一张优惠券");
return price;
}
}
4)创建客户端类,调用商家的方法买一个u盘。
// Market.java
package com.bjpowernode;
import com.bjpowernode.Saler.TaoBao;
import com.bjpowernode.factory.UsbKingFactory;
public class Market {
public static void main(String[] args) {
TaoBao taoBao = new TaoBao();
float price = taoBao.sell(1);
System.out.println("通过淘宝购买U盘的单价:" + price);
UsbKingFactory usbKingFactory = new UsbKingFactory();
float price1 = usbKingFactory.sell(1);
System.out.println("淘宝在厂家直接购买U盘单价:" + price1);
}
}
4、动态代理
在静态代理中目标类很多时候,可以使用动态代理,避免静态代理的缺点
- 1)代理类数量可以很少,
- 2)当你修改了接口中的方法时,不会影响代理类。
在程序执行过程中,使用jdk的反射机制,创建代理类对象, 并动态的指定要代理目标类
动态代理是一种创建java对象的能力,让你不用创建代理类,就能创建代理类对象
5、动态代理的实现
java 语言通过 java.lang.reflect
包提供三个类支持代理模式 Proxy, Method, InovcationHandler
1)InvocationHandler 接口(调用处理器):就一个方法invoke()
invoke():表示代理对象要执行的功能代码。
你的代理类要完成的功能就写在invoke()方法中。
2)Method类:表示方法的, 确切的说就是目标类中的方法。
作用:通过Method可以执行某个目标类的方法,Method.invoke();
method.invoke(目标对象,方法的参数)
3)Proxy类:核心的对象,创建代理对象。之前创建对象都是 new 类的构造方法()
现在我们是使用Proxy类的方法,代替new的使用。
方法: 静态方法 newProxyInstance()
作用是: 创建代理对象, 等同于静态代理中的TaoBao taoBao = new TaoBao();
6、举例
通过动态代理完成模拟一个用户购买u盘的行为。
用户是客户端类
商家:代理,代理某个品牌的u盘。
厂家:目标类。
1)创建接口,定义目标类要完成的功能
// UsbSell.java
package com.bjpowernode.service;
public interface UsbSell {
float sell(int amount);
}
2)创建目标类实现接口
// UsbKingFactory.java
package com.bjpowernode.factory;
import com.bjpowernode.service.UsbSell;
// 目标类
public class UsbKingFactory implements UsbSell {
@Override
public float sell(int amount) {
// 目标方法
System.out.println("此为目标类,执行了目标方法");
return 85.0f;
}
}
3)创建InvocationHandler接口的实现类,在invoke方法中完成代理类的功能
调用目标方法;增强功能
// MySellHandler.java
package com.bjpowernode.handler;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
// 必须实现InvocationHandler接口,完成代理类要做到功能
// 即 1.调用目标方法;2.功能增强
public class MySellHandler implements InvocationHandler {
private Object target = null;
// 动态代理:目标对象是活动的,不是固定的,需要传入进来
// 传入的是谁,就给谁创建代理
public MySellHandler(Object target){
// 给目标对象赋值
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object res = null;
res = method.invoke(target, args); // 执行目标方法
// 功能增强
if(res != null){
Float price = (Float)res;
price = price + 25;
res = price;
}
// 其他功能
System.out.println("欢迎购买,赠送淘宝优惠券");
return res;
}
}
4)使用Proxy类的静态方法,创建代理对象。 并把返回值转为接口类型。
// MainShop.java
package com.bjpowernode;
import com.bjpowernode.factory.UsbKingFactory;
import com.bjpowernode.handler.MySellHandler;
import com.bjpowernode.service.UsbSell;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
public class MainShop {
public static void main(String[] args) {
// 创建代理对象,使用Proxy
// 1.创建目标对象
UsbSell factory = new UsbKingFactory();
// 2.创建InvocationHandler对象,传入目标对象
InvocationHandler handler = new MySellHandler(factory);
// 3.创建代理对象
UsbSell proxy = (UsbSell)Proxy.newProxyInstance(factory.getClass().getClassLoader(), factory.getClass().getInterfaces(), handler);
// 4.通过代理执行方法
float price = proxy.sell(1);
System.out.println("通过动态代理,调用方法:" + price);
}
}