知道什么是动态代理以及动态代理能干什么就可以
? 使用jdk的反射机制,创建对象的能力, 创建的是代理类的对象。
? 可以在不改变原来目标方法功能的前提下, 可以在代理中增强自己的功能代码。
? 例如实际开发中,你所在的项目中,有一个功能是其他人(公司的其它部门,其它小组的人)写好的,你可以使用。你发现这个功能,现在还缺点,不能完全满足我项目的需要。 我需要在gn.print()执行后,需要自己在增加代码。用代理实现 gn.print()调用时, 增加自己代码, 而不用去改原来的 GoNong文件。
// GoNong.class
GoNong gn = new GoNong();
gn.print();
? 注意,不知道源代码,不能使用重写,而且你要用写好的功能想要去扩展功能,就只能先把写好的方法执行一边,然后再代理中扩展,重写的话,原来写好的方法也没了
? 代理就是中介、代购、商家等。
? 例如留学中介就是一个代理,我想上美国的一所大学,但是我没办法去这个大学实地考察,也没办法要这个大学的联系方式,并且这个大学拒绝个人去访问它。但是这个大学在国内把招生业务委派给了一个留学中介。这样我就可以去和留学中介交谈,留学中介可以与美国大学联系。留学中介会从我这里收取额外的中介费。
? 在以上的案例中,学校是目标,留学中介是代理,我是客户。它们具有以下特点:
中介和代理他们要做的事情是一致的: 招生。
中介是学校代理, 学校是目标。
我—中介(学校介绍,办入学手续)----美国学校。
中介是代理,不能白干活,需要收取费用。
代理不让你访问到目标。
中介是专业的,方便
我现在不能自己去找学校。 我没有能力访问学校。 或者美国学校不接收个人来访。
买东西都是商家卖, 商家是某个商品的代理, 你个人买东西, 肯定不会让你接触到厂家的。
? 代理模式是指,当一个对象(目标)无法直接使用时,可以在该客户端和目标类之间创建一个中介,这个中介就是代理。
? 在实际开发中有这样情况,有一个A类,有一个C类,但是C类不允许A类直接访问,这样我们可以创建一个A类和C类之间的B类,C类允许B类访问,这样我们可以在A类中访问B类,然后B类在访问C类,这样就相当于在A类中间接访问到了C类。其中A类是客户类,B类是代理类,C类是目标类。另外,我可以在B类中添加一些内容,意味着功能增强。
实现代理的方式有:静态代理,动态代理
? 静态代理:代理类是手工创建的,代理的目标类是固定的。
模拟一个用户购买u盘的行为,其中用户是客户端类,商家是代理类,厂家是目标类,商家和厂家都是卖U盘的,应该把卖U盘这个动作抽象为一个接口。
创建一个接口,定义卖u盘的方法, 表示你的厂家和商家做的事情。
// 表示功能的,厂家,商家都要完成的功能
public interface UsbSell {
//定义方法 参数 amount:表示一次购买的数量,暂时不用
//返回值表示一个u盘的价格。
float sell(int amount);
//可以多个其它的方法
//void print();
}
创建厂家类,实现1步骤的接口
//目标类:金士顿厂家, 不接受用户的单独购买。
public class UsbKingFactory implements UsbSell {
@Override
public float sell(int amount) {
System.out.println("目标类中的方法调用 , UsbKingFactory 中的sell ");
//一个128G的u盘是 85元。
//后期根据amount ,可以实现不同的价格,例如10000个,单击是80, 50000个75
return 85.0f;
}
}
创建商家,就是代理类,也需要实现1步骤中的接口。
// taobao是一个商家,代理金士顿u盘的销售。
public class TaoBao implements UsbSell {
// 声明 商家代理的厂家具体是谁
// private修饰为了控制访问,不让客户知道厂家是谁
private UsbKingFactory factory = new UsbKingFactory();
@Override
// 实现销售u盘功能
public float sell(int amount) {
// 向厂家发送订单,告诉厂家,我买了u盘,厂家发货
float price = factory.sell(amount); //厂家的价格。
// 商家 需要加价, 也就是代理要增加价格。
price = price + 25; //增强功能,代理类在完成目标类方法调用后,增强了功能。
// 在目标类的方法调用后,你做的其它功能,都是增强的意思。
System.out.println("淘宝商家,给你返一个优惠券,或者红包");
// 增加的价格
return price;
}
}
public class WeiShang implements UsbSell {
//代理的是 金士顿,定义目标厂家类
private UsbKingFactory factory = new UsbKingFactory();
@Override
public float sell(int amount) {
//调用目标方法
float price = factory.sell(amount);
//只增加1元
price = price + 1;
return price;
}
}
创建客户端类,调用商家的方法买一个u盘。
public class Customer {
public static void main(String[] args) {
// 通过淘宝卖
// 下载了淘宝的app
/*
TaoBao taoBao = new TaoBao();
// 通过代理类,实现购买u盘,增加了优惠券,红包等等
float price = taoBao.sell(1);
System.out.println("淘宝的价格:" + price);
*/
// 取得微商的联系方式
WeiShang weiShang = new WeiShang();
// 通过微商代理,实现购买u盘,增加了优惠券,红包等等
float price = weiShang.sell(1);
System.out.println("通过微商购买的价格:"+ price);
}
}
分析问题:
简而言之,静态代理容易理解,代码好写,但是各个类之间耦合度太高,一旦扩展就有问题
? 动态代理就是在程序执行过程(动态)中,使用jdk的反射机制,创建代理类对象, 并动态的指定要代理目标类。换句话说: 动态代理是一种创建java对象的能力,让你不用自己写代理类的java程序,然后new对象。而是直接用jdk创建代理类对象。这样我不关心代理类是谁,我只知道它能增强功能,并且通过它我可以找到目标类。(类似暗下交易)
注意:jdk动态代理必须有接口,对于无接口类,必须使用cglib来为它创建动态代理
需要用到反射包 java.lang.reflect,里面有三个类 : InvocationHandler , Method, Proxy.
public Object invoke(Object proxy, Method method, Object[] args)
invoke方法参数:
InvocationHandler接口表示你的代理想要干什么,即代理完成的功能写在该接口实现类的invoke方法中
使用方法:
public static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)
newProxyInstance参数说明:
返回值就是代理类对象,并且在该对象创建时已经说明了,该代理类对象所代理的目标对象是谁,该目标对象完成了那些功能,该代理类所要完成的功能
创建接口,定义目标类要完成的功能
/**
* 目标类要完成的功能
*/
public interface UsbSell {
float sell(int amount);
}
创建目标类实现接口
//目标类:金士顿厂家, 不接受用户的单独购买。
public class UsbKingFactory implements UsbSell {
@Override
public float sell(int amount) {
System.out.println("目标类中的方法调用 , UsbKingFactory 中的sell ");
//一个128G的u盘是 85元。
//后期根据amount ,可以实现不同的价格,例如10000个,单击是80, 50000个75
return 85.0f;
}
}
创建InvocationHandler接口的实现类,在invoke方法中完成代理类的功能
1.调用目标方法
2.增强功能
//必须实现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;
//向厂家发送订单,告诉厂家,我买了u盘,厂家发货
//float price = factory.sell(amount); //厂家的价格。
res = method.invoke(target,args); //执行目标方法
//商家 需要加价, 也就是代理要增加价格。
//price = price + 25; //增强功能,代理类在完成目标类方法调用后,增强了功能。
if( res != null ){
Float price = (Float)res;
price = price + 25;
res = price;
}
//在目标类的方法调用后,你做的其它功能,都是增强的意思。
System.out.println("淘宝商家,给你返一个优惠券,或者红包");
//记录数据库
//增加的价格
return res;
}
}
使用Proxy类的静态方法,创建代理对象。 并把返回值转为接口类型。
public class Customer {
public static void main(String[] args) {
//创建代理对象,使用Proxy
//1. 创建目标对象
// UsbKingFacotry factory = new UsbKingFactory();
UsbSell factory = new UsbKingFactory();
//2.创建InvocationHandler对象
InvocationHandler handler = new MySellHandler(factory);
//3.创建代理对象
UsbSell proxy = (UsbSell) Proxy.newProxyInstance(factory.getClass().getClassLoader(),
factory.getClass().getInterfaces(),
handler);
//com.sun.proxy.$Proxy0 : 这是jdk动态代理创建的对象类型。
System.out.println("proxy:"+proxy.getClass().getName());
//4.通过代理执行方法
float price = proxy.sell(1);
System.out.println("通过动态代理对象,调用方法:"+price);
}
}
// 目标完成的功能
public interface HelloService {
//打印报告, 报表
int print(String name);
}
// 目标类
public class GoNeng implements HelloService {
@Override
public int print(String name) {
System.out.println("其它人写好的个功能方法");
return 2;
}
}
// 代理完成的功能
public class MyInvocationHandler implements InvocationHandler {
private Object target = null;
public MyInvocationHandler(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//我在项目中记录数据库,
//调用目标方法, 执行print()得到 2
Object res = method.invoke(target,args); //2
// 代理进行“功能增强”
//需要乘以 2的结果
if( res != null){
Integer num = (Integer)res;
res = num * 2;
}
return res;
}
}
// 测试类
public class MyApp {
public static void main(String[] args) {
// GoNeng gn = new GoNeng();
//int num = gn.print("销售");
// System.out.println("num="+num);
// 创建目标类
GoNeng goNeng = new GoNeng();
// 代理完成的功能
InvocationHandler handler = new MyInvocationHandler(goNeng);
// 这里表示目标类必须实现一个接口,否则不能用jdk实现动态代理,只能用cglib实现动态代理
System.out.println("goNeng.getClass().getInterfaces()="+goNeng.getClass().getInterfaces()[0].getName());
HelloService proxy = (HelloService) Proxy.newProxyInstance( goNeng.getClass().getClassLoader(),
goNeng.getClass().getInterfaces(),handler);
// 代理proxy的print方法实际上是接口中的,因为再创建代理是,把目标类的构造器和实现的接口都给了代理,并且代理完成的功能也给了代理
// 代理执行print方法就去handler的invoke方法,把print方法给了method,参数“市场”给了args
int num = proxy.print("市场");
System.out.println("我们期望的 num ==" + num);
// 总之proxy,handler,目标类之间是相关联的。
}
}