Spring中静态代理与动态代理的实现及区别对比分析

 更新时间:2025年12月09日 11:43:30   作者:沓然  
文章介绍了静态代理和动态代理的区别,静态代理通过在编译时生成代理类来实现对真实对象的代理,而动态代理通过反射机制在运行时生成代理类,更加灵活,两者都实现了对真实对象功能的扩展,但动态代理更为高效,适用于需要代理大量对象的情况,感兴趣的朋友跟随小编一起看看吧

Spring中静态代理与动态代理的区别

前言

代理模式在Java中特别常见,如spring AOP功能就是用代理来实现的。代理模式作用是:在不修改被代理对象功能的基础上,通过对代理类进行扩展,进行一些功能上的附加与增强。
一般使用代理模式我们需要先定义一个接口,静态代理只是一种简单的java代码功能扩展。而动态代理利用了反射机制,使用更简单。

无论是静态代理还是动态代理,都有四大角色:

  1. 抽象角色:一般会使用接口或者抽象类来解决
  2. 真实角色:被代理的角色
  3. 代理角色:代理真实角色,代理真实角色后,我们一般会做一些附属操作
  4. 客户:访问代理对象的人

静态代理(中介租房案例)

首先,定义一个接口(Rent),房东类(Host)实现该接口,并输出自己房子的相关信息。

//租房
public interface Rent {
    public  void rent();
}
//房东
public class Host implements Rent{
    public void rent() {
        System.out.println("我的房子是蓝色的,准备出租房子!");
    }
}

房东将房子交给中介,此时的中介相当于代理类,故创建代理类(Proxy),代理类在不修改被代理对象功能的基础上(Host类的rent方法),可以对代理类进行扩展,进行一些功能上的附加与增强(增加seeHouse、hetong、fare方法)。

public class Proxy implements Rent{
    private Host host;
    public Proxy(){ }
    public Proxy(Host host){
        this.host=host;
    }
    public void rent() {
        seeHouse();
        host.rent();
        hetong();
        fare();
    }
    //看房
    public void seeHouse(){
        System.out.println("中介带你看房子");
    }
    //签合同
    public void hetong(){
        System.out.println("签合同");
    }
//    收费
    public void fare(){
        System.out.println("收中介费");
    }
}

客户购房不用面对房东,只需与中介对接。

public class Client {
    public static void main(String[] args) {
        Host host=new Host(); //房东要出租房子
        //代理,中介帮房东租房子,但是代理角色一般会有一些附属操作
        Proxy proxy=new Proxy(host);
        //客户不用面对房东,直接找中介租房即可
        proxy.rent();
    }
}

上述代码就实现了静态代理,客户只需面向代理类操作即可。

运行截图:

静态代理的优点:

  1. 可以使真实角色的操作更加纯粹,不用去关注一些公共的业务
  2. 公共也就交给代理角色,实现了业务的分工
  3. 业务发生扩展的时候,方便集中管理

静态代理的缺点:

  1. 一个真实角色就会产生一个代理角色,代码量会翻倍,开发效率变低。

动态代理

静态代理中,每个真实对象都会拥有一个代理类,这样将会十分繁琐,采用动态代理将会解决这种问题!我们在上述的中介租房案例中进行修改。

首先创建一个Rent接口,并创建两个房东类实现Rent接口。

//租房
public interface Rent {
    public  void rent();
}
//房东1
public class Host implements Rent {
    public void rent() {
        System.out.println("我的房子是蓝色的,准备出租房子!");
    }
}
//别的房东
public class Host_other implements Rent{
    public void rent() {
        System.out.println("我的房子是红色的,准备出租房子!");
    }
}

如果采用静态代理,我们将要编写两个代理类,当房东数量很大时,这种处理方法明显不妥,因此我们可以编写一个代理工具类,该类并未指明代理的真实对象是哪一个,相当于我们之前学Java时编写的Math类(完成某种特定的计算过程)。

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
//我们会用这个类自动生成代理类
public class ProxyInvocationHandler implements InvocationHandler {
    //被代理的接口
    private Object target;
    public void setTarget(Object target){
        this.target=target;
    }
    //生成得到代理类
    public Object getProxy(){
        return Proxy.newProxyInstance(this.getClass().getClassLoader(),target.getClass().getInterfaces(),this);
    }
    //处理代理实例,并返回结果
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        //动态代理的本质,就是使用反射机制实现
        seeHouse();
        Object result=method.invoke(target,args);
        fare();
        return result;
    }
    public void seeHouse(){
        System.out.println("中介带你看房子");
    }
    public void fare(){
        System.out.println("收中介费");
    }
}

其中的target变量,就是未来客户类传入的真实对象。很明显,动态代理也能在不改变原有业务代码的基础上,实现对功能的扩展(seeHouse等方法的加入)。

在客户类中,只需new多个代理工具类,并为他们传入相应的真实对象,就可以获取各个真实对象的rent方法。

public class Client {
    public static void main(String[] args) {
        //真实角色
        Host host=new Host();
        //代理角色:现在没有
        ProxyInvocationHandler pih=new ProxyInvocationHandler();
        //通过调用程序处理角色来处理我们要调用的接口对象!
        pih.setTarget(host);
        Rent proxy=(Rent)pih.getProxy();//这里的proxy就是动态生成的,我们并没有写这个类
        proxy.rent();
        System.out.println("--------------------------");
        //真实角色
        Host_other host_other=new Host_other();
        //代理角色:现在没有
        ProxyInvocationHandler pih1=new ProxyInvocationHandler();
        //通过调用程序处理角色来处理我们要调用的接口对象!
        pih1.setTarget(host_other);
        Rent proxy1=(Rent)pih1.getProxy();//这里的proxy1就是动态生成的,我们并没有写这个类
        proxy1.rent();
    }
}

运行结果见下图:

动态代理的好处:

  1. 可以使真实角色的操作更加纯粹,不用去关注一些公共的业务
  2. 公共业务就交给代理角色,实现了业务分工
  3. 公共业务发生扩展的时候,方便集中管理
  4. 一个动态代理类代理的是一个接口,一般就是对应的一类业务(多个类实现同一个接口,只要重写方法,客户端可以通过修改代理的真实对象来实现动态的代理)
  5. 多个房东同时卖房,他们的房子信息不一样,如果采用静态代理,需要为他们各自写一个代理类,就十分麻烦。我们可以采用动态代理的方法,让这些房东同时实现一个接口(Rent),这样我们在客户类只需要修改代理的真实对象,就可以得到每个房东各自的房子信息。

总结

无论是静态代理还是动态代理,都符合下面几个步骤:

  1. 创建接口
  2. 创建真实角色并实现接口
  3. 创建代理类
  4. 客户类访问代理角色

不同的是静态代理需要为每个真实对象创建一个代理类,而动态代理只用为同一类业务创建一个代理工具类即可。

到此这篇关于Spring中静态代理与动态代理的实现及区别的文章就介绍到这了,更多相关Spring静态代理与动态代理内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Mybatis使用foreach标签实现批量插入方式

    Mybatis使用foreach标签实现批量插入方式

    这篇文章主要介绍了Mybatis使用foreach标签实现批量插入方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2024-03-03
  • Java接收xml格式参数转为json的方法

    Java接收xml格式参数转为json的方法

    文章主要介绍了如何使用JAXB将XML格式的参数接收并转换为Java实体类,然后将实体类转换为JSON格式,文中提到在实体类中使用`@XmlElement`和`@JsonProperty`注解的重要性,以及如何处理复杂的XML结构
    2024-11-11
  • SpringBoot中间件ORM框架实现案例详解(Mybatis)

    SpringBoot中间件ORM框架实现案例详解(Mybatis)

    这篇文章主要介绍了SpringBoot中间件ORM框架实现案例详解(Mybatis),本篇文章提炼出mybatis最经典、最精简、最核心的代码设计,来实现一个mini-mybatis,从而熟悉并掌握ORM框架的涉及实现,需要的朋友可以参考下
    2023-07-07
  • 简单了解JavaBean作用及常用操作

    简单了解JavaBean作用及常用操作

    这篇文章主要介绍了简单了解JavaBean作用及常用操作,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-05-05
  • Java源码解析之GenericDeclaration详解

    Java源码解析之GenericDeclaration详解

    这篇文章主要介绍了Java源码解析之GenericDeclaration详解。有句古话说得好,源码能使人快乐!这里分享给大家,供需要的朋友参考。
    2017-10-10
  • Java 数组详解及示例代码

    Java 数组详解及示例代码

    本文主要介绍Java 数组的知识,这里整理了数组所有操作方法,并一一列举,有学习的朋友可以参考下
    2016-09-09
  • 在Java中将List转换为String输出过程解析

    在Java中将List转换为String输出过程解析

    这篇文章主要介绍了在Java中将List转换为String输出过程解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2019-09-09
  • java 单例模式的实例详解

    java 单例模式的实例详解

    这篇文章主要介绍了java 单例模式的实例详解的相关资料,希望通过本文能帮助大家彻底理解掌握这部分内容,需要的朋友可以参考下
    2017-10-10
  • 在Java中实现可见性(visibility)的主要方法详解

    在Java中实现可见性(visibility)的主要方法详解

    这篇文章主要介绍了在Java中实现可见性(visibility)的主要方法详解,在Java中,使用关键字volatile和使用锁(如synchronized关键字或 java.util.concurrent包中的锁)来确保对共享变量的修改在多线程环境中能够正确地被其他线程所观察到,需要的朋友可以参考下
    2023-08-08
  • Spring Data JPA例子代码[基于Spring Boot、Mysql]

    Spring Data JPA例子代码[基于Spring Boot、Mysql]

    这篇文章主要介绍了Spring Data JPA例子代码[基于Spring Boot、Mysql],小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2018-04-04

最新评论