欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

学习Java代理模式,一篇就足够够了!

程序员文章站 2022-07-03 11:34:56
什么是动态代理动态代理,就是在不修改源码的情况下,对方法进行增强.静态代理 需要开发者手动编写代理类,实现对目标类的增强动态代理 在程序运行的过程中,由JVM虚拟机动态创建出代理对象,我们可以对代理对象进行控制,对其方法进行增强。动态代理的原理动态代理需要代理类和目标类实现同一个接口动态代理基于反射动态代理中最灵魂的一步通过代理对象,基于反射调用目标对象的方法。method.invoke(xiaoWang,args) ;动态代理的组成代理对象目标对象动态代理的实现...

什么是动态代理

动态代理,就是在不修改源码的情况下,对方法进行增强.

静态代理 需要开发者手动编写代理类,实现对目标类的增强

动态代理 在程序运行的过程中,由JVM虚拟机动态创建出代理对象,我们可以对代理对象进行控制,对其方法进行增强。

动态代理的原理

  • 动态代理需要代理类和目标类实现同一个接口
  • 动态代理基于反射

动态代理中最灵魂的一步

通过代理对象,基于反射调用目标对象的方法。

method.invoke(xiaoWang,args) ;

动态代理的组成

代理对象

目标对象

动态代理的实现

  • 动态代理的实现技术

      1. jdk 2. cglib
  • 动态代理的实现步骤

    • 创建接口
    • 创建目标类和目标对象
    • 创建代理对象 ,没有代理类
    • 调用代理对象的方法,代理成功
  • 动态代理具体实现

    • Proxy工具类介绍

      static Object newProxyInstance( ClassLoader loader, Class<?>[] interfaces, InvocationHandler h);

      三个参数

      第一个参数 loader 目标类(对象)的加载器

      ​ xiaoWang.getClass().getClassLoader()

      第二个参数 interfaces 目标类(对象)的接口数组

      ​ xiaoWang.getClass().getInterfaces()

      第三个参数 h : 处理器接口,在这个参数中,对目标方法进行增强。

      ​ 两种方法

      ​ 一:匿名内部类

      ​ 二:Lambda表达式

      ​ 动态代理增强的仅仅是方法。

      ​ 实现第三个参数时,需要重写invoke方法,在invoke方法中对目标方法增强

      ​ Object invoke(Object proxy, Method method, Object[] args)

      ​ 第一个参数 proxy 工具类生产的代理对象,xiaozhe

      ​ 第二个参数 method 当前执行的方法的对象,基于反射

      ​ 第三个参数 args 当前执行方法的参数数组

@Test
public void versi() throws Exception {
    // 1.创建目标对象
    XiaoWang xiaoWang = new XiaoWang();
    // 2.通过Proxy工具类生产代理类和创建代理对象
    DancerInterface xiaozhe = (DancerInterface) Proxy.newProxyInstance(xiaoWang.getClass().getClassLoader(), xiaoWang.getClass().getInterfaces(), new InvocationHandler() {
    
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            // 当前执行的方法名
            // System.out.println(method.getName());
            // 当前执行方法的参数
            // System.out.println(Arrays.toString(args));
            // 前置增强
            if ("dance".equals(method.getName())) {
                System.out.println("小哲去工作了");
            }
            // 由代理对象调用目标对象方法
            // method的意思是方法,它是方法对象
            Object result = method.invoke(xiaoWang, args);
 			
            // 后置增强
            if ("dance".equals(method.getName())) {
                result = "小王回到了家里," + result;
            }
            // 代理对象将结果返回给调用者
            return result;
        }
    });
    // 3.调用方法
    // 目标对象方法,不进行加强,简简单单的就相当于xiaoWang执行了这个方法.
    // String result = xiaoWang.dance("香泽菠菜");
    // 代理对象方法,已增强.
    String result = xiaozhe.dance("香泽菠菜");
    // 看看代理和不代理的区别
    System.out.println(result);
}

最终一定是代理对象执行方法,通过反射机制,在代理对象增强方法的内部method,最终仍然是目标对象执行目标对象的原方法,增强的功能是在invoke里增强的.

代理对象调用方法时,内部共分为三个步骤

1、执行增强功能。

2、目标对象执行目标对象方法。

2、执行增强功能.即前置增强或者后置增强。

package com.qinghong.test;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class verwu {

    public static void main(String[] args) {

	 //	不使用代理增强
     //	Dancer dancer = new Xiaoqiang();
     //	dancer.dance();

        
     //  静态代理,Xiaozhe是自定义代理类,静态代理,两份代码同时写。
     //  Dancer dancer = new Xiaozhe();
     //  dancer.dance();

    
    //动态代理,动态的创建代理对象,不需要写实体代理类。
       // 创建目标对象
        Dancer dancer = new Xiaoqiang();
       /* 创建代理对象时要注意:
        	1、方法中传的三个参数,代理对象要跟目标对象在类加载器上和接口数组上保持一致,所以传的类加载器和接口数组都是目标对象的。
            2、类加载器,通过类加载器表明代理对象由哪个类加载器加载,要选用跟目标对象一样的类加载器,目标对象的类加载器,别装成猪了,你要装人。
            3、接口数组,通过跟目标对象一模一样的接口数组,你要装别人,你起码得知道别人长啥样,有啥衣服(方法)吧。
            4、处理器接口,增强的业务逻辑。*/
        Dancer xiaozhe = (Dancer)Proxy.newProxyInstance(dancer.getClass().getClassLoader(), dancer.getClass().getInterfaces(), new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                //代理对象中,如何调用目标对象的方法。
                //你们猜,这个method是个啥玩意。
                System.out.println("你去卖烧烤吧");
                //这个方法,包含很多东西啊。
                Object obj = method.invoke(dancer, args);
                System.out.println("我不去");
                
                //方法对象有方法名,代理对象和目标对象是一个方法。
                //本质为让目标对象在这里调用它目标对象的方法.(重点!!!)
                //为什么代理对象执行这个方法就会发生反射?
                /*因为代理对象的这个方法就是在创建代理对象的过程中编写的
                执行这个方法时,自然要跑到上边创建代理对象的invoke方法中
                代理对象内部有一个大大的空间,这个空间里边有目标对象执行它目标对象方法的语句.
                代理对象类内部,动态代理没有物理上的代理类,需要虚拟代理类和目标类实现同一接口,创建代理对象时参数中前两个参数都是反射的基本条件。*/
                return obj;
            }
        });
        //代理对象调用方法
        xiaozhe.dance();
    }
}

代理模式简单理解

代理对象就是把被代理对象包装一层,在其内部做一些额外的工作,比如用户需要上facebook,而普通网络无法直接访问,网络代理帮助用户先*,然后再访问facebook。这就是代理的作用了。

远程代理:我们在国内因为GFW,所以不能访问 facebook,我们可以用*(设置代理)的方法访问。访问过程是:
(1)用户把HTTP请求发给代理。
(2)代理把HTTP请求发给web服务器。
(3)web服务器把HTTP响应发给代理。
(4)代理把HTTP响应发回给用户。

静态与动态的区别

静态代理

​ 由程序员创建代理类或特定工具自动生成源代码再对其编译,在程序运行前代理类的.class文件就已存在.

优点:代理使客户端不需要知道具体的实现类是什么,怎么做的,只需要知道代理即可(解耦合)

缺点:

​ 1.目标类实现了这个方法,代理类也得实现这个方法,代码重复.

如果接口增加一个方法,所有的实现类都需要重写这个方法(这个接口不可能专门为一个实现类为一个方法所定制,它肯定有多个实现类),所有的代理类也需要重写这样的方法,增加了代码维护的复杂度.

​ 2.代理对象只服务于一种类型的对象,如果要服务多类型的对象,势必要为每一种对象都进行代理,静态代理在程序规模稍大时就无法胜任了.如果还要为其他类提供代理的话,就需要我们再次添加其他代理类.

​ 即静态代理类只能为特定的接口(Service)服务,如想要为多个接口服务则需要建立很多个代理类,想办法通过一个代理类完成全部的代理功能,就需要用动态代理。

动态代理

​ 在程序运行时运用反射机制动态创建而成,在程序运行时,通过反射机制实现动态代理,并且能够代理各种类型的对象。JAVA程序我们遵循OCP(对扩展开放,对修改关闭)原则(开闭原则),并且是AOP思想的实践。

优点:

​ 动态代理与静态代理相比较,最大的好处是接口中声明的所有方法都被转移到调用处理器一个集中的方法中处理(InvocationHandler.invoke).这样在接口方法数量比较多的时候,我们可以进行灵活处理,而不需要像静态代理那样每一个方法进行中转.而且动态代理的应用使我们的类职责更加单一,复用性更强.

动态代理与静态代理区别

​ 使用上: 静态代理需要手动书写代理类

​ 功能上:静态代理代理一个类型,动态代理代理好多个类型

动态代理和静态代理实际业务区别

举个小例子

静态代理,代理类实现的这个接口中的每一个方法都需要添加日志记录代码

动态代理,只需要对invoke()方法中添加日志记录代码就可以完成对每一个方法添加日志记录.

·················································································

你学废了吗?

本文地址:https://blog.csdn.net/numbbe/article/details/109271061