欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 新闻 > 焦点 > 【了解一下静态代理与动态代理】

【了解一下静态代理与动态代理】

2024/10/28 23:28:51 来源:https://blog.csdn.net/weixin_44585177/article/details/143256657  浏览:    关键词:【了解一下静态代理与动态代理】

文章目录

    • 一.什么是静态代理与动态代理
    • 二.静态代理
    • 三.动态代理
      • 1.jdk动态代理
      • 2.cglib动态代理
    • 四.小结

一.什么是静态代理与动态代理

什么是代理?代理是一种设计模式,在这种模式中,一个类(代理类)代表另一个类(目标类)进行操作。代理类控制对目标类的访问,并可能添加额外的功能,如权限检查、日志记录、延迟加载、缓存、事务处理等。

  1. 静态代理
  • 定义:静态代理是在编译时创建的代理类,由开发者手动定义代理类,不会随着程序运行时的条件改变而变化,适用于在类的行为不变的情况下,可以增加一些额外的功能。
  • 特点:
    1.代理类在编译阶段就已经存在。
    2.代理类需要实现与目标类相同的接口,并在接口方法中调用目标类的相应方法。
    3.代码量较多,需手动编写代理类,增加了开发成本。
  • 优点:实现简单,直接创建代理类即可。
  • 缺点:每个类都需要一个代理类,导致代码冗余,难以维护。不适合大量类的代理需求。
  1. 动态代理
  • 定义:代理类在运行时动态生成,通常使用反射机制或第三方库(如JDK动态代理、CGLIB)。动态代理允许在运行时改变代理行为,通常更灵活。
  • 特点:
    1.不需要为每个代理类手动创建代理类,而是通过反射在运行时动态创建代理对象。
    2.代理类可以处理实现多个接口的目标类。
  • 优点:可以复用代理逻辑,减少代码冗余。适合需要代理多个类或方法的场景。
  • 缺点:
    1.需要通过反射实现,性能相对较低。
    2.仅适用于接口的代理,若目标类未实现接口,需要使用CGLIB等第三方库来实现。

在这里插入图片描述
静态代理需要手动创建代理类,适用于简单、固定的代理需求。动态代理通过反射在运行时动态生成代理对象,适合复杂和可复用的代理需求,灵活性更高。

我们可以把静态代理和动态代理的概念映射到租房的场景中,分别对比“找固定的中介租房”和“通过中介平台动态分配中介租房”这两种情况。

二.静态代理

在静态代理中,我们找了一个中介A来帮忙找房子。中介A提供了一系列的服务,比如筛选房源、安排看房、签约等。这个中介的流程是固定的,我们每次找中介A租房的时候,中介A都按照它们规定的流程执行。

1.类比说明:

  • 我们(Renters,租房者):客户,想要租到合适的房子。
  • 房东(Landlord,真实的出租者):拥有房源,真实的目标对象。
  • 中介A(LandlordProxy):静态代理角色,由于我们每次都找同一家中介,这家中介在编译时就明确了自己的代理流程,不会临时调整。

2.静态代理流程:

  1. 我们找到固定的中介A,希望租房。
  2. 中介A开始按固定流程代理我们完成租房:筛选房源、安排带看、签合同等。
  3. 我们通过中介A租到了房子。

3.静态代理的缺点:
如果我们之后需要不同的服务,比如希望找到不收中介费的中介B,又或者找专门提供短租的中介C,那我们就得找不同的中介,并为每个中介创建单独的代理对象,增加了复杂度,不够灵活。

对上述场景用静态代理代码实现:
假设有一个房东类和一个中介代理类,静态代理需要手动创建代理类来完成租房的代理服务。

public interface Rent {// 定义租房接口void rentHouse();
}/*** 房东A(真实的出租者),实现租房接口*/
public class LandlordA implements Rent {@Overridepublic void rentHouse() {System.out.println("房东A待出租的房子");}
}/*** 中介A*/
public class LandlordAProxy implements Rent {// 中介有房东信息private final LandlordA landlordA = new LandlordA();@Overridepublic void rentHouse() {System.out.println("中介带租客看房源信息");// 调用房东的租房方法landlordA.rentHouse();System.out.println("中介带我们跟房东处理租赁合同");}
}/*** 我们(打工人):租房者*/
public class Renters {public static void main(String[] args) {System.out.println("我是租客,找到中介..");// 创建代理LandlordProxy agency = new LandlordProxy();// 通过代理租房agency.rentHouse();}
}

输出结果:

  • 我是租客,找到中介…
  • 中介带租客看房源信息
  • 房东A待出租的房子
  • 中介带我们跟房东处理租赁合同

缺点就是我想换中介了,又得写一套静态代理逻辑,代码量大。

三.动态代理

在动态代理中,我们没有选择某一个固定的中介,而是通过一个中介平台下单。这个中介平台可以根据我们的需求,自动匹配一个合适的中介来帮忙租房。我们只需告诉平台需求,平台会动态地分配一个代理人,而我们并不关心具体是哪个中介代理的,只关注服务结果。

1.类比说明:

  • 我们(Renters,租房者):客户,目标是找到合适的房源。
  • 房东(Landlord,真实的出租者):拥有房源,真实的目标对象。
  • 中介平台(JdkDynamicProxyPlatform/CglibDynamicProxyPlatform):动态代理角色,平台会根据需求实时生成合适的代理人。

2.动态代理流程:

  1. 我们将租房需求提交到中介平台,平台在运行时根据需求生成适合的代理人。
  2. 代理人动态匹配房源、安排看房和签约等代理流程。
  3. 我们通过中介平台成功租到合适的房子。

3.动态代理的优点
动态代理可以根据需求灵活匹配代理流程,比如选择是否提供带看服务、是否收取中介费等,无需手动创建代理类。这种方式适合租房需求多变的场景。

动态代理又分为jdk动态代理、cglib动态代理

1.jdk动态代理

JDK代理,也称为基于接口的动态代理,是Java动态代理的一种实现方式,它要求被代理的对象必须实现一个或多个接口。JDK代理主要利用了java.lang.reflect.Proxy类和java.lang.reflect.InvocationHandler接口来生成代理对象。
当你通过JDK代理创建代理对象时,你需要提供一个实现了InvocationHandler接口的类,该类中的invoke方法会拦截并处理所有通过代理对象调用的方法。Proxy类则负责生成代理类的实例。

/*** JDK动态代理租房平台*/
public class JdkDynamicProxyPlatform implements InvocationHandler {// 中介有房东信息private final LandlordA target = new LandlordA();@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {System.out.println("中介带租客看房源信息");// 调用房东的租房方法Object result = method.invoke(target, args);System.out.println("中介带我们跟房东处理租赁合同");return result;}/*** 定义获取代理对象方法*/public Object getLandlordProxy(){//JDK动态代理只能针对实现了接口的类进行代理,newProxyInstance函数所需参数就可看出return Proxy.newProxyInstance(target.getClass().getClassLoader(),target.getClass().getInterfaces(),this);}
}/*** 我们(打工人):租房者*/
public class Renters {public static void main(String[] args) {System.out.println("我是租客,找到JdkDynamicProxyPlatform中介平台..");// 动态生成代理对象Rent agency = (Rent)new JdkDynamicProxyPlatform().getLandlordProxy();// 通过动态代理租房agency.rentHouse();}
}

输出结果:

  • 我是租客,找到JdkDynamicProxyPlatform中介平台…
  • 中介带租客看房源信息
  • 房东A待出租的房子
  • 中介带我们跟房东处理租赁合同

2.cglib动态代理

CGLIB(Code Generation Library)动态代理的原理是基于字节码生成,通过创建目标类的子类()来实现代理。它使用ASM(一个操作字节码的框架)在运行时动态生成子类字节码,从而实现对方法的拦截和增强。
CGLIB通过Enhancer类生成目标类的子类,目标类的方法会被重写,代理逻辑插入在调用前后。

/*** 房东B(不实现接口的目标类)*/
public class LandlordB {public void rentHouse() {System.out.println("房东B待出租的房子");}
}/*** Cglib动态代理租房平台*/
public class CglibDynamicProxyPlatform implements MethodInterceptor {// 创建代理对象的方法public Object getLandlordProxy() {Enhancer enhancer = new Enhancer();// 设置代理类的父类enhancer.setSuperclass(LandlordB.class);// 设置回调函数enhancer.setCallback(this);// 创建代理对象return enhancer.create();}/*** 拦截方法,加入代理逻辑*/@Overridepublic Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {System.out.println("中介带租客看房源信息");// 调用目标类的方法Object result = proxy.invokeSuper(obj, args);System.out.println("中介带我们跟房东处理租赁合同");return result;}
}/*** 我们(打工人):租房者*/
public class Renters {public static void main(String[] args) {System.out.println("我是租客,找到CglibDynamicProxyPlatform中介平台..");// 动态生成代理对象LandlordB landlordBAgency = (LandlordB) new CglibDynamicProxyPlatform().getLandlordProxy();// 通过动态代理租房landlordBAgency.rentHouse();}
}

输出结果:

  • 我是租客,找到CglibDynamicProxyPlatform中介平台…
  • 中介带租客看房源信息
  • 房东B待出租的房子
  • 中介带我们跟房东处理租赁合同

总结:
JDK动态代理只能代理实现了接口的类,生成的代理对象类型是接口类型。CGLIB代理可以代理任何类,包括没有实现接口的类。生成的代理对象类型是目标类的子类类型。

四.小结

主要介绍下静态代理、jdk动态代理、cglib动态代理,上一篇文章讲Spring声明式事务聊了很多cglib动态代理,做下补充jdk动态代理和静态代理。

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com