什么是动态代理?
使用JDK反射机制,创建对象的能力,创建的是代理类的对象,而不用你创建类,不用写java文件 动态:在程序执行时,调用JDK提供的方法才能创建代理类的对象 JDK动态代理,必须有接口,目标类必须实现接口,没有接口时需要使用cglib动态代理
知道动态代理能做什么 ?
在不改变原来的目标方法功能的前提下,可以在代理中增强自己的功能代码
1.什么是代理
代理:在我们生活之中就有体会,代购,中介,换IP,商家等等
使用代理模式的作用:
- 功能增强: 在你原有的功能上,增加了额外的功能,新增加的功能,叫做功能增强
- 控制访问: 代理类不上你访问目标…例如商家不让用户访问厂家
实现代理的方式
静态代理
- 代理类是自己手工写实现的,自己创建一个JAVA类,表示代理类
- 同时你所代理的目标类是确定的
**优点>>**实现简单 容易理解
缺点>> 当你的项目中.目标类和代理类很多的时候,有以下缺点
- 当目标类增加了,代理类可能也需要成倍的增加,代理类数量过多
- 当你的接口中功能增加了,或者修改了,会影响众多的实现类,厂家类,代理都需要修改,影响比较多
模拟一个用户购买u盘的行为。 用户是客户端类 商家:代理,代理某个品牌的u盘。 厂家:目标类。 三者的关系: 用户(客户端)—商家(代理)—厂家(目标) 商家和厂家都是卖u盘的,他们完成的功能是一致的,都是卖u盘。 实现步骤
- 创建一个接口,定义卖U盘的方法,表示你的厂家和商家做的事情
- 创建厂家类,实现1步骤的接口
- 创建厂家类,就是代理,也需要实现1步骤中的接口
- 创建客户端类,调用商家的方法买一个
代理类完成的功能:
- 目标类中的方法调用
- 功能增强
所属我们只有一个代理商,我们实际上可以写多个代理商,
动态代理
什么是动态代理
使用JDK的反射机制,创建对象的能力,创建的时代理类的对象.而不用我们创建类的文件.
什么叫动态?在程序执行时,调用JDK提供的方法才能创建代理类的对象
静态代理和动态代理模式的对比
静态代理中目标很多的时候,可以使用动态代理,避免静态代理的缺点
动态代理中目标类即使很多
- 代理类数量可以很少
- 当你修改了接口中的方法时…不会影响代理类
动态代理:
在执行过程中,使用了JDK的反射机制,创建代理类对象,并动态的指定要代理目标类
换句话说:动态代理是一种创建JAVA对象的能力,让你不用创建淘宝类,就能创建代理类对象,
在java中,要想创建对象
- 创建类文件,java文件编译为Class文件
- 使用构造方法,创建类的对象
动态代理的介绍:
1.动态代理是指代理类对象在程序运行时由JVM根据反射机制动态生成的,动态代理不需要定义代理类的,java源文件
2.动态代理其就是JDK运行期间,动态创建Class字节码并加载到JVM
3.动态代理的实现运行常用两种方式:使用JDK
代理,与通过CGLlB
动态代理。
动态代理的实现:
JDK动态代理
JDK动态代理(理解),使用java反射包的类和接口实现动态代理的功能
反射包java.lang.reflect
里面有三个类 : InvocationHandler
,Method
, Proxy
- 反射: Method类,表示方法,类中的方法,通过method可以执行某个方法
- JDK动态代理的实现
反射包 java.lang.reflect , 里面有三个类 :
InvocationHandler , Method, Proxy.
1) InvocationHandler`InvocationHandler
接口(调用对象); 就是一个方法invoke
()invoke
(): 表示代理对象要执行的功能代码, 要完成的功能就写在invoke()方法中 代理类完成的功能- 调用目标方法:执行目标方法的功能
- 功能增强,在目标方法调用时,增加功能。
方法原型:
代码语言:javascript复制参数:
Object proxy:jdk创建的代理对象,无需赋值。
Method method:目标类中的方法,jdk提供method对象的
Object[] args:目标类中方法的参数, jdk提供的。
public Object invoke(Object proxy, Method method, Object[] args)
InvocationHandler
接口:
代码语言:javascript复制表示你的代理要干什么。
怎么用: 1.创建类实现接口InvocationHandler
2.重写invoke()方法, 把原来静态代理中代理类要完成的功能,写在这。
2)Method类:
表示方法的, 确切的说就是目标类中的方法。
代码语言:javascript复制作用:
通过Method可以执行某个目标类的方法,Method.invoke();
method.invoke(目标对象,方法的参数)
Object ret = method.invoke(service2, "李四");
说明: method.invoke()就是用来执行目标方法的,等同于静态代理中的
//向厂家发送订单,告诉厂家,我买了u盘,厂家发货
float price = factory.sell(amount); //厂家的价格。
3)Proxy类:
代码语言:javascript复制核心的对象,创建代理对象。之前创建对象都是 new 类的构造方法() 现在我们是使用Proxy类的方法,代替new的使用。
方法: 静态方法 newProxyInstance()
作用是: 创建代理对象, 等同于静态代理中的TaoBao taoBao = new TaoBao();
参数:
-
ClassLoader loader
类加载器,负责向内存中加载对象的。 使用反射获取对象的ClassLoader
类a ,a.getCalss().getClassLoader()
, 目标对象的类加载器 -
Class<?>[] interfaces
: 接口, 目标对象实现的接口,也是反射获取的。 -
InvocationHandler
h : 我们自己写的,代理类要完成的功能。
返回值:就是代理对象
代码语言:javascript复制public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)
实现动态代理的步骤:
- 创建接口,定义目标类要完成的功能
- 创建目标类实现接口
- 创建InvocationHandler接口的实现类,在invoke方法中完成代理类的功能 1.调用目标方法 2.增强功能
4.使用Proxy类的静态方法,创建代理对象。 并把返回值转为接口类型。
代码语言:javascript复制第一步
public interface UsbSell {
float sell(int amount);
}
代码语言:javascript复制第二步
public class UsbKingFactory implements UsbSell {
@Override
public float sell(int amount) {
System.out.println("目标类中,执行了sell目标方法");
return 85.02f;
}
}
我们写了接口类,定义了功能,写了代理类,实现了接口功能,按照以前的操作,现在就需要写一个真正的代理类,创建对象.
第三步: 创建了
Invocationhandler
实现类,在invoke()方法中完成代理类de对象
- 调用目标的方法
- 增强功能
public class MyHandle implements InvocationHandler {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
return null;
}
}
代理类的实现方法上进行修改
代码语言:javascript复制//之前的代理类
public class TaoBao implements usbSell {
// 声明 商家代理的厂家具体是谁
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;
}
}
调用目标的方法
代码语言:javascript复制//传入是谁的对象,就给谁创建代理
public MyHandle(Object target) {
this.target = target;
}
public Object invoke(Object proxy, Method method, Object[] args){
Object res =null;
// 向厂家发送订单,告诉厂家,我买了U盘,厂家发货
// 发送给工厂,我需要的订单,返回报价
// float price = factory.sell(amount);
res = method.invoke(target,args); //待执行目标方法,执行后返回值
//增强的方法 res
}
第四步: 使用Proxy类的静态方法,创建代理对象,并把返回值转换成接口类型
创建一个MainShop类.
代码语言:javascript复制public class MainShop {
public static void main(String[] args){
// 1.创建对象,使用Proxy
// 2.创建目标对象
UsbSell factory = new UsbKingFactory();
// 3.创建Invocationhandler对象
InvocationHandler myHandle = new MyHandle(factory);
// 4.创建代理对象
UsbSell proxy = (UsbSell) Proxy.newProxyInstance(factory.getClass().getClassLoader(),
factory.getClass().getInterfaces(),
myHandle);
// 通过代理执行方法
float price = proxy.sell(1);
System.out.println("通过动态代理对象,调用方法:" price);
}
}
JDK动态代理执行流程
我们先复习一下,Proxy类,实现动态代理的流程,使用返回指定接口的代理类实例,
我们此时debug一下程序,在invok实现类中打一个断点
此时我们再观察,代理对象MyHandler里面的invoke方法的参数