代理是一种设计模式,它提供了另一种访问目标对象的方式。本文主要介绍Java中的三种代理模式。有需要的朋友可以参考一下,希望能帮到你。
目录
什么是代理?给我举个栗子?什么是代理模式?如何实现代理?静态代理?根据以上流程,分析静态剂的优缺点。动态代理CGLIB代理jdk代理InvocationHandler接口方法类代理类JDK动态代理实现步骤摘要
什么是代理
举个栗子
比如有一所美国大学,可以招收世界各地的学生。但是对于家长来说,家长不能直接去学校,家长不能直接去学校参观,或者美国学校不接受个人参观,那么就需要一个留学中介来帮助这个美国学校招生。
学生,中介是学校的代理人。和中介学校要做的一样:招生。对于家长来说,学校是目标,学习代理是代理。日常生活中,代理的例子很多,代购、房产中介、各种中介、ip交易所、商家、厂家、买家。发展中
也有同样的情况。例如,如果你有一个类A,你应该调用类C的方法来完成某个函数。但是C不让打电话。A-不能调用C的方法,直接在A和C中创建一个B代理,C让B访问。甲参观乙参观丙.
原始访问关系
通过代理的访问关系
什么是代理模式
百度百科
代理模式是指为其他对象提供代理,以控制对该对象的访问。在某些情况下,一个对象不适合或者不能直接引用另一个对象,代理对象可以充当客户端类和目标对象之间的中介。
换句话说,代理对象用于在不修改目标对象的情况下加强主要业务逻辑。客户端类真正想访问的对象是目标对象,但客户端类真正能访问的对象是代理对象。客户端对目标对象的访问是通过访问代理对象来实现的。
是的。当然,代理类和目标类应该实现相同的接口。
实现代理的方式
静态代理
静态代理是指程序运行前代理类为已经定义好.java 源文件,与目标类的关系在程序运行前就已经确立不同。在程序运行之前,代理类已经被编译成一个. class文件。
以静态代理为例。
需求:用户需要购买u盘,u盘厂商不接受单独零散购买。厂家规定一次购买至少1000个u盘,用户可以通过淘宝代理商或者微信商家购买。对于淘宝上的商品,微商是u盘厂的代理商,他们代理u盘的销售。
服务。用户-代理商(淘宝、微信商家)-U盘厂商(金士顿、三迪等不同厂商)
1、定义业务接口
定义业务接口UsbSell(目标接口),包含抽象方法sell(int amout);卖出是目标方法。
公共接口UsbSell {
/**
*表示功能,制造商和商家必须完成该功能。
* @param金额
* @返回
*/
float sell USB(int amount);
}
2、定义接口的实现类
目标UsbKingFactory Kingston USB闪存盘,实现接口。
导入school . x UAT . service . USB sell;
公共类UsbKingFactory实现UsbSell {
@覆盖
/**
*定义金士顿制造商的销售价格。
*/
公共浮动销售Usb(内部账户){
返回75.0f
}
}
3、定义代理
淘宝是代理类,给厂商卖u盘。
导入school . x UAT . factory . usbkingfactory;
导入school . x UAT . service . USB sell;
公共类淘宝实现UsbSell {
//声明哪家厂商是商家的代理。
private UsbSell factory=new usbking factory();
@覆盖
/**
*实现出售u盘的功能。
*/
公共浮动销售Usb(内部账户){
浮动价格=factory . sell USB(account);
//代理增强功能
价格=25;
退货价格;
}
}
魏也是一家代理销售u盘的厂家。
导入school . x UAT . factory . usbkingfactory;
导入school . x UAT . service . USB sell;
公共类尚维实现UsbSell {
//声明哪家厂商是商家的代理。
private UsbSell factory=new usbking factory();
@覆盖
公共浮动sellUsb(int amount) {
浮动价格=factory.sellUsb(金额);
//代理增强功能
价格=15;
退货价格;
}
}
4、客户端调用者,购买商品类
客户可以通过淘宝和尚维代理商购买u盘。
导入school . xau at . business . Taobao;
导入school . xau at . business . weishang;
公共类ShopMain {
公共静态void main(String[] args) {
淘宝淘宝=新淘宝();
浮动价格=Taobao . sell USB(1);
System.out.println(价格);
尚维尚维=新尚维();
float price 2=weishang . sell USB(1);
system . out . println(price 2);
}
}
根据以上过程,分析静态代理的优缺点
优点:实现简单,容易理解。
缺点:
代码复杂,难于管理
代理类和目标类实现同一个接口,每个代理都需要实现目标类的方法,这就导致了大量的代码重复。如果一个方法被添加到接口中,那么除了所有目标类之外,所有代理类都需要实现这个方法。这增加了代码维护的复杂性。
代理类依赖目标类,代理类过多
如果您想要服务于多种类型,代理只服务于一种类型的目标类。需要对每个目标类进行代理,但是在程序规模稍大的情况下,静态代理无法胜任,代理类太多。
动态代理
动态代理是指JVM在程序运行时根据反射机制动态生成的代理类对象。动态代理不需要定义。代理类的java源文件。
实际上,动态代理就是在jdk运行过程中动态创建类字节码并加载到JVM中。
实现动态代理有两种常见的方法:使用 JDK 动态代理(这里主要讲),和使用 CGLIB 动态代理。
CGLIB代理
CGLIB(代码生成库)是一个开源项目。是一个功能强大、高性能、高质量的代码生成类库,可以在运行时扩展Java类,实现Java接口。它被很多AOP框架广泛使用,比如Spring AOP。使用JDK
Proxy实现proxy,要求目标类和代理类实现同一个接口。如果目标类没有接口,它就不能以这种方式实现。然而,对于没有接口的类,要为它们创建一个动态代理,应该使用CGLIB。CGLIB代理的生成原理是生成目标类的子类,而
子类得到了增强,这个子类对象就是代理对象。因此,使用CGLIB生成动态代理,要求目标类必须能够被继承,即不能是final类。Cglib常用于框架中,如Spring、Hibernate等。Cglib的代理效率高于Jdk。正确
它不用于cglib的一般开发。只是做个理解。
JDK代理
基于Java反射机制实现了Jdk动态代理。使用jdk中的接口和类实现代理对象的动态创建。Jdk的动态性要求目标对象必须实现接口,这是java设计的要求。从jdk1.3开始,java语言通过java.lang.reflect包提供了三个类。
支持代理模式Proxy, Method 和InovcationHandler。
InvocationHandler接口
调用处理程序接口称为调用处理程序,负责调用目标方法并增强其功能。通过对象执行接口中方法的替换,方法将被分配给InvocationHandler的实现类,实现类中的I将被执行。
Nvke()方法,我们需要在invoke()方法中编写功能代理。
invoke方法可以拦截对目标方法的调用。这里的功能得到了增强。Java的动态代理是基于反射机制的。实现InvocationHandler接口的类用于增强目标类的主要业务逻辑。这个接口中有一个方法invoke(),专门添加了
这种方法定义了强代码逻辑。当通过代理对象执行接口中的方法时,会自动调用invoke()方法。
invoke()方法的介绍如下:
public Object invoke ( Object proxy, Method method, Object[] args)
proxy:代表生成的代理对象
method:代表目标方法
args:代表目标方法的参数
第一个参数proxy由jdk在运行时分配,并直接在方法中使用。后面介绍第二个参数,第三个参数是方法执行的参数。这三个参数由jdk在运行时分配,不需要程序员给出。
Method类
invoke()方法的第二个参数是方法类对象,它有一个名为invoke()的方法,可以调用目标方法。这两个invoke()方法虽然名称相同,但并不相关。
公共对象调用(对象对象,对象.参数)
Obj:表示目标对象
Args:指示目标方法参数,这是它上面的invoke方法的第三个参数。
方法用于调用obj对象所属类的方法,该方法由其调用方方法对象决定。
在代码中,一般的写法是
method.invoke(target,args);
其中method是上一层的invoke方法的第二个参数。这样就可以调用目标类的目标方法。
Proxy类
通过JDK的java.lang.reflect.Proxy类,动态代理会由它的静态方法newProxyInstance()根据目标对象、业务接口、调用处理器自动生成。
公共静态new proxy instance(Class loader loader,Class?[]接口,InvocationHandler处理程序)
Loader:目标类的类加载器,可以通过目标对象的反射获得。
Interfaces:由目标类实现的接口数组,可以通过目标对象的反射获得。
处理程序:调用处理器。
jdk动态代理的实现步骤
Jdk动态代理是代理模式的实现,只能代理接口。
实施步骤
1、新建一个接口,作为目标接口
2、为接口创建一个实现类,是目标类
3、创建类实现 java.lang.reflect.InvocationHandler 接口,调用目标方法并增加其他功能代码
4、创建动态代理对象,使用 Proxy.newProxyInstance()方法,并把返回值强制转为接口类型。
举个例子
1.创建一个目标接口并定义其功能。
2.为接口创建一个实现类。
以上两个步骤与静态代理相同。
3.创建InvocationHandler接口的实现类,调用目标方法,添加其他代码函数。
导入Java . lang . reflect . invocation handler;
导入Java . lang . reflect . method;
公共类MySellHandler实现InvocationHandler {
//目标对象
私有对象target=null
public MySellHandler(对象目标){
this.target=target
}
@覆盖
/**
*实现InvocationHandler接口的实现类,完成invoke方法中代理类的功能。
*-调用目标方法
*-功能增强
*/
公共对象调用(对象代理、方法方法、对象[]参数)抛出Throwable {
对象结果=null
result=method.invoke(target,args);
//功能增强
//这里为了简化,我们把功能增强定义为加价25元。
如果(结果!=null){
浮动价格=(浮动)结果;
价格=价格25;
结果=价格;
}
返回结果;
}
}
这里的目标对象相当于静态代理中的淘宝和尚维。
4.模拟客户购买u盘,使用proxy.newProxyInstance创建代理对象,返回值为目标接口类型。
导入school . x UAT . factory . usbkingfactory;
导入school . x UAT . handler . my sell handler;
导入school . x UAT . service . USB sell;
导入Java . lang . reflect . invocation handler;
导入Java . lang . reflect . proxy;
公共类MainShop {
公共静态void main(String[] args)引发异常{
//创建目标对象
Class c=UsbKingFactory.class
object obj=c . new instance();
//获取目标类的类加载器
class loader loader=usbking factory . class . getclass loader();
//获取目标类实现的接口数组
班级?[]interfaces=obj.getClass()。get interfaces();
//创建InvocationHandler对象
invocation handler=new mysell handler(obj);
//创建代理对象
UsbSell proxy=(UsbSell)proxy . newproxyinstance(loader,interfaces,handler);
//通过此代理执行方法
浮动价格=proxy . sell(1);
System.out.println(价格);
}
}
静态代理
动态代理
UML图
总结
本文到此为止。希望能帮到你,也希望你能多关注我们的更多内容!
郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。