当前位置: 首页 > article >正文

Java的动态代理(实际案例秒懂!)

在看动态代理解决两个案例之前,请先看链接VCR

《java代理》2分钟动画_哔哩哔哩_bilibili

一.动态代理-精致小案例

需求分析

传统方法

就是定义一个接口,然后实现类去实现规定的run方法

缺点:代码很冗余,有一些运行前和运行后的代码都给了实现类,难以管理

 

 动态代理方法

使用动态代理,利用反射机制,根据方法决定调用哪个对象的方法

添加VehicleProxyProvider类

package me;


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

/**
 * @version 1.0
 * VehicleProxyProvider 该类可以返回一个代理对象.
 */
public class VehicleProxyProvider {

    //定义一个属性
    //target_vehicle 表示真正要执行的对象
    //该对象实现了Vehicle接口
    private Vehicle target_vehicle;

    //构造器
    public VehicleProxyProvider(Vehicle target_vehicle) {
        this.target_vehicle = target_vehicle;
    }

    //编写一个方法,可以返回一个代理对象, 该代理对象可以通过反射机制调用到被代理对象的方法
    public Vehicle getProxy() {

        //得到类加载器
        ClassLoader classLoader =
                target_vehicle.getClass().getClassLoader();

        //得到要代理的对象/被执行对象 的接口信息,底层是通过接口来完成调用
        Class<?>[] interfaces = target_vehicle.getClass().getInterfaces();


        //创建InvocationHandler 对象
        //因为 InvocationHandler 是接口,所以我们可以通过匿名对象的方式来创建该对象
        /**
         *
         * public interface InvocationHandler {
         *  public Object invoke(Object proxy, Method method, Object[] args)
         *         throws Throwable;
         * }
         * invoke 方法是将来执行我们的target_vehicle的方法时,会调用到
         *
         */

        InvocationHandler invocationHandler = new InvocationHandler() {
            /**
             * invoke 方法是将来执行我们的target_vehicle的方法时,会调用到
             * @param o 表示代理对象
             * @param method 就是通过代理对象调用方法时,的哪个方法 代理对象.run()
             * @param args : 表示调用 代理对象.run(xx) 传入的参数
             * @return 表示 代理对象.run(xx) 执行后的结果.
             * @throws Throwable
             */
            @Override
            public Object invoke(Object o, Method method, Object[] args)
                    throws Throwable {

                System.out.println("交通工具开始运行了....");
                //这里是我们的反射基础 => OOP
                //method 是?: public abstract void com.hspedu.spring.proxy2.Vehicle.run()
                //target_vehicle 是? Ship对象
                //args 是null
                //这里通过反射+动态绑定机制,就会执行到被代理对象的方法
                //执行完毕就返回
                Object result = method.invoke(target_vehicle, args);
                System.out.println("交通工具停止运行了....");
                return result;
            }
        };

        /*

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

          老师解读
          1. Proxy.newProxyInstance() 可以返回一个代理对象
          2. ClassLoader loader: 类的加载器.
          3. Class<?>[] interfaces 就是将来要代理的对象的接口信息
          4. InvocationHandler h 调用处理器/对象 有一个非常重要的方法invoke
         */
        Vehicle proxy =
                (Vehicle) Proxy.newProxyInstance(classLoader, interfaces, invocationHandler);

        return proxy;
    }
}

最重要的代码就是 :

Proxy.newProxyInstance(classLoader, interfaces, invocationHandler);

这是提供最后代理对象实例的方法:参数有三:

        @你要求代理对象的类加载器

        @你要求代理对象的接口信息

        @以及调用处理器

底层是用反射机制来实现的。

测试方法:

public class VehicleProxyTest {
    @Test
    public void test01()
    {
        Vehicle vehicle = new Ship();
        //传入我们需要代理的对象
        VehicleProxyProvider vehicleProxyProvider = new VehicleProxyProvider(vehicle);
        //获取代理对象
        Vehicle proxy = vehicleProxyProvider.getProxy();
        //通过代理对象执行对应的run()方法
        proxy.run();
    }
}

以及真正的运行结果:
 

 真正解析这个代码

所谓的这个代理,就可以将我们的Vehicle接口看做是一个老板。我们的car类和ship类就是员工。现在老板给这两个员工一个run的工作,但是因为在run工作的前后他们都要输出相同的一句话。这个输出同一句话没必要让每个员工都写一遍,于是就把这个输出同一句话的事情交给了一个代理对象,帮我们输出这句话。代理对象就是老板的助理。

 


这个代码提供代理对象的类:

当你调用proxy.run()方法的时候:会进入到调用器InvocationHandler的invoke方法去

这个调用器中的Object o就是你传入的ship对象,method就是run()方法,arg就是run()里面的参数。

Object result = method.invoke(target_vehicle, args);

方法.invoke(对象)这是反射调用对象ship的run()方法。返回一个结果,

 可以自己去debug一下这个代码。

二.动态代理的深入[横切关注点]

需求分析

 

传统的方法

定义接口:

package proxy;

/**
 * @version 1.0
 * 接口
 */
public interface SmartAnimalable {
    //求和
    float getSum(float i, float j);
    //求差
    float getSub(float i, float j);
}

 传统的实现子类

package proxy;

/**
 * @version 1.0
 */
public class SmartDog implements SmartAnimalable {
    @Override
    public float getSum(float i, float j) {
        //System.out.println("日志-方法名-getSum-参数 " + i + " " + j);
        float result = i + j;
        System.out.println("方法内部打印result = " + result);
        //System.out.println("日志-方法名-getSum-结果result= " + result);
        return result;
    }

    @Override
    public float getSub(float i, float j) {
        //System.out.println("日志-方法名-getSub-参数 " + i + " " + j);
        float result = i - j;
        System.out.println("方法内部打印result = " + result);
        //System.out.println("日志-方法名-getSub-结果result= " + result);
        return result;
    }
}

结果:

 

动态代理的方法 

MyProxyProvider

package proxy;

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

/**
 * @version 1.0
 * 可以返回一个动态代理对象, 可以执行SmartDog对象的方法
 */
public class MyProxyProvider {

    //定义我们要执行的目标对象, 该对象需要实现SmartAnimalable
    private SmartAnimalable target_obj;

    //构造器
    public MyProxyProvider(SmartAnimalable target_obj) {
        this.target_obj = target_obj;
    }

    //方法, 可以返回代理对象,该代理对象可以执行目标对象
    public SmartAnimalable getProxy() {

        //1. 先到的类加载器/对象
        ClassLoader classLoader = target_obj.getClass().getClassLoader();

        //2. 得到要执行的目标对象的接口信息
        Class<?>[] interfaces = target_obj.getClass().getInterfaces();

        //3. 创建InvocationHandler
        InvocationHandler invocationHandler = new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                Object result = null;
                try {
                    System.out.println("方法执行前-日志-方法名-" + method.getName() + "-参数 "
                            + Arrays.asList(args)); //这里从AOP看,就是一个横切关注点-前置通知
                    //使用反射调用方法
                    result = method.invoke(target_obj, args);
                    System.out.println("方法执行正常结束-日志-方法名-" + method.getName() + "-结果result= "
                            + result);//从AOP看, 也是一个横切关注点-返回通知

                } catch (Exception e) {
                    e.printStackTrace();
                    //如果反射执行方法时,出现异常,就会进入到catch{}
                    System.out.println("方法执行异常-日志-方法名-" + method.getName()
                            + "-异常类型=" + e.getClass().getName());//从AOP看, 也是一个横切关注点-异常通知
                } finally {//不管你是否出现异常,最终都会执行到finally{}
                    //从AOP的角度看, 也是一个横切关注点-最终通知
                    System.out.println("方法最终结束-日志-方法名-" + method.getName());
                }

                return result;
            }
        };

        //创建代理对象
        SmartAnimalable proxy =
                (SmartAnimalable)Proxy.newProxyInstance(classLoader, interfaces, invocationHandler);
        return proxy;
    }
}

 Test方法

  @Test
    public void smartDogTestByProxy() {

        SmartAnimalable smartAnimalable = new SmartDog();

        MyProxyProvider myProxyProvider =
                new MyProxyProvider(smartAnimalable);

        //我们返回了代理对象
        SmartAnimalable proxy =
                myProxyProvider.getProxy();

        proxy.getSum(10, 2);
        System.out.println("====================");
        proxy.getSub(10, 2);

    }


http://www.kler.cn/a/286408.html

相关文章:

  • 智慧园区系统助力企业智能化升级实现管理效率与安全性全方位提升
  • 【开源免费】基于SpringBoot+Vue.JS公交线路查询系统(JAVA毕业设计)
  • floodfill算法(6题)
  • 计算机网络 (60)蜂窝移动通信网
  • Haproxy入门学习二
  • 【UE插件】Sphinx关键词语音识别
  • 【Unity】简单机甲运动系统——坦克式操控方式
  • 前后端分离的security角色权限实现
  • 在 macOS 上升级 Ruby 版本的几种方法
  • Linux 常用命令 - hexdump 【以指定格式显示文件内容】
  • 【UE5】控件蓝图——树视图(TreeView)的基本使用
  • 2024国赛数学建模备战:灰色预测,国赛数学建模思路代码 模型
  • hive学习(六)
  • 【大模型】GPT系列模型基础
  • 讯鹏科技智慧公厕专业供应商,解读智慧公厕有哪些奥秘
  • 【Spring Boot 3】【Web】文件下载
  • 盘点2024年4款可以免费使用的视频压缩软件。
  • 如何打造Java SpringBoot宿舍设备管理系统,全程跟踪设备使用周期,2025最新设计指南
  • 量化投资策略与技术学习PART8:量化选股之趋势追踪
  • 【数据结构】二叉树基础(带你详细了解二叉树)
  • GPU服务器与CPU服务器的不同之处
  • 37次8.27(docker03)
  • 我的sql我做主!Mysql 的集群架构详解之组从复制、半同步模式、MGR、Mysql路由和MHA管理集群组
  • QPS提升10倍怎么设计-JAVA后端经常用到的技术
  • tomcat 调优
  • Python爬虫案例五:将获取到的文本生成词云图