Spring之代理模式

news2024/11/28 20:54:57

1、概念

1.1 介绍

二十三种设计模式中的一种,属于结构型模式。它的作用就是通过提供一个代理类,让我们在调用目标方法的时候,不再是直接对目标方法进行调用,而是通过代理类间接调用。让不属于目标方法核心逻辑的代码从目标方法中剥离出来——解耦。调用目标方法时先调用代理对象的方法,减少对目标方法的调用和打扰,同时让附加功能能够集中在一起也有利于统一维护。

在这里插入图片描述
使用代理后:
在这里插入图片描述
②生活中的代理

  • 广告商找大明星拍广告需要经过经纪人
  • 合作伙伴找大老板谈合作要约见面时间需要经过秘书
  • 房产中介是买卖双方的代理
1.2 相关术语
  • 代理:将非核心逻辑剥离出来以后,封装这些非核心逻辑的类、对象、方法。
  • 目标:被代理“套用”了非核心逻辑代码的类、对象、方法。

2 静态代理

    public interface Calculator {
        int add(int i, int j);
        int sub(int i, int j);
        int mul(int i, int j);
        int div(int i, int j);
    }
    package com.giser.java.spring6.calcu.impl;
    
    import com.giser.java.spring6.calcu.Calculator;
    
    /**
     * @author giserDev
     * @description 基础实现
     * @date 2024-01-06 23:41:55
     */
    public class CalculatorImpl implements Calculator {
        @Override
        public int add(int i, int j) {
            int result = i + j;
            System.out.println("方法内部 result = " + result);
            return result;
        }
    
        @Override
        public int sub(int i, int j) {
            int result = i - j;
            System.out.println("方法内部 result = " + result);
            return result;
        }
    
        @Override
        public int mul(int i, int j) {
            int result = i * j;
            System.out.println("方法内部 result = " + result);
            return result;
        }
    
        @Override
        public int div(int i, int j) {
            int result = i / j;
            System.out.println("方法内部 result = " + result);
            return result;
        }
    }

创建静态代理类

    package com.giser.java.spring6.calcu.impl;
    
    import com.giser.java.spring6.calcu.Calculator;
    
    /**
     * @author giserDev
     * @description
     * 提出问题
     *
     * ①现有代码缺陷
     *
     * 针对带日志功能的实现类,我们发现有如下缺陷:
     *
     * - 对核心业务功能有干扰,导致程序员在开发核心业务功能时分散了精力
     * - 附加功能分散在各个业务功能方法中,不利于统一维护
     *
     * ②解决思路
     *
     * 解决这两个问题,核心就是:解耦。我们需要把附加功能从业务功能代码中抽取出来。
     *
     * ③困难
     *
     * 解决问题的困难:要抽取的代码在方法内部,靠以前把子类中的重复代码抽取到父类的方式没法解决。所以需要引入新的技术。
     * @date 2024-01-06 23:43:25
     */
    public class CalculatorLogImpl implements Calculator {
    
        @Override
        public int add(int i, int j) {
    
            System.out.println("[日志] add 方法开始了,参数是:" + i + "," + j);
    
            int result = i + j;
    
            System.out.println("方法内部 result = " + result);
    
            System.out.println("[日志] add 方法结束了,结果是:" + result);
    
            return result;
        }
    
        @Override
        public int sub(int i, int j) {
    
            System.out.println("[日志] sub 方法开始了,参数是:" + i + "," + j);
    
            int result = i - j;
    
            System.out.println("方法内部 result = " + result);
    
            System.out.println("[日志] sub 方法结束了,结果是:" + result);
    
            return result;
        }
    
        @Override
        public int mul(int i, int j) {
    
            System.out.println("[日志] mul 方法开始了,参数是:" + i + "," + j);
    
            int result = i * j;
    
            System.out.println("方法内部 result = " + result);
    
            System.out.println("[日志] mul 方法结束了,结果是:" + result);
    
            return result;
        }
    
        @Override
        public int div(int i, int j) {
    
            System.out.println("[日志] div 方法开始了,参数是:" + i + "," + j);
    
            int result = i / j;
    
            System.out.println("方法内部 result = " + result);
    
            System.out.println("[日志] div 方法结束了,结果是:" + result);
    
            return result;
        }
    }

静态代理的问题:

静态代理确实实现了解耦,但是由于代码都写死了,完全不具备任何的灵活性。就拿日志功能来说,将来其他地方也需要附加日志,那还得再声明更多个静态代理类,那就产生了大量重复的代码,日志功能还是分散的,没有统一管理。

提出进一步的需求:将日志功能集中到一个代理类中,将来有任何日志需求,都通过这一个代理类来实现。这就需要使用动态代理技术了。

3 动态代理

在这里插入图片描述

package com.giser.spring6.calcu.impl.dynamicproxy;

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

/**
 * @author giserDev
 * @description 代理工厂类
 * @date 2024-01-06 23:52:21
 */
public class DynamicProxyFactory {

    /**
     * 被持有的被代理对象
     */
    private Object target;

    public DynamicProxyFactory(Object target) {
        this.target = target;
    }

    /**
     * 创建代理对象
     * @return 代理对象
     */
    public Object getProxy(){
        return Proxy.newProxyInstance(
                // 代理对象的类加载器
                target.getClass().getClassLoader(),
                // 代理对象实现的接口列表
                target.getClass().getInterfaces(),
                // 处理器
                new InvocationHandler() {
                    /**
                     *
                     * @param proxy the proxy instance that the method was invoked on
                     *              代理对象
                     *
                     * @param method the {@code Method} instance corresponding to
                     * the interface method invoked on the proxy instance.  The declaring
                     * class of the {@code Method} object will be the interface that
                     * the method was declared in, which may be a superinterface of the
                     * proxy interface that the proxy class inherits the method through.
                     *               代理对象需要实现的方法
                     *
                     * @param args an array of objects containing the values of the
                     * arguments passed in the method invocation on the proxy instance,
                     * or {@code null} if interface method takes no arguments.
                     * Arguments of primitive types are wrapped in instances of the
                     * appropriate primitive wrapper class, such as
                     * {@code java.lang.Integer} or {@code java.lang.Boolean}.
                     *             method对应的方法参数
                     *
                     * @return
                     * @throws Throwable
                     */
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        Object result = null;
                        try {
                            System.out.println("[动态代理][日志] "+method.getName()+",参数:"+ Arrays.toString(args));
                            result = method.invoke(target, args);
                            System.out.println("[动态代理][日志] "+method.getName()+",结果:"+ result);
                        } catch (Exception e) {
                            e.printStackTrace();
                            System.out.println("[动态代理][日志] "+method.getName()+",异常:"+e.getMessage());
                        } finally {
                            System.out.println("[动态代理][日志] "+method.getName()+",方法执行完毕");
                        }
                        return result;
                    }
                }
        );
    }

}

测试

package com.giser.spring6;

import com.giser.spring6.calcu.Calculator;
import com.giser.spring6.calcu.impl.CalculatorImpl;
import com.giser.spring6.calcu.impl.dynamicproxy.DynamicProxyFactory;

/**
 * @author giserDev
 * @description 动态代理测试
 * @date 2024-01-07 00:02:54
 */
public class DynamicProxyTest {

    public static void main(String[] args) {
        DynamicProxyFactory dynamicProxyFactory = new DynamicProxyFactory(new CalculatorImpl());
        Calculator proxy = (Calculator) dynamicProxyFactory.getProxy();
        int add = proxy.add(1, 3);
    }

}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1365302.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

鸿蒙开发基础运用(ArkTS)-健康生活APP

健康生活应用,主要功能包括: 用户可以创建最多6个健康生活任务(早起,喝水,吃苹果,每日微笑,刷牙,早睡),并设置任务目标、是否开启提醒、提醒时间、每周任务频…

2024拜年祝福视频AE模板31套

做短视频必备的AE模板非常好看,跨年做个视频非常漂亮,喜欢的赶紧保存吧! 链接:https://pan.quark.cn/s/fc1f3db12049

回首2023,厉兵秣马,启航2024

目录 回首风波的20232023,感恩相遇暂停发文发文狂潮感恩有你备战2024学习之余跆拳道比赛做手工diy 学习心路年初学习伊始心路其后学习后来心路 必须看配图说明 未知的2024Flag 回首风波的2023 2023,感恩相遇 还记得,22年末,23年…

Anaconda下载安装与使用

前言 Pandas之所以被称为工具包,原因是Pandas这个工具是由不同的代码模块组成的。每一个代码模块的功能不同,合在一起构成Pandas的丰富功能。其他工具包亦然。 名称描述NumpyNumpy是通用的数值计算工具包,包含大量数学计算函数和矩阵运算函数…

QT应用篇:QT自定义最小化托盘显示和操作

将应用程序最小化到托盘任务栏中,可以使用Qt框架中的QSystemTrayIcon类。该类允许应用程序在关闭窗口后最小化到系统托盘,保持在后台运行,同时可以显示应用程序图标、添加右键菜单功能以及发送消息通知等。通过学习这些技术,能够为自己的Qt应用程序增加更多的交互性和便利性…

3.1 CUDA Thread Organization

在第2章中,数据并行计算,我们学会了编写一个简单的CUDA C程序,该程序启动内核和线程网格,以对一维数组中的元素进行操作。内核指定每个线程执行的C语句。当我们发动如此大规模的执行活动时,我们需要控制这些活动&#…

【书生·浦语大模型实战营02】《轻松玩转书生·浦语大模型趣味Demo》学习笔记

《轻松玩转书生浦语大模型趣味Demo》 教程文档:《轻松玩转书生浦语大模型趣味 Demo文档》 致谢 感谢助教 MINGX 的帮助~ 1、InternLM-Chat-7B 智能对话:生成 300 字的小故事 本节中我们将使用InternLM-Chat-7B 模型部署一个智能对话 Dem…

深入了解static关键字的作用和应用--java面向对象学习

Static修饰成员变量 Static是什么 叫静态,可以修饰成员变量,成员方法 成员变量按有无static修饰分俩种: 类变量:有static修饰,属于类,在计算机里只有一份,会被类的全部对…

Saprk SQL基础知识

一.Spark SQL基本介绍 1.什么是Spark SQL Spark SQL是Spark多种组件中其中一个,主要是用于处理大规模的[结构化数据] Spark SQL的特点: 1).融合性:既可以使用SQL语句,也可以编写代码,同时支持两者混合使用. 2).统一的数据访问:Spark SQL用统一的API对接不同的数据源 3).H…

vueRouter 配合 keep-alive 不生效的问题

文章目录 问题说明案例复现demo 结构问题复现和解决 其实这个不生效的问题根本也不算一个问题,犯的错和写错单词差不多,但是也是一时上头没发现,所以记录一下,如果遇到同样的问题,也希望可以帮助你早点看到这个哭笑不得…

WWDG---窗口看门狗

一.简介 窗口看门狗跟独立看门狗一样,也是一个递减计数器不断的往下递减计数,必须在一个窗口的上限值(用户定义)和下限值(0X40,固定不能变)之间喂狗不会复位,在上限值之前和下限值之…

etcd储存安装

目录 etcd介绍: etcd工作原理 选举 复制日志 安全性 etcd工作场景 服务发现 etcd基本术语 etcd安装(centos) 设置:etcd后台运行 etcd 是云原生架构中重要的基础组件,由 CNCF 孵化托管。etcd 在微服务和 Kubernates 集群中不仅可以作为服务注册…

【hcie-cloud】【18】华为云Stack灾备服务介绍【容灾解决方案介绍、灾备方案架构介绍、管理组件灾备方案介绍、高阶云服务容灾简介、缩略词】【下】

文章目录 灾备方案概述、备份解决方案介绍容灾解决方案介绍华为云容灾解决方案概览云容灾服务云硬盘高可用服务 (VHA)VHA组网结构VHA逻辑组网架构VHA管理组件介绍VHA服务实现原理云服务器高可用服务(CSHA)CSHA物理组网架构CSHA逻辑组网架构CSHA服务组件间…

嵌入式培训机构四个月实训课程笔记(完整版)-Linux系统编程第五天-Linux消息共享内存练习题(物联技术666)

更多配套资料CSDN地址:点赞+关注,功德无量。更多配套资料,欢迎私信。 物联技术666_嵌入式C语言开发,嵌入式硬件,嵌入式培训笔记-CSDN博客物联技术666擅长嵌入式C语言开发,嵌入式硬件,嵌入式培训笔记,等方面的知识,物联技术666关注机器学习,arm开发,物联网,嵌入式硬件,单片机…

2024--Django平台开发-Web框架和Django基础(二)---Mysql多版本共存(Mac系统)

MySQL多版本共存(Mac系统) 想要在Mac系统上同时安装【MySQL5.7 】【MySQL8.0】版本,需要进行如下的操作和配置。 想要同时安装两个版本可以采取如下方案: 方案1:【讲解】 MySQL57,用安装包进行安装。 MyS…

像专家一样使用TypeScript映射类型

掌握TypeScript的映射类型,了解TypeScript内置的实用类型是如何工作的。 您是否使用过Partial、Required、Readonly和Pick实用程序类型? 你知道他们内部是怎么运作的吗? 如果您想彻底掌握它们并创建自己的实用程序类型,那么不要错过本文所涵盖的内容。…

2、Excel:基础概念、表格结构与常见函数

数据来源:八月成交数据 数据初探 业务背景 数据来源行业:金融行业(根据应收利息和逾期金额字段来判断) 可以猜测: 业务主体:某互联网金融公司(类似支付宝)也业务模式:给…

leetcode动态规划问题总结 Python

目录 一、基础理论 二、例题 1. 青蛙跳台阶 2. 解密数字 3. 最长不含重复字符的子字符串 4. 连续子数组的最大和 5. 最长递增子序列 6. 最长回文字符串 7. 机器人路径条数 8. 礼物的最大价值 一、基础理论 动态规划其实是一种空间换时间的基于历史数据的递推算法&…

Java异常机制:从混乱到控制的错误管理艺术

👑专栏内容:Java⛪个人主页:子夜的星的主页💕座右铭:前路未远,步履不停 目录 一、异常的体系结构1、异常的体系结构2、异常的分类 二、异常的处理1、异常的抛出2、异常的捕获2.1、异常声明throws2.2、try-c…

C#中List<T>底层原理剖析

C#中List底层原理剖析 1. 基础用法2. List的Capacity与Count:3.List的底层原理3.1. 构造3.2 Add()接口3.3 Remove()接口3.4 Inster()接口3.5 Clear()接口3.6 Contains()接口3.7 ToArray()接口3.8 Find()接口3.8 Sort()接口 4. 总结5. 参考 1. 基础用法 list.Max() …