代理模式和动态代理:
掌握:代理的作用,动态代理能什么。不用关心技术的实现细节。
后面会将框架,mybatis ,spring 他们都用到了动态代理的概念。
概念:
设计模式:指java中解决某些问题模板。 是前辈经验的总结。用来解决某些问题的。
单例模式, 模板模式等等。
代理模式:当你需要访问一个对象,这个对象因为某种原因不能直接访问,需要通过另一个对象间接访问。
这个间接对象就是代理。这种对象的访问方式就是代理模式的使用。
对象C, 使用A访问C , 正常A可以访问C。 现在C不让A访问,但可以让B访问。
此时A需要访问,借助B实现, A--->B--->C, 此时B代理C的对外访问功能。
B就是A和C之间的代理。
日常生活中的代理:
1.房屋中介
2.代购
3.留学中介。
代理模式作用:
1.增强功能:在通过商场买东西时,可以加价。还可以返红包。
2.控制访问: 控制对目标方法的调用, 用户不能直接访问工厂。
代理模式分类:
1.静态代理:代理类和目标类的关系已经确定的, 在程序执行之前,关系已经确定的。
2.动态代理:在程序执行过程中确定代理和目标关系的,并且能够创建出代理对象。
动态代理中能够创建对象,这是他的重要能力。这个对象是代理对象
静态代理优点: 结构简单,容易理解,代理的目标类是固定的。
静态代理缺点: 1.当目标类比较多,会造成代理类数量庞大,类越多难以管理。
2.当接口中方法有修改,会造成所有的目标类和代理类都发生修改。
静态代理的适用条件:目标类比较少, 代理类也不多。
====================================================================================
动态代理: 使用反射机制创建代理对象。 在程序执行过程中确定代理和目标类的关系。
并创建内存中的代理对象。 通过这个代理对象能调用目标方法并增强功能。
动态代理就是在程序执行时,使用反射机制创建类似TaoBao类,并创建TaoBao类的对象。
这个对象只存在内存中。 实现TaoBao类的功能。
动态代理是创建对象的一种能力。 创建的是代理类的对象。
java中创建对象有哪些方式:
1. 使用new 创建对象
2. 使用反射机制 , Class.forName(“com.wkcto.entity.Student”).newInstance();
3. 使用序列化和反序列化
4. 读取二进制文件
动态代理特点:
1.代理对象(TaoBao)是存在内存中的,不需要写java文件,不需要编译class文件。
这个对象可以使用jdk的方法帮你创建好。
2.可以在程序中,组合目标类,给不同的目标类创建出代理对象。这样你的程序中没有那么多的类了。
3.当目标类的接口发生变化,不影响动态代理对象。
动态代理实现方式:
1.使用jdk中的反射机制实现,叫做jdk动态代理(重点)
2.使用第三方的工具库,叫做cglib。 也叫做cglib动态代理。
cglib创建代理的原理是:继承。 同继承目标类,在子类中重写方法的代理,实现代理类的功能。
这个子类就是代理。 因为cglib使用继承方式,所以目标类不能使用final修饰,方法也不能是final的
使用jdk的反射机制,创建对象(内存中的代理对象):
1.接口InvocationHandler (调用处理器)
调用处理器作用:完成代理对象的功能,也就是代理类要做什么。
具体使用是:定义类实现InvocationHandler 接口,这个接口中就一个方法invoke().
需要重写方法invoke(). 在invoke()方法中,主要作两件事情
1.调用目标方法 ,例如: float price = kingFactory.sell(1000);
2.增强功能,例如 price = price + 25; System.out.println(“TaoBao代理类实现了红包的返现功能”);
例如: class MyInvocation implements InvocationHandler{
public Object invoke(Object proxy, Method method, Object[] args)throws Throwable{
1.调用目标方法 ,例如: float price = kingFactory.sell(1000);
method.invoke(目标对象需要赋值,args)
2.增强功能,例如 price = price + 25; System.out.println("TaoBao代理类实现了红包的返现功能");
}
}
jdk会调用invoke()方法,实现代理类要执行的功能
2.Method类:表示方法的。表示任何的方法。
动态代理,在程序执行时确定目标对象的, 当我们编写invoke()方法时,还不知道目标对象,也不知道目标方法叫什么名字
class OrderService{
private String orderName; //订单名称
public void createOrder(){ //创建订单
}
}
Class clazz = OrderService.class
Method [] method = clazz.getMethod();
Method == createOrder();
java中使用反射机制得到Method,可以表示方法,也可以执行方法。
Method类有一个内部自己的方法invoke().
invoke()格式:
public Object invoke(Object obj, Object… args)
方法的参数说明:Object obj 表示一个java对象 , Method表示obj中一个方法
Object… args:Method表示的方法执行时的实参
怎么使用Method类的invoke()执行目标方法,达到float price = kingFactory.sell(1000);这个方法调用的功能呢。
做法: method.invoke(目标对象,参数)
3.创建代理对象。使用jdk中的静态方法,使用Proxy类的newProxyInstance()方法。
Proxy.newProxyInstacne()方法的作用:使用反射机制创建代理类的对象。就是相当于(TaoBao taobao = new TaoBao() )
方法定义:
public static Object newProxyInstance( ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
使用这三个参数,创建代理对象的。 理解上newProxyInstance就相当于一个工厂,比如这个工厂是生产水果罐头的。
可以桃的罐头, 橘子的罐头等等
生产罐头需要原材料, 方法的参数就是原材料。有哪些材料:
ClassLoader loader:类加载器,目标类的类加载类。找到目标对象,需要使用目标对象的信息。
Class<?>[] interfaces: 目标类实现的接口,需要接口信息。指定接口中的方法。
InvocationHandler h:表示代理类要执行的功能
使用上面的材料,生产出目标对象的代理对象。
实现动态代理的步骤:
1.创建目标类要实现的接口,定义功能
2.创建InvocationHandler接口的实现类,完成代理的功能
3.使用Proxy.newProxyInstacne方法,创建代理对象
4.把3中的代理对象强制转为接口的类型
==============================================================
使用代理购买u判断,请求的流程是:
用户购买—TaoBao代理—访问目标类的方法UsbKingFactory.sell()
注意:通过代理对象才能访问目标方法,执行期望的功能。
动态代理:解决静态代理中类比较多,接口方法修改会影响很多类这些缺点的。
动态代理就是说不能你创建TaoBao这样的类,不用定义TaoBao的java文件。 使用jdk中通过的功能
处理代理类对象, 使用jdk创建一个拥有TaoBao类功能的对象。 而这个对象的创建内部都实现好了。
使用jdk动态代理的实现: jdk动态代理就是使用java.lang.reflect反射包中的类和接口来实现创建对象的能力
1)InvocationHandler接口:调用处理器,访问代理类功能的(1.调用目标类的方法;2.增强功能)
2) Method类:执行目标方法, method.invoke(目标对象,方法参数); 因为动态代理中目标类是不确定的。
只有在程序执行时,才知道目标是谁,
3) Proxy.newProxyInstance: 创建代理对象.
创建代理需要指定的必要信息:
1. 要实现的接口(UsbSell)
2. 目标对象
3. 代理执行的功能代码
================================================================
动态代理底层的实现:
创建对象,必须有的类(class文件) ,通过这个class文件才能创建对象。
jdk的动态代理如何创建代理对象:1)创建类一个class文件;2)使用这个class创建对象
jdk动态代理把上面两个步骤隐藏起来了,不需要过问。
分析:
1) 使用 UsbSell proxy = (UsbSell) Proxy.newProxyInstance(
target.getClass().getClassLoader(),
target.getClass().getInterfaces(),
handler
);
创建的proxy对象是 com.sun.proxy.
P
r
o
x
y
0
这
个
类
型
的
。
也
就
是
相
当
于
Proxy0 这个类型的。 也就是相当于
Proxy0这个类型的。也就是相当于Proxy0 proxy = new …();
proxy是代理, 如果和静态代理对比 proxy应该是 TaoBao taobao =new TaoBao()中的taobao对象
可以看做 proxy == taobao , $Proxy0 和TaoBao 类似的
-
执行方法 taobao.sell(1) 执行的
sell是实现的UsbSell接口中的方法
public float sell(int amount) {
//通过代理访问目标类的方法, 实现卖u盘功能
float price = kingFactory.sell(1000);//代理类需要增加价格,25 增值。
price = price + 25;//代理中给用户返回一个红包。0.1元
System.out.println(“TaoBao代理类实现了红包的返现功能”);
return price;
}
----------------------------------------------------
proxy.sell(1)执行的是 invoke();
public class MyInvocation implements InvocationHandler {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object result= null;
//1.执行目标方法。使用参数Method
result = method.invoke(target,args);//表示执行target目标对象的method方法
//2.增强功能
System.out.println("代理类实现返红包功能");
return result;
}
//目标对象
private Object target;
//传入那个目标,就创建这个目标对象的代理对象
public MyInvocation(Object target) {
this.target = target;
}
}
3.)com.sum.proxy.$Proxy0类的定义, 这个类等同于TaoBao
proxy.sell(1)执行的是 InvocationHandler.invoke()方法
1.类定义 :class $Proxy0 extends Proxy implements UsbSell
2.实现UsbSell接口中的sell()方法
public final float sell(int var1) throws {
try {
return (Float)super.h.invoke(this, m4, new Object[]{var1});
这里执行的是方法调用 super.h.invoke();
super表示父类(Proxy),
h:父类中的一个对象(InvocationHandler)
invoke():应该是h的一个方法
//super.h.invoke() 就是 InvocationHandler.invoke()
} catch (RuntimeException | Error var3) {
throw var3;
} catch (Throwable var4) {
throw new UndeclaredThrowableException(var4);
}
}
总结一下:jdk动态代理
1。jdk创建一个 类叫做
P
r
o
x
y
0
,
实
现
了
U
s
b
S
e
l
l
接
口
2.
创
建
了
Proxy0, 实现了UsbSell接口 2. 创建了
Proxy0,实现了UsbSell接口2.创建了Proxy0类的对象, 叫做proxy
3. 通过代理对象 proxy执行sell方法时。
在sell()方法中会执行 InvocationHandler.invoke()
所有执行sell就是InvocationHandler的invoke()方法。
4.动态代理是创建对象能力,创建的
P
r
o
x
y
0
的
对
象
,
这
个
Proxy0的对象,这个
Proxy0的对象,这个Proxy0相当于是 TaoBao类
动态代理可以创建接口的实现类对象。实现类对象要完成的功能是InvoationHandler的invoke()方法中完成的。
![代理执行图](https://img-blog.csdnimg.cn/20200302150704412.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L0pXNjE0NzE4,size_16,color_FFFFFF,t_70)