Java的动态代理和静态代理详解

 更新时间:2022年03月07日 11:29:13   作者:v_BinWei_v  
这篇文章主要为大家详细介绍了Python实现学生成绩管理系统,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

0、代理模式

为什么要学习代理模式?这是SpringAOP的底层【SpringAOP和SpringMVC】

代理模式的分类:

  • 静态代理
  • 动态代理

1、静态代理

静态代理中,我们对目标对象的每个方法的增强都是手动完成的(后面会具体演示代码_),非常不灵活(比如接口一旦新增加方法,目标对象和代理对象都要进行修改)且麻烦(_需要对每个目标类都单独写一个代理类)。 实际应用场景非常非常少,日常开发几乎看不到使用静态代理的场景。

角色分析:

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

代码步骤:

1、接口

public interface Rent {
    public void rent();
}

2、真实角色

//房东
public class Host implements Rent {
    public void rent() {
        System.out.println("房东要租房子");
    }
}

3、代理角色

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

4、客服端访问代理角色

public class Client {
    public static void main(String[] args) {
        Host host = new Host();
        //代理,代理角色一般会有附属操作!
        Proxy proxy = new Proxy(host);
        proxy.rent();
    }
}

代理模式的好处:

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

缺点:

一个真实角色会产生一个代理角色;从JVM角度来看,静态代理在编译时就将接口、实现类、代理类这些都变成了一个个实际的class文件。

2、 加深理解

AOP,的底层代理模式

在这里插入图片描述

3、动态代理

  • 动态代理和静态代理角色一样
  • 动态代理的代理类是动态生成的,不是我们直接写好的!
  • 动态代理分为两大类:基于接口的动态代理,基于类的动态代理
    • 基于接口——JDK动态代理
    • 基于类:cglib动态代理
    • java字节码实现:javasist

需要了解两个类:Proxy: 代理类,InvocationHandler : 调用处理程序

从 JVM 角度来说,动态代理是在运行时动态生成类字节码,并加载到 JVM 中的。

//Proxy是生成动态代理类,提供了创建动态代理类和实例的静态方法,它也是由这些方法创建的所有动态代理类的超类。
//InvocationHandler-- invoke 调用处理程序并返回接口, 是由代理实例的调用处理程序实现的接口 。

动态代理的好处:

  • 可以使真实角色的操作更加纯粹!不用去关系一些公共的业务
  • 公共也就交给代理角色!实现
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h){
}

1.loader :类加载器,用于加载代理对象。

2.interfaces : 被代理类实现的一些接口;

3.h : 实现了 InvocationHandler 接口的对象;

要实现动态代理的话,还必须需要实现InvocationHandler 来自定义处理逻辑。 当我们的动态代理对象调用一个方法时,这个方法的调用就会被转发到实现InvocationHandler 接口类的 invoke 方法来调用。

public interface InvocationHandler {
    Object invoke(Object proxy, Method method, Object[] args) throws Throwable;
}

1.proxy :动态生成的代理类

2.method : 与代理类对象调用的方法相对应

3.args : 当前 method 方法的参数

动态代理的例子

1、定义接口

public interface Rent {
    public void rent();
}

2、实现租房的接口

public class Host implements Rent {
    @Override
    public void rent() {
        System.out.println("房东要租房");
    }
}

3、定义一个JDK动态代理类

public class DebugInvocationHandler implements InvocationHandler {
    /**
     * 代理类中的真实对象
     */
    private final Object target;
    public DebugInvocationHandler(Object target){
        this.target = target;
    }
    /**
     * 当你使用代理对象调用方法的时候实际会调用到这个方法
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        //调用方法前
        System.out.println("before method" + method.getName());
        Object res = method.invoke(target, args);
        //调用方法后
        System.out.println("after method" + method.getName());
        return res;
    }
}

invoke() 方法: 当我们的动态代理对象调用原生方法的时候,最终实际上调用到的是 invoke() 方法,然后 invoke() 方法代替我们去调用了被代理对象的原生方法。

4、获取代理对象的工厂类

public class JdkProxyFactory {
    public static Object getProxy(Object target){
        return Proxy.newProxyInstance(
                target.getClass().getClassLoader(),
                target.getClass().getInterfaces(),
                new DebugInvocationHandler(target)
        );
    }
}

getProxy() :主要通过Proxy.newProxyInstance()方法获取某个类的代理对象

5、实际使用

public static void main(String[] args) {
        //Rent rent = new Host();
        //Rent rentProxy= (Rent) Proxy.newProxyInstance(rent.getClass().getClassLoader(), rent.getClass().getInterfaces(),new DebugInvocationHandler(rent));
        Rent rentProxy = (Rent)JdkProxyFactory.getProxy(new Host());
        rentProxy.rent();
    }

运行上述代理的输出

before methodrent
房东要租房
after methodrent

总结

本篇文章就到这里了,希望能够给你带来帮助,也希望您能够多多关注脚本之家的更多内容!    

相关文章

  • 使用jmx exporter采集kafka指标示例详解

    使用jmx exporter采集kafka指标示例详解

    这篇文章主要为大家介绍了使用jmx exporter采集kafka指标示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-11-11
  • Java前后端时间格式的转化方式

    Java前后端时间格式的转化方式

    这篇文章主要介绍了Java前后端时间格式的转化方式,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-08-08
  • 使用ObjectMapper把Json转换为复杂的实体类

    使用ObjectMapper把Json转换为复杂的实体类

    这篇文章主要介绍了使用ObjectMapper把Json转换为复杂的实体类操作,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-08-08
  • java+mysql实现登录和注册功能

    java+mysql实现登录和注册功能

    这篇文章主要为大家详细介绍了java+mysql实现登录和注册功能,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-04-04
  • SpringBoot中的Logging详解

    SpringBoot中的Logging详解

    这篇文章主要介绍了SpringBoot中的Logging详解,log配置可能是被忽视的一个环节,一般的项目中日志配置好了基本上很少去改动,我们常规操作是log.info来记录日志内容,很少会有人注意到springBoot中日志的配置,需要的朋友可以参考下
    2023-09-09
  • Json 自定义使用函数的简单实例

    Json 自定义使用函数的简单实例

    下面小编就为大家带来一篇Json 自定义使用函数的简单实例。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2016-10-10
  • AOP之事务管理<aop:advisor>的两种配置方式

    AOP之事务管理<aop:advisor>的两种配置方式

    这篇文章主要介绍了AOP之事务管理<aop:advisor>的两种配置方式,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-11-11
  • 如何写好一个Spring组件的实现步骤

    如何写好一个Spring组件的实现步骤

    这篇文章主要介绍了如何写好一个Spring组件的实现步骤,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-06-06
  • 详解Java双轴快速排序算法

    详解Java双轴快速排序算法

    在排序算法中,快速排序是占比非常多的一环,但是快速排序其思想一直被考察研究,也有很多的优化方案。这里主要讲解双轴快速排序的思想和实现
    2021-06-06
  • java 解析由String类型拼接的XML文件方法

    java 解析由String类型拼接的XML文件方法

    今天小编就为大家分享一篇java 解析由String类型拼接的XML文件方法,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2018-07-07

最新评论