前所未有的文章,Java代理模式终极篇!

什么是动态代理

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

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

动态代理 在程序运行的过程中,由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();
    }
}

代理模式简单理解

我用两个例子来比喻:
1、可以将代理对象理解为中介。租房子的时候大家通过中介,来租到对应的房子,最终住房子的人还是你来住,中介仅仅负责一个传达,中间商的作用。
2、大家应该都知道Nginx的反向代理,同样都是代理,你访问Nginx时,访问的是代理服务器,不是真实服务器,由代理服务器根据你自定义的反向代理规则,进行请求转发,代理服务器帮你传递一些东西。
·················································································
eg:这里我本来举的例子是那个什么什么,中国的网和外国的网,懂吧,但是呢,官方不给我通过,只能换了个例子啦。其实,是很奇怪的,我第一次发,带有那两个字,但是通过了,之后发就不可以了,所以这个审核是人工审核,还是关键字审核。

if("关键字审核"){
sout("为什么,第一次通过了");
}else("人工审核"){
sout("那劳动量也太大了吧,而且第一个人给我通过了,哈哈");
}

其实我可以在评论去下边写这两个字,哈哈哈哈哈。你们说是什么词语啊。兄弟们给我打在公屏上!^ _ ^。
·················································································

静态与动态的区别

静态代理

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

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

缺点:

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

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

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

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

动态代理

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

优点:

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

动态代理与静态代理区别

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

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

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

举个小例子

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

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

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

你学废了吗?

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值