第十五章 Spring之假如让你来写AOP——Joinpoint(连接点)篇

news2024/12/29 4:13:11

Spring源码阅读目录

第一部分——IOC篇

第一章 Spring之最熟悉的陌生人——IOC
第二章 Spring之假如让你来写IOC容器——加载资源篇
第三章 Spring之假如让你来写IOC容器——解析配置文件篇
第四章 Spring之假如让你来写IOC容器——XML配置文件篇
第五章 Spring之假如让你来写IOC容器——BeanFactory和FactoryBean
第六章 Spring之假如让你来写IOC容器——Scope和属性填充
第七章 Spring之假如让你来写IOC容器——属性填充特别篇:SpEL表达式
第八章 Spring之假如让你来写IOC容器——拓展篇
第九章 Spring之源码阅读——环境搭建篇
第十章 Spring之源码阅读——IOC篇

第二部分——AOP篇

第十一章 Spring之不太熟的熟人——AOP
第十二章 Spring之不得不了解的内容——概念篇
第十三章 Spring之假如让你来写AOP——AOP联盟篇
第十四章 Spring之假如让你来写AOP——雏形篇
第十五章 Spring之假如让你来写AOP——Joinpoint(连接点)篇
第十六章 Spring之假如让你来写AOP——Pointcut(切点)篇
第十七章 Spring之假如让你来写AOP——Advice(通知)上篇
第十八章 Spring之假如让你来写AOP——Advice(通知)下篇
第十九章 Spring之假如让你来写AOP——番外篇:Spring早期设计
第二十章 Spring之假如让你来写AOP——Aspect(切面)篇
第二十一章 Spring之假如让你来写AOP——Weaver(织入器)篇
第二十二章 Spring之假如让你来写AOP——Target Object(目标对象)篇


文章目录

  • Spring源码阅读目录
    • 第一部分——IOC篇
    • 第二部分——AOP篇
  • 前言
  • 尝试动手写IOC容器
      • 第十七版 Joinpoint(连接点)
  • 总结


前言

    对于Spring一直都是既熟悉又陌生,说对它熟悉吧,平时用用没啥问题,但面试的时候被问的一脸懵逼,就很尴尬,都不好意思在简历上写着熟悉Spring了
在这里插入图片描述

    所以决定花点时间研究研究Spring的源码。主要参考的书籍是:《Spring源码深度解析(第2版)》、《Spring揭秘》、《Spring技术内幕:深入解析Spring架构与设计原理(第2版)》


    书接上回,在上篇 第十四章 Spring之假如让你来写AOP——雏形篇 中,A君 已经完成了初稿,先让 AOP 跑起来。接下来看看 A君 会有什么骚操作吧

尝试动手写IOC容器

    出场人物:A君(苦逼的开发)、老大(项目经理)

    背景:老大要求A君在一周内开发个简单的 IOC容器

    前情提要: A君 完成了初稿,让 AOP 先跑起来了 。。。

第十七版 Joinpoint(连接点)

    “不错,A君,能在这么短的时间内整出个初稿了。” 老大 看着 A君 提交上来的代码说到

    “哪里,哪里?” A君 嘴上谦虚,暗道:“别有但是就行了”

    “但是,Joinpoint(连接点) 需要更细致化的区分,比如说:你这个链式调用,在整个调用链中,可能会有一些共享变量,要将他放在哪里?而且我看你并未实现环绕通知,环绕通知是很特殊的一个通知,它可以甚至修改入参,涉及到修改的时候,不得不谨慎一点了,假如有人在参数数组中添加元素,这时候就会导致整个调用链失败,这也是不得不考虑的部分。” 老大 说到 “拿回去改改吧”

    A君 默然,老大 说的确是有道理,让人没法反驳。不过对于 老大 说的这几个点,也好解决,在执行通知调用链的时候,用个Map保存共享数据即可,至于入参数组与有可能被意外修改。这个就更简单了,clone一份就行了

    思量完毕,A君 定义 ProxyMethodInvocation 接口,代码如下:

public interface ProxyMethodInvocation extends MethodInvocation {
    /**
     * 获取代理对象
     *
     * @return
     */
    Object getProxy();

    /**
     * 复制对象
     *
     * @return
     */
    MethodInvocation invocableClone();

    /**
     * 复制参数
     *
     * @param arguments
     * @return
     */
    MethodInvocation invocableClone(Object... arguments);

    /**
     * 设置参数
     *
     * @param arguments
     */
    void setArguments(Object... arguments);

    /**
     * 设置调用链共享数据
     *
     * @param key
     * @param value
     */
    void setUserAttribute(String key, @Nullable Object value);

    @Nullable
    Object getUserAttribute(String key);
}

接着,让 ReflectiveMethodInvocation 做对应的实现即可,修改如下:

在这里插入图片描述

完整代码如下:

import com.hqd.ch03.v17.aop.ProxyMethodInvocation;
import com.hqd.ch03.v17.aopalliance.intercept.MethodInterceptor;
import com.hqd.ch03.v17.aopalliance.intercept.MethodInvocation;

import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.lang.reflect.AccessibleObject;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 连接点类,用以执行通知及目标方法
 */
public class ReflectiveMethodInvocation implements ProxyMethodInvocation, Cloneable {
    private Object proxy;
    private Object target;
    private Method method;
    private Object[] args;
    private List<? extends MethodInterceptor> mis;
    private Map<String, Object> userAttributes = new HashMap<>();
    private int currentInterceptorIndex = -1;

    public ReflectiveMethodInvocation(Object target, Object proxy, Method method,
                                      Object[] args, List<MethodInterceptor> mis) {
        this.proxy = proxy;
        this.target = target;
        this.method = method;
        this.args = args;
        this.mis = mis;
    }

    @Nonnull
    @Override
    public Method getMethod() {
        return method;
    }

    @Nonnull
    @Override
    public Object[] getArguments() {
        return args;
    }

    @Override
    public void setArguments(Object... arguments) {
        this.args = arguments;
    }

    @Override
    public MethodInvocation invocableClone() {
        Object[] args = this.args.clone();
        return invocableClone(args);
    }

    @Override
    public MethodInvocation invocableClone(Object... arguments) {
        try {
            ReflectiveMethodInvocation clone = (ReflectiveMethodInvocation) clone();
            clone.args = arguments;
            return clone;
        } catch (CloneNotSupportedException e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public void setUserAttribute(String key, @Nullable Object value) {
        this.userAttributes.put(key, value);
    }

    @Nullable
    @Override
    public Object getUserAttribute(String key) {
        return this.userAttributes.get(key);
    }

    @Nullable
    @Override
    public Object proceed() throws Throwable {
        /**
         * 链式调用通知
         */
        if (mis.size() - 1 == currentInterceptorIndex) {
            return getMethod().invoke(target, args);
        }
        MethodInterceptor methodInterceptor = this.mis.get(++currentInterceptorIndex);

        return methodInterceptor.invoke(this);
    }

    @Nullable
    @Override
    public Object getThis() {
        return target;
    }

    @Nonnull
    @Override
    public AccessibleObject getStaticPart() {
        return method;
    }

    @Override
    public Object getProxy() {
        return proxy;
    }


    public Map<String, Object> getUserAttributes() {
        return userAttributes;
    }
}

“没想到 Joinpoint(连接点) 这么简单。” A君 窃喜,今天又能准时下班了。A君 做个简单的测试意思一下,测试代码如下:

  @Test
    public void v17() throws Throwable {

        System.out.println("############# 第十七版  Joinpoint(连接点) #############");

        v16();
    }

在这里插入图片描述

    “搞定,今天真是愉快的一天”

tips:Joinpoint(连接点) 核心在于通知的调用链,这一点整明白了,其他就没什么了

请添加图片描述

总结

    正所谓树欲静而风不止,欲知后事如何,请看下回分解(✪ω✪)

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

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

相关文章

喜讯 | 科东软件荣获广东省工业软件科学技术进步奖一等奖

工业软件是制造业数字化、智能化转型升级的核心支撑&#xff0c;贯穿于工业生产的全过程&#xff0c;包括研发设计、测试&#xff0c;智能装备与操作系统嵌入式&#xff0c;系统与平台&#xff0c;算法、模型与工具等类型。通过开展工业软件科学技术奖评选活动&#xff0c;激励…

SystemVerilog学习笔记(二):数组

数组是元素的集合&#xff0c;所有元素都具有相同的类型&#xff0c;并使用其名称和一个或多个索引进行访问。 Verilog 2001 要求数组的下限和上限必须是数组声明的一部分。 System Verilog 引入了紧凑数组声明样式&#xff0c;只需给出数组大小以及数组名称声明就足够了。 下…

批量从Excel某一列中找到符合要求的值并提取其对应数据

本文介绍在Excel中&#xff0c;从某一列数据中找到与已知数据对应的字段&#xff0c;并提取这个字段对应数值的方法。 首先&#xff0c;来明确一下我们的需求。现在已知一个Excel数据&#xff0c;假设其中W列包含了上海市全部社区的名称&#xff0c;而其后的Y列则是这些社区对应…

握手协议是如何在SSL VPN中发挥作用的?

SSL握手协议&#xff1a;客户端和服务器通过握手协议建立一个会话。会话包含一组参数&#xff0c;主要有会话ID、对方的证书、加密算法列表&#xff08;包括密钥交换算法、数据加密算法和MAC算法&#xff09;、压缩算法以及主密钥。SSL会话可以被多个连接共享&#xff0c;以减少…

数字化转型:基于价值流的业务架构战略解析

在当前数字化浪潮下&#xff0c;企业纷纷转向数字化转型&#xff0c;以适应市场需求的快速变化和技术革新。数字化转型不仅仅是技术层面的变革&#xff0c;更是对企业业务模式、文化以及价值创造方式的全面重新思考和重塑。《价值流&#xff08;Value Streams&#xff09;》为企…

Mac终端字体高亮、提示插件

一、安装配置“oh my zsh” 1.1 安装brew /bin/zsh -c "$(curl -fsSL https://gitee.com/cunkai/HomebrewCN/raw/master/Homebrew.sh)" 按照步骤安装即可&#xff0c;安装完成查看版本 brew -v 1.2 安装zsh brew install zsh 安装完成后查看版本 zsh --version 1.3 …

什么是CRM系统?

越来越多的企业意识到&#xff1a;如何有效管理与客户的关系、提升客户满意度&#xff0c;并通过这些提升推动销售增长&#xff0c;已经成为许多公司亟待解决的问题。为此&#xff0c;客户关系管理&#xff08;Customer Relationship Management&#xff0c;简称CRM&#xff09…

Ilya Sutskever AI行业将进入一个新的“探索时代”

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗&#xff1f;订阅我们的简报&#xff0c;深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同&#xff0c;从行业内部的深度分析和实用指南中受益。不要错过这个机会&#xff0c;成为AI领…

MySQL(5)【数据类型 —— 字符串类型】

阅读导航 引言一、char&#x1f3af;基本语法&#x1f3af;使用示例 二、varchar&#x1f3af;基本语法&#x1f3af;使用示例 三、char 和 varchar 比较四、日期和时间类型1. 基本概念2. 使用示例 五、enum 和 set&#x1f3af;基本语法 引言 之前我们聊过MySQL中的数值类型&…

湾区聚力 开源启智 | 2024 CCF中国开源大会暨第五届OpenI/O启智开发者大会闪耀深圳

当下&#xff0c;全球数字化浪潮席卷而来&#xff0c;开源技术已成为科技创新和产业升级的关键驱动力。11月9-10日&#xff0c;以“湾区聚力 开源启智”为主题的2024 CCF中国开源大会在深圳隆重举行。本届大会由中国计算机学会主办&#xff0c;CCF开源发展委员会、鹏城实验室、…

Linux基本指令(中)(2)

文章目录 前言一、echo二、cat三、more四、less五、head六、tail七、date八、cal九、find十、whoami十一、clear总结 前言 承上启下&#xff0c;我们再来看看另外一些常用的基础指令吧&#xff01; 一、echo 语法&#xff1a;echo [选项] [字符串] 功能&#xff1a;在终端设备上…

MYSQL中JDBC的使用

一、JDBC基础概念 JDBC 是Java 中的一组API&#xff0c;用于执行SQL 操作&#xff08;例如CRUD 操作&#xff1a;增、删、改、关系&#xff09;&#xff0c;同时可以和各种类型的数据库类型进行连接&#xff08;MySQL、Oracle、SQL Server 等&#xff09;。 JDBC是Java标准库的…

UnixBench和Geekbench进行服务器跑分

1 概述 服务器的基准测试&#xff0c;常见的测试工具有UnixBench、Geekbench、sysbench等。本文主要介绍UnixBench和Geekbench。 1.1 UnixBench UnixBench是一款开源的测试UNIX系统基本性能的工具&#xff08;https://github.com/kdlucas/byte-unixbench&#xff09;&#x…

基于Java Springboot人力资源管理系统

一、作品包含 源码数据库设计文档万字全套环境和工具资源部署教程 二、项目技术 前端技术&#xff1a;Html、Css、Js、Vue 数据库&#xff1a;MySQL 后端技术&#xff1a;Java、Spring Boot、MyBatis 三、运行环境 开发工具&#xff1a;IDEA 数据库&#xff1a;MySQL8.0…

使用OpenCV(C++)通过鼠标点击操作获取图像的像素坐标和像素值

使用OpenCV&#xff08;C&#xff09;通过鼠标点击操作获取图像的像素坐标和像素值 在这篇博客中&#xff0c;我们将介绍如何使用OpenCV库在C中实现鼠标点击操作&#xff0c;以获取图像的像素坐标和像素值。代码分为两个部分&#xff1a;一个是鼠标事件处理的回调函数&#xff…

Windows VSCode .NET CORE WebAPI Debug配置

1.安装C#插件 全名C# for Visual Studio Code&#xff0c;选择微软的 2. 安装C# Dev Kit插件 全名C# Dev Kit for Visual Studio Code&#xff0c;同样是选择微软的 3.安装Debugger for Unity 4.配置launch.json 文件 {"version": "0.2.0","config…

AI斩获6枚金牌!华为Kaggle大师级智能体诞生,自主解决数据科学难题

继 OpenAI o1 成为首个达到 Kaggle 特级大师的人工智能&#xff08;AI&#xff09;模型后&#xff0c;另一个 Kaggle 大师级 AI 也诞生了。 根据 Kaggle 的晋级系统&#xff0c;由华为诺亚方舟实验室和伦敦大学学院团队联合推出的端到端自主数据科学智能体&#xff08;agent&a…

[Mysql基础] 表的操作

一、创建表 1.1 语法 CREATE TABLE table_name ( field1 datatype, field2 datatype, field3 datatype ) character set 字符集 collate 校验规则 engine 存储引擎; 说明&#xff1a; field 表示列名 datatype 表示列的类型 character set 字符集&#xff0c;如果没有指定字符集…

04 简单神经网络推导及实现(C++/C)

简单神经网络推导及实现&#xff08;C/C&#xff09; 代码见A simple neural network - stock price prediction as an example(C/C) 1. 主要模块 Neuron.h&#xff1a;用于声明神经元类和构造函数。Layer.h&#xff1a;用于声明网络层类和构造函数。NNet.h&#xff1a;用于…

Mybatis配置文件的增删改查功能

Mybatis配置文件的增删改查功能 查询—条件查询 //resources里面的org.example.mapper中的BrandMapper.xml文件 <?xml version"1.0" encoding"UTF-8" ?> <!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://…