[{"data":1,"prerenderedAt":6283},["ShallowReactive",2],{"search-docs":3,"doc-\u002Fother\u002Fspring-series\u002Fspring\u002Fspring-aop":886},[4,8,12,16,20,24,28,32,36,40,44,48,52,56,60,64,68,72,76,80,84,88,92,96,100,104,108,112,116,120,124,128,132,136,140,144,148,152,156,159,162,165,169,172,175,178,182,186,190,194,198,202,206,210,214,218,222,226,230,234,238,242,246,250,254,258,262,266,269,273,277,281,285,288,291,294,298,301,304,307,310,313,316,319,322,325,329,332,336,340,344,348,352,356,359,362,365,368,371,374,377,380,383,386,389,393,396,399,402,405,408,411,414,417,420,424,428,432,435,438,442,446,450,454,458,462,466,470,474,477,480,483,487,491,494,497,500,504,507,511,515,518,521,524,527,530,533,536,539,542,545,548,551,554,557,560,563,566,569,572,575,579,583,587,591,595,599,603,606,610,614,617,620,623,626,629,633,637,640,643,646,649,652,655,658,661,664,667,670,673,676,679,682,685,688,691,694,697,700,703,706,709,712,716,720,724,728,732,736,740,744,748,752,756,760,764,768,772,775,779,783,787,790,793,796,799,802,805,808,811,814,818,822,825,829,832,835,838,841,844,848,851,854,858,862,865,869,873,876,879,882],{"path":5,"title":6,"description":7},"\u002Fabout\u002Fauthor","作者相关","只想纯粹的做一个程序员...",{"path":9,"title":10,"description":11},"\u002Fabout\u002Fjourney","心路历程","",{"path":13,"title":14,"description":15},"\u002Fai\u002Fagent\u002Fframeworks","Agent 框架","主流 Agent 框架：LangChain、LlamaIndex、AutoGen、CrewAI",{"path":17,"title":18,"description":19},"\u002Fai\u002Fagent\u002Fhooks","Agent Hooks 与自动化","Claude Agent 的 Hooks 生命周期、事件类型、典型自动化场景",{"path":21,"title":22,"description":23},"\u002Fai\u002Fagent\u002Fintroduction","AI Agent 概述","AI Agent 核心概念：感知、规划、执行、记忆",{"path":25,"title":26,"description":27},"\u002Fai\u002Fagent\u002Fpractice","Agent 实战","AI Agent 实战：构建自主任务执行系统",{"path":29,"title":30,"description":31},"\u002Fai\u002Fagent\u002Fsdk","Claude Agent SDK 开发","使用 Claude Agent SDK 构建自定义 AI Agent：架构、API、生命周期",{"path":33,"title":34,"description":35},"\u002Fai\u002Fagent\u002Fsubagents","Subagents 子代理","用 Subagents 分解复杂任务、并发执行、隔离上下文",{"path":37,"title":38,"description":39},"\u002Fai\u002Fagent\u002Ftool-use","工具调用","AI Agent 工具调用：Function Calling、Tool Use 原理与实践",{"path":41,"title":42,"description":43},"\u002Fai\u002Ffundamentals\u002Fdeep-learning","深度学习入门","深度学习基础知识：前向传播、反向传播、损失函数、优化器",{"path":45,"title":46,"description":47},"\u002Fai\u002Ffundamentals\u002Fml-basics","机器学习基础","机器学习核心概念：监督学习、无监督学习、强化学习",{"path":49,"title":50,"description":51},"\u002Fai\u002Ffundamentals\u002Fneural-networks","神经网络原理","神经网络架构：CNN、RNN、注意力机制",{"path":53,"title":54,"description":55},"\u002Fai\u002Fgetting-started","AI 学习路线","AI 技术学习路线图，从基础到实战的完整指南",{"path":57,"title":58,"description":59},"\u002Fai\u002Fllm\u002Ffine-tuning","模型微调","大模型微调技术：LoRA、QLoRA、全量微调、RLHF",{"path":61,"title":62,"description":63},"\u002Fai\u002Fllm\u002Fintroduction","大模型概述","大语言模型发展历程、核心能力与主流模型对比",{"path":65,"title":66,"description":67},"\u002Fai\u002Fllm\u002Flocal-deploy","本地部署","大模型本地部署：Ollama、vLLM、llama.cpp",{"path":69,"title":70,"description":71},"\u002Fai\u002Fllm\u002Ftransformer","Transformer 架构","Transformer 架构详解：自注意力机制、位置编码、多头注意力",{"path":73,"title":74,"description":75},"\u002Fai\u002Fmcp\u002Fclient","MCP Client 开发","MCP Client 开发指南：连接、调用、集成",{"path":77,"title":78,"description":79},"\u002Fai\u002Fmcp\u002Fdebugging","MCP 调试与排错","MCP Server 开发与集成过程中的常见问题、日志分析、诊断工具",{"path":81,"title":82,"description":83},"\u002Fai\u002Fmcp\u002Fintroduction","MCP 概述","Model Context Protocol 协议概述：架构、核心概念、应用场景",{"path":85,"title":86,"description":87},"\u002Fai\u002Fmcp\u002Fserver","MCP Server 开发","MCP Server 开发指南：资源、工具、提示词的实现",{"path":89,"title":90,"description":91},"\u002Fai\u002Fmcp\u002Ftools","MCP Tools 深入","深入理解 MCP Tools：与 Resources\u002FPrompts 的差异、Schema 设计、Annotations 与权限控制",{"path":93,"title":94,"description":95},"\u002Fai\u002Fprompt\u002Fadvanced","高级 Prompt 模式","高级 Prompt 设计模式：Tree-of-Thought、自我反思、多轮对话策略",{"path":97,"title":98,"description":99},"\u002Fai\u002Fprompt\u002Fbasics","Prompt 基础","Prompt Engineering 入门：基本概念、角色设定、输出格式控制",{"path":101,"title":102,"description":103},"\u002Fai\u002Fprompt\u002Ftechniques","提示词技巧","常用提示词技巧：Few-shot、Chain-of-Thought、ReAct",{"path":105,"title":106,"description":107},"\u002Fai\u002Frag\u002Fembedding","文本嵌入","文本嵌入模型：Embedding 原理、模型选择、相似度计算",{"path":109,"title":110,"description":111},"\u002Fai\u002Frag\u002Fintroduction","RAG 概述","检索增强生成（RAG）架构原理、优势与应用场景",{"path":113,"title":114,"description":115},"\u002Fai\u002Frag\u002Fpractice","RAG 实战","RAG 应用实战：文档问答系统、知识库搭建",{"path":117,"title":118,"description":119},"\u002Fai\u002Frag\u002Fvector-database","向量数据库","主流向量数据库对比：Milvus、Pinecone、Chroma、Weaviate",{"path":121,"title":122,"description":123},"\u002Fai\u002Fskills\u002Fbest-practices","Skill 最佳实践","编写高质量 Skill 的设计原则、常见陷阱与优化技巧",{"path":125,"title":126,"description":127},"\u002Fai\u002Fskills\u002Fcreating","创建自定义 Skill","从零编写一个可被 Agent 自动发现和调用的 Skill",{"path":129,"title":130,"description":131},"\u002Fai\u002Fskills\u002Fintroduction","Agent Skills 概述","Claude Agent Skills 概念、工作原理、与 Tools\u002FMCP 的区别",{"path":133,"title":134,"description":135},"\u002Fgolang\u002Fadvanced\u002Fconcurrency","Go - 并发深入","深入理解 Go 并发编程的核心机制。",{"path":137,"title":138,"description":139},"\u002Fgolang\u002Fadvanced\u002Fgc","Go - 垃圾回收","理解 Go 的垃圾回收机制，掌握 GC 调优方法。",{"path":141,"title":142,"description":143},"\u002Fgolang\u002Fadvanced\u002Fgmp","Go - GMP 调度模型","GMP 是 Go 运行时调度器的核心模型，理解它对于编写高性能 Go 程序至关重要。",{"path":145,"title":146,"description":147},"\u002Fgolang\u002Fadvanced\u002Fgo-concurrency","Go - 并发编程","Go 的并发是其核心特性之一，通过 Goroutine 和 Channel 实现。",{"path":149,"title":150,"description":151},"\u002Fgolang\u002Fadvanced\u002Fmemory","Go - 内存模型","理解 Go 的内存分配机制和内存模型。",{"path":153,"title":154,"description":155},"\u002Fgolang\u002Fadvanced\u002Fprofiling","Go - 性能分析","掌握 Go 的性能分析工具：pprof、trace、benchmark。",{"path":157,"title":158,"description":11},"\u002Fgolang\u002Fcore\u002Fgo-basic","Go - 基础语法",{"path":160,"title":161,"description":11},"\u002Fgolang\u002Fcore\u002Fgo-composite","Go - 复合类型",{"path":163,"title":164,"description":11},"\u002Fgolang\u002Fcore\u002Fgo-control","Go - 流程控制",{"path":166,"title":167,"description":168},"\u002Fgolang\u002Fcore\u002Fgo-error","Go - 错误处理","Go 使用显式的错误返回值来处理错误，而不是异常机制。",{"path":170,"title":171,"description":11},"\u002Fgolang\u002Fcore\u002Fgo-function","Go - 函数",{"path":173,"title":174,"description":11},"\u002Fgolang\u002Fcore\u002Fgo-install","Go - 环境搭建",{"path":176,"title":177,"description":11},"\u002Fgolang\u002Fcore\u002Fgo-interface","Go - 接口",{"path":179,"title":180,"description":181},"\u002Fgolang\u002Fcore\u002Fgo-module","Go - 包管理","Go Modules 是 Go 1.11 引入的官方依赖管理方案，Go 1.16 后成为默认模式。",{"path":183,"title":184,"description":185},"\u002Fgolang\u002Fdistributed\u002Fgrpc","Go - gRPC","gRPC 是 Google 开发的高性能 RPC 框架，使用 Protocol Buffers 作为序列化协议。",{"path":187,"title":188,"description":189},"\u002Fgolang\u002Fdistributed\u002Fmicroservice","Go - 微服务","微服务架构的核心组件：服务发现、负载均衡、熔断降级。",{"path":191,"title":192,"description":193},"\u002Fgolang\u002Fdistributed\u002Fmq","Go - 消息队列","使用 Go 操作 Kafka 和 RabbitMQ。",{"path":195,"title":196,"description":197},"\u002Fgolang\u002Fdistributed\u002Fredis","Go - Redis","使用 go-redis 操作 Redis，实现缓存、分布式锁等功能。",{"path":199,"title":200,"description":201},"\u002Fgolang\u002Fengineering\u002Fconfig","Go - 配置管理","使用 viper 进行配置管理，支持多种配置格式和配置中心。",{"path":203,"title":204,"description":205},"\u002Fgolang\u002Fengineering\u002Fdocker","Go - Docker 部署","使用 Docker 容器化部署 Go 应用。",{"path":207,"title":208,"description":209},"\u002Fgolang\u002Fengineering\u002Fkubernetes","Go - Kubernetes 部署","在 Kubernetes 上部署和管理 Go 应用。",{"path":211,"title":212,"description":213},"\u002Fgolang\u002Fengineering\u002Flogging","Go - 日志系统","使用 zap 和 logrus 构建高性能结构化日志系统。",{"path":215,"title":216,"description":217},"\u002Fgolang\u002Fengineering\u002Ftesting","Go - 单元测试","Go 内置了强大的测试框架，掌握测试是编写高质量代码的基础。",{"path":219,"title":220,"description":221},"\u002Fgolang\u002Fstdlib\u002Fbufio","bufio","在 Go 语言中，bufio 包提供了带缓冲的 I\u002FO 操作，能够提高读写性能。以下是一些常用的 bufio 包 API 及其详细说明：",{"path":223,"title":224,"description":225},"\u002Fgolang\u002Fstdlib\u002Fcontainer","container","在Go语言标准库中，container 包提供了几种常用的数据结构实现，这些数据结构对于高效地管理和操作数据非常有用。以下是 container 包中主要的数据结构：",{"path":227,"title":228,"description":229},"\u002Fgolang\u002Fstdlib\u002Fcrypto","crypto","在 Go 语言中，crypto 包提供了一组用于加密和解密的功能。以下是一些常用的 crypto 包及其子包的 API 及其详细说明：",{"path":231,"title":232,"description":233},"\u002Fgolang\u002Fstdlib\u002Fencoding-csv","encoding\u002Fcsv","在 Go 语言中，encoding\u002Fcsv 包提供了对 CSV（逗号分隔值）文件进行读写的功能。以下是一些常用的 encoding\u002Fcsv 包的 API 及其详细说明：",{"path":235,"title":236,"description":237},"\u002Fgolang\u002Fstdlib\u002Fencoding-json","encoding\u002Fjson","在 Go 语言中，encoding\u002Fjson 包提供了对 JSON 数据进行编码和解码的功能。以下是一些常用的 encoding\u002Fjson 包的 API 及其详细说明：",{"path":239,"title":240,"description":241},"\u002Fgolang\u002Fstdlib\u002Fencoding-xml","encoding\u002Fxml","在 Go 语言中，encoding\u002Fxml 包提供了对 XML 数据进行编码和解码的功能。以下是一些常用的 encoding\u002Fxml 包的 API 及其详细说明：",{"path":243,"title":244,"description":245},"\u002Fgolang\u002Fstdlib\u002Fflag","flag","在Go语言中，flag 包是用于处理命令行参数的标准库，它提供了一种简单而直接的方式来解析和使用命令行参数。下面是关于 flag 包的一些基本介绍和常用功能：",{"path":247,"title":248,"description":249},"\u002Fgolang\u002Fstdlib\u002Ffmt","fmt","在 Go 语言的标准库中，fmt 包是非常重要的，它提供了处理格式化输入和输出的基本工具。以下是一些 fmt 包内常用的API：",{"path":251,"title":252,"description":253},"\u002Fgolang\u002Fstdlib\u002Fhttp","net\u002Fhttp","在 Go 语言中，net\u002Fhttp 包提供了用于构建 HTTP 客户端和服务器的强大工具。以下是一些常用的 net\u002Fhttp 包的 API 及其详细说明：",{"path":255,"title":256,"description":257},"\u002Fgolang\u002Fstdlib\u002Fio","io","在 Go 语言中，io 包提供了基本的输入输出功能。以下是一些常用的 io 包的 API 及其详细说明：",{"path":259,"title":260,"description":261},"\u002Fgolang\u002Fstdlib\u002Flog","log","在 Go 语言中，log 包提供了简单的日志记录功能。以下是一些常用的 log 包的 API 及其详细说明：",{"path":263,"title":264,"description":265},"\u002Fgolang\u002Fstdlib\u002Fmath","math","在 Go 语言中，math 包提供了基本的数学函数和常量。以下是一些常用的 math 包的 API 及其详细说明：",{"path":267,"title":268,"description":11},"\u002Fgolang\u002Fstdlib\u002Fnet","net",{"path":270,"title":271,"description":272},"\u002Fgolang\u002Fstdlib\u002Fos","os","在Go语言中，os 包是一个非常重要且常用的标准库，它提供了与操作系统交互的功能，包括文件操作、环境变量管理、进程管理等。下面是一些 os 包中常用的功能和API：",{"path":274,"title":275,"description":276},"\u002Fgolang\u002Fstdlib\u002Fsort","order","在 Go 语言中，sort 包提供了对切片和用户定义的集合进行排序的函数。它实现了常见的排序算法，如快速排序（Quicksort）和堆排序（Heapsort），并且为自定义集合提供了接口，使得用户可以根据特定的需求进行排序。",{"path":278,"title":279,"description":280},"\u002Fgolang\u002Fstdlib\u002Fstrconv","strconv","在 Go 语言中，strconv 包提供了字符串和基本数据类型之间的转换函数，例如将整数转换为字符串、字符串转换为整数，以及其他类型之间的转换。这些功能非常有用，特别是在处理用户输入或从外部数据源读取数据时。",{"path":282,"title":283,"description":284},"\u002Fgolang\u002Fstdlib\u002Ftime","time","在 Go 语言中，time 包提供了处理时间和日期的功能。以下是一些常用的 time 包的 API 及其详细说明：",{"path":286,"title":287,"description":11},"\u002Fgolang\u002Fweb\u002Fgin\u002Ferror","Gin - 错误处理",{"path":289,"title":290,"description":11},"\u002Fgolang\u002Fweb\u002Fgin\u002Ffile","Gin - 文件处理",{"path":292,"title":293,"description":11},"\u002Fgolang\u002Fweb\u002Fgin\u002Fmiddleware","Gin - 中间件",{"path":295,"title":296,"description":297},"\u002Fgolang\u002Fweb\u002Fgin\u002Fquickstart","Gin - 快速开始","Gin 是目前最流行的 Go Web 框架，以高性能和简洁 API 著称。",{"path":299,"title":300,"description":11},"\u002Fgolang\u002Fweb\u002Fgin\u002Frequest","Gin - 请求处理",{"path":302,"title":303,"description":11},"\u002Fgolang\u002Fweb\u002Fgin\u002Fresponse","Gin - 响应处理",{"path":305,"title":306,"description":11},"\u002Fgolang\u002Fweb\u002Fgin\u002Frouter","Gin - 路由",{"path":308,"title":309,"description":11},"\u002Fgolang\u002Fweb\u002Fgin\u002Fvalidation","Gin - 参数校验",{"path":311,"title":312,"description":11},"\u002Fgolang\u002Fweb\u002Fgorm\u002Fassociation","GORM - 关联关系",{"path":314,"title":315,"description":11},"\u002Fgolang\u002Fweb\u002Fgorm\u002Fcrud","GORM - CRUD 操作",{"path":317,"title":318,"description":11},"\u002Fgolang\u002Fweb\u002Fgorm\u002Fmodel","GORM - 模型定义",{"path":320,"title":321,"description":11},"\u002Fgolang\u002Fweb\u002Fgorm\u002Fperformance","GORM - 日志与性能",{"path":323,"title":324,"description":11},"\u002Fgolang\u002Fweb\u002Fgorm\u002Fquery","GORM - 高级查询",{"path":326,"title":327,"description":328},"\u002Fgolang\u002Fweb\u002Fgorm\u002Fquickstart","GORM - 快速开始","GORM 是 Go 语言最流行的 ORM 库，功能强大，使用简单。",{"path":330,"title":331,"description":11},"\u002Fgolang\u002Fweb\u002Fgorm\u002Ftransaction","GORM - 事务与 Hook",{"path":333,"title":334,"description":335},"\u002Finterview\u002Fbasic","计算机基础面经","本章节汇总了面试中常见的通用技术概念，不局限于特定语言或数据库，是考察技术内功的关键考点。",{"path":337,"title":338,"description":339},"\u002Finterview\u002Fgolang","Golang 面试题","Go 语言面试高频考点，覆盖基础语法、数据结构、并发编程、内存管理、GC、调度器等核心知识。",{"path":341,"title":342,"description":343},"\u002Finterview\u002Fk8s","Kubernetes 面试题","Kubernetes（K8s）面试高频考点，覆盖架构原理、核心资源、网络存储、调度策略、运维监控等核心知识。",{"path":345,"title":346,"description":347},"\u002Finterview\u002Fmysql","MySQL 面试题","MySQL 数据库面试高频考点，覆盖索引、事务、锁、优化、主从复制等核心知识。",{"path":349,"title":350,"description":351},"\u002Finterview\u002Fredis","Redis 面试题","Redis 面试高频考点，覆盖数据结构、持久化、集群、缓存一致性、性能优化等核心知识。",{"path":353,"title":354,"description":355},"\u002Finterview\u002Frocketmq","RocketMQ 面试题","RocketMQ 面试高频考点，覆盖消息模型、可靠性、顺序消息、事务消息、存储与高可用等核心知识。",{"path":357,"title":358,"description":11},"\u002Fother\u002Fjava\u002Fcollection\u002Flist-arraylist","List - ArrayList 源码解析",{"path":360,"title":361,"description":11},"\u002Fother\u002Fjava\u002Fcollection\u002Flist-linkedlist","List - LinkedList 源码解析",{"path":363,"title":364,"description":11},"\u002Fother\u002Fjava\u002Fcollection\u002Flist-stack","List - Satck源码解析",{"path":366,"title":367,"description":11},"\u002Fother\u002Fjava\u002Fcollection\u002Flist-vectore","List - Vector 源码解析",{"path":369,"title":370,"description":11},"\u002Fother\u002Fjava\u002Fcollection\u002Fmap-hashmap","Map - HashMap 源码解析",{"path":372,"title":373,"description":11},"\u002Fother\u002Fjava\u002Fcollection\u002Fmap-linkedhashmap","Map - LinkedHashMap 源码解析",{"path":375,"title":376,"description":11},"\u002Fother\u002Fjava\u002Fcollection\u002Fmap-treemap","Map - TreeMap 源码解析",{"path":378,"title":379,"description":11},"\u002Fother\u002Fjava\u002Fcollection\u002Fqueue-deque","Queue - Deque 接口解析",{"path":381,"title":382,"description":11},"\u002Fother\u002Fjava\u002Fcollection\u002Fqueue-queue","Queue - Queue 接口解析",{"path":384,"title":385,"description":11},"\u002Fother\u002Fjava\u002Fcollection\u002Fset-hashset","Set - HashSet源码解析",{"path":387,"title":388,"description":11},"\u002Fother\u002Fjava\u002Fcollection\u002Fset-linkedhashset","Set - LinkedHashSet 源码解析",{"path":390,"title":391,"description":392},"\u002Fother\u002Fjava\u002Fcollection\u002Fset-treeset","Set - TreeSet源码解析","TreeSet 是一个 Set 集合接口的实现类，与 HashSet 类似，其底层也是通过维护了一个 TreeMap 对象来封装了一些实现方法，故本篇不再对 TreeSet 的底层原理进行详细说明，仅对常用 API 做简单介绍，如需了解 TreeMap 的底层实现原理，请移步 Map - HashMap 源码解析",{"path":394,"title":395,"description":11},"\u002Fother\u002Fjava\u002Fcore\u002Fannotation","Java核心 - 注解",{"path":397,"title":398,"description":11},"\u002Fother\u002Fjava\u002Fcore\u002Fbasic-grammar","Java核心 - 基础语法",{"path":400,"title":401,"description":11},"\u002Fother\u002Fjava\u002Fcore\u002Fclass-and-object","Java核心 - 面向对象",{"path":403,"title":404,"description":11},"\u002Fother\u002Fjava\u002Fcore\u002Fcommon-classes","Java核心 - 常用类",{"path":406,"title":407,"description":11},"\u002Fother\u002Fjava\u002Fcore\u002Fexception","Java核心 - 异常处理",{"path":409,"title":410,"description":11},"\u002Fother\u002Fjava\u002Fcore\u002Fgenerics","Java核心 - 泛型",{"path":412,"title":413,"description":11},"\u002Fother\u002Fjava\u002Fcore\u002Fjdk-env-path","Java核心 - 环境搭建",{"path":415,"title":416,"description":11},"\u002Fother\u002Fjava\u002Fcore\u002Freflection","Java核心 - 反射",{"path":418,"title":419,"description":11},"\u002Fother\u002Fjava\u002Fcore\u002Fstring","Java核心 - String 字符串",{"path":421,"title":422,"description":423},"\u002Fother\u002Fjava\u002Fio\u002Fbuffer-stream","Java IO - 缓冲流","缓冲流是对基本流的包装，通过内置缓冲区减少系统调用次数，大幅提升读写效率。",{"path":425,"title":426,"description":427},"\u002Fother\u002Fjava\u002Fio\u002Fbyte-stream","Java IO - 字节流","字节流是 Java IO 中最基本的流类型，以字节（byte）为单位进行数据读写，可以处理任意类型的文件。",{"path":429,"title":430,"description":431},"\u002Fother\u002Fjava\u002Fio\u002Fchar-stream","Java IO - 字符流","字符流以字符为单位进行读写，专门用于处理文本文件。相比字节流，字符流能够正确处理字符编码，避免中文乱码问题。",{"path":433,"title":434,"description":11},"\u002Fother\u002Fjava\u002Fio\u002Ffile","Java IO - File 类",{"path":436,"title":437,"description":11},"\u002Fother\u002Fjava\u002Fio\u002Fio-stream-system","Java IO - IO流概述",{"path":439,"title":440,"description":441},"\u002Fother\u002Fjava\u002Fio\u002Fnio","Java IO - NIO","NIO（New IO）是 JDK 1.4 引入的新 IO 模型，提供了更高效的 IO 操作方式，支持非阻塞 IO 和多路复用。",{"path":443,"title":444,"description":445},"\u002Fother\u002Fjava\u002Fjvm\u002Fclass-loading","类加载机制","类加载机制是 JVM 将 .class 文件加载到内存，并对数据进行校验、转换解析和初始化，最终形成可被 JVM 直接使用的 Java 类型的过程。",{"path":447,"title":448,"description":449},"\u002Fother\u002Fjava\u002Fjvm\u002Fgarbage-collection","垃圾回收","垃圾回收（Garbage Collection，GC）是 JVM 自动管理内存的机制，负责回收不再使用的对象所占用的内存。",{"path":451,"title":452,"description":453},"\u002Fother\u002Fjava\u002Fjvm\u002Fjvm-memory","JVM 内存结构","JVM 在执行 Java 程序时，会把它管理的内存划分为若干个不同的数据区域。这些区域有各自的用途、创建和销毁时间。",{"path":455,"title":456,"description":457},"\u002Fother\u002Fjava\u002Fjvm\u002Fjvm-tuning","JVM 调优","JVM 调优是优化 Java 应用性能的重要手段，主要包括参数配置、性能监控和问题排查。",{"path":459,"title":460,"description":461},"\u002Fother\u002Fjava\u002Fthread\u002Fatomic","原子类","Java 原子类（Atomic Classes）提供了一种无锁的线程安全方式，基于 CAS（Compare-And-Swap）操作实现。",{"path":463,"title":464,"description":465},"\u002Fother\u002Fjava\u002Fthread\u002Fcompletable-future","CompletableFuture","CompletableFuture 是 JDK 8 引入的异步编程工具，实现了 Future 和 CompletionStage 接口，支持函数式编程和链式调用。",{"path":467,"title":468,"description":469},"\u002Fother\u002Fjava\u002Fthread\u002Fconcurrent-collections","并发集合","Java 并发包提供了多种线程安全的集合类，用于替代传统的同步集合（如 Collections.synchronizedList）。",{"path":471,"title":472,"description":473},"\u002Fother\u002Fjava\u002Fthread\u002Fconcurrent-utils","并发工具类","Java 并发包提供了多种实用的并发工具类，用于控制线程之间的协调与同步。",{"path":475,"title":476,"description":11},"\u002Fother\u002Fjava\u002Fthread\u002Fsynchronized-lock","同步机制",{"path":478,"title":479,"description":11},"\u002Fother\u002Fjava\u002Fthread\u002Fthread-basic","线程基础",{"path":481,"title":482,"description":11},"\u002Fother\u002Fjava\u002Fthread\u002Fthread-pool","线程池",{"path":484,"title":485,"description":486},"\u002Fother\u002Fspring-series\u002Fspring\u002Fannotations-beans","Spring - 基于注解管理Bean","从 Java 5 开始，Java 增加了对注解（Annotation）的支持，它是代码中的一种特殊标记，可以在编译、类加载和运行时被读取，执行相应的处理。开发人员可以通过注解在不改变原有代码和逻辑的情况下，在源代码中嵌入补充信息。",{"path":488,"title":489,"description":490},"\u002Fother\u002Fspring-series\u002Fspring\u002Fimplement-ioc","Spring - 原理手写IoC","Spring 框架的 IOC 是基于 Java 反射机制实现的，在学习手写 IoC 之前，你需要具备一定的 Java 反射相关的知识，参考本站内的 Java 教程。",{"path":492,"title":493,"description":11},"\u002Fother\u002Fspring-series\u002Fspring\u002Fintroduction-case","Spring - 入门案例",{"path":495,"title":496,"description":11},"\u002Fother\u002Fspring-series\u002Fspring\u002Fspring-aop","Spring - 面向切面AOP",{"path":498,"title":499,"description":11},"\u002Fother\u002Fspring-series\u002Fspring\u002Fspring-aot","Spring - AOT提前编译",{"path":501,"title":502,"description":503},"\u002Fother\u002Fspring-series\u002Fspring\u002Fspring-data-validation","Spring - 数据校验","在开发中，我们经常遇到参数校验的需求，比如用户注册的时候，要校验用户名不能为空、用户名长度不超过20个字符、手机号是合法的手机号格式等等。如果使用普通方式，我们会把校验的代码和真正的业务处理逻辑耦合在一起，而且如果未来要新增一种校验逻辑也需要在修改多个地方。而spring validation允许通过注解的方式来定义对象校验规则，把校验和业务逻辑分离开，让代码编写更加方便。Spring Validation其实就是对Hibernate Validator进一步的封装，方便在Spring中使用。",{"path":505,"title":506,"description":11},"\u002Fother\u002Fspring-series\u002Fspring\u002Fspring-i18n","Spring - 国际化i18n",{"path":508,"title":509,"description":510},"\u002Fother\u002Fspring-series\u002Fspring\u002Fspring-ioc","Spring - IOC容器","IoC 是 Inversion of Control 的简写，译为“控制反转”，它不是一门技术，而是一种设计思想，是一个重要的面向对象编程法则，能够指导我们如何设计出松耦合、更优良的程序。",{"path":512,"title":513,"description":514},"\u002Fother\u002Fspring-series\u002Fspring\u002Fspring-junit","Spring - 单元测试JUnit","在之前的测试方法中，几乎都能看到以下的两行代码：",{"path":516,"title":517,"description":11},"\u002Fother\u002Fspring-series\u002Fspring\u002Fspring-resources","Spring - 资源操作",{"path":519,"title":520,"description":11},"\u002Fother\u002Fspring-series\u002Fspring\u002Fspring-summarize","Spring - Spring概述",{"path":522,"title":523,"description":11},"\u002Fother\u002Fspring-series\u002Fspring\u002Fspring-transaction","Spring - 事务",{"path":525,"title":526,"description":11},"\u002Fother\u002Fspring-series\u002Fspring\u002Fxml-beans","Spring - 基于XML管理Bean",{"path":528,"title":529,"description":11},"\u002Fother\u002Fspring-series\u002Fspringboot\u002Fspringboot-config","SpringBoot - 配置详解",{"path":531,"title":532,"description":11},"\u002Fother\u002Fspring-series\u002Fspringboot\u002Fspringboot-data","SpringBoot - 数据访问",{"path":534,"title":535,"description":11},"\u002Fother\u002Fspring-series\u002Fspringboot\u002Fspringboot-quickstart","SpringBoot - 快速入门",{"path":537,"title":538,"description":11},"\u002Fother\u002Fspring-series\u002Fspringboot\u002Fspringboot-web","SpringBoot - Web 开发",{"path":540,"title":541,"description":11},"\u002Fother\u002Fspring-series\u002Fspringcloud\u002Fspringcloud-config","SpringCloud - 配置中心",{"path":543,"title":544,"description":11},"\u002Fother\u002Fspring-series\u002Fspringcloud\u002Fspringcloud-discovery","SpringCloud - 服务注册与发现",{"path":546,"title":547,"description":11},"\u002Fother\u002Fspring-series\u002Fspringcloud\u002Fspringcloud-feign","SpringCloud - 服务调用",{"path":549,"title":550,"description":11},"\u002Fother\u002Fspring-series\u002Fspringcloud\u002Fspringcloud-gateway","SpringCloud - 服务网关",{"path":552,"title":553,"description":11},"\u002Fother\u002Fspring-series\u002Fspringcloud\u002Fspringcloud-introduction","SpringCloud - 微服务概述",{"path":555,"title":556,"description":11},"\u002Fother\u002Fspring-series\u002Fspringcloud\u002Fspringcloud-sentinel","SpringCloud - 服务保护",{"path":558,"title":559,"description":11},"\u002Fother\u002Fspring-series\u002Fspringmvc\u002Fspringmvc-databind","SpringMVC - 数据绑定与转换",{"path":561,"title":562,"description":11},"\u002Fother\u002Fspring-series\u002Fspringmvc\u002Fspringmvc-exception","SpringMVC - 异常处理",{"path":564,"title":565,"description":11},"\u002Fother\u002Fspring-series\u002Fspringmvc\u002Fspringmvc-interceptor","SpringMVC - 拦截器",{"path":567,"title":568,"description":11},"\u002Fother\u002Fspring-series\u002Fspringmvc\u002Fspringmvc-introduction","SpringMVC - 简介与环境搭建",{"path":570,"title":571,"description":11},"\u002Fother\u002Fspring-series\u002Fspringmvc\u002Fspringmvc-request","SpringMVC - 请求处理",{"path":573,"title":574,"description":11},"\u002Fother\u002Fspring-series\u002Fspringmvc\u002Fspringmvc-response","SpringMVC - 响应处理",{"path":576,"title":577,"description":578},"\u002Fproject\u002Frocket-leaf\u002Farchitecture","项目架构","Rocket-Leaf 的目录结构、模块划分、数据流向，以及各层之间的依赖关系。",{"path":580,"title":581,"description":582},"\u002Fproject\u002Frocket-leaf\u002Fbackend-layers","后端分层设计","Rocket-Leaf 的 model \u002F rocketmq \u002F service 三层结构，以及服务之间的依赖关系与设计取舍。",{"path":584,"title":585,"description":586},"\u002Fproject\u002Frocket-leaf\u002Fclient-manager","RocketMQ 客户端管理器","AdminClientManager 的多客户端池、默认连接懒加载、自动重连重试的设计与实现。",{"path":588,"title":589,"description":590},"\u002Fproject\u002Frocket-leaf\u002Fencryption","连接信息加密存储","AES-256-GCM + SHA-256 字段级派生密钥的实现，以及如何在不破坏兼容性的前提下为历史明文数据做透明迁移。",{"path":592,"title":593,"description":594},"\u002Fproject\u002Frocket-leaf\u002Ffrontend","前端结构与类型绑定","React + Vite 目录组织、自动生成的 Wails 绑定、api 薄封装与自定义 hooks 的职责划分。",{"path":596,"title":597,"description":598},"\u002Fproject\u002Frocket-leaf","项目简介","Rocket-Leaf 是一款基于 Wails v3 构建的跨平台 RocketMQ 桌面管理客户端，Go 后端 + React 前端。本文档系列拆解它的架构与关键实现。",{"path":600,"title":601,"description":602},"\u002Fproject\u002Frocket-leaf\u002Fwails-v3","Wails v3 入门","Wails v3 的核心概念、Service 绑定机制，以及 Rocket-Leaf 是如何用它把 Go 后端和 React 前端打通的。",{"path":604,"title":605,"description":11},"\u002Ftutorials\u002Fcloud\u002Fdocker\u002Fdocker-basic","Docker - 入门基础",{"path":607,"title":608,"description":609},"\u002Ftutorials\u002Fcloud\u002Fdocker\u002Fdocker-compose","Docker - Compose","在部署应用时，常常使用到不止一个容器，那么在部署容器的时候就需要一个一个进行部署，这样的部署过程也相对来说比较繁琐复杂，也容易出问题，那么有没有一种更为简单的方法呢？",{"path":611,"title":612,"description":613},"\u002Ftutorials\u002Fcloud\u002Fdocker\u002Fdocker-container-connection","Docker - 容器互联","在上一个章节中我们学习了 Docker 容器的端口映射，可以将 Docker 容器和本地以及网络中的端口进行连接起来。",{"path":615,"title":616,"description":11},"\u002Ftutorials\u002Fcloud\u002Fdocker\u002Fdocker-dockerfile","Docker - Dockerfile",{"path":618,"title":619,"description":11},"\u002Ftutorials\u002Fcloud\u002Fdocker\u002Fdocker-helloworld","Docker - HelloWorld",{"path":621,"title":622,"description":11},"\u002Ftutorials\u002Fcloud\u002Fdocker\u002Fdocker-install","Docker - 安装",{"path":624,"title":625,"description":11},"\u002Ftutorials\u002Fcloud\u002Fdocker\u002Fdocker-introduce","Docker - 简介",{"path":627,"title":628,"description":11},"\u002Ftutorials\u002Fcloud\u002Fdocker\u002Fdocker-object","Docker - 镜像、容器、仓库",{"path":630,"title":631,"description":632},"\u002Ftutorials\u002Fcloud\u002Fdocker\u002Fdocker-warehouse","Docker - 仓库管理","仓库是集中存放资源的地方，代码仓库是存放代码的，那么Docker 中的仓库就是存放 Docker 镜像的。",{"path":634,"title":635,"description":636},"\u002Ftutorials\u002Fcloud\u002Fdocker\u002Fdocker-web-containers","Docker - WEB应用实例","在之前的章节中，仅对普通容器进行了演示，但在实际中常常使用到 Docker 容器中的 WEB 应用程序。",{"path":638,"title":639,"description":11},"\u002Ftutorials\u002Fcloud\u002Fkubernetes\u002Fk8s-config","Kubernetes - ConfigMap 与 Secret",{"path":641,"title":642,"description":11},"\u002Ftutorials\u002Fcloud\u002Fkubernetes\u002Fk8s-helm","Kubernetes - Helm 包管理",{"path":644,"title":645,"description":11},"\u002Ftutorials\u002Fcloud\u002Fkubernetes\u002Fk8s-install","Kubernetes - 集群安装",{"path":647,"title":648,"description":11},"\u002Ftutorials\u002Fcloud\u002Fkubernetes\u002Fk8s-introduction","Kubernetes - 简介与架构",{"path":650,"title":651,"description":11},"\u002Ftutorials\u002Fcloud\u002Fkubernetes\u002Fk8s-kubectl","Kubernetes - kubectl 命令行工具",{"path":653,"title":654,"description":11},"\u002Ftutorials\u002Fcloud\u002Fkubernetes\u002Fk8s-monitoring","Kubernetes - 监控与日志",{"path":656,"title":657,"description":11},"\u002Ftutorials\u002Fcloud\u002Fkubernetes\u002Fk8s-network-security","Kubernetes - 网络与安全",{"path":659,"title":660,"description":11},"\u002Ftutorials\u002Fcloud\u002Fkubernetes\u002Fk8s-service","Kubernetes - Service 与 Ingress",{"path":662,"title":663,"description":11},"\u002Ftutorials\u002Fcloud\u002Fkubernetes\u002Fk8s-storage","Kubernetes - 持久化存储",{"path":665,"title":666,"description":11},"\u002Ftutorials\u002Fcloud\u002Fkubernetes\u002Fk8s-workload","Kubernetes - 工作负载资源",{"path":668,"title":669,"description":11},"\u002Ftutorials\u002Fcloud\u002Flinux\u002Flinux-bash","Linux - Bash 基础语法",{"path":671,"title":672,"description":11},"\u002Ftutorials\u002Fcloud\u002Flinux\u002Flinux-file-directory","Linux - 文件与目录操作",{"path":674,"title":675,"description":11},"\u002Ftutorials\u002Fcloud\u002Flinux\u002Flinux-network","Linux - 网络配置",{"path":677,"title":678,"description":11},"\u002Ftutorials\u002Fcloud\u002Flinux\u002Flinux-package","Linux - 软件包管理",{"path":680,"title":681,"description":11},"\u002Ftutorials\u002Fcloud\u002Flinux\u002Flinux-process","Linux - 进程管理",{"path":683,"title":684,"description":11},"\u002Ftutorials\u002Fcloud\u002Flinux\u002Flinux-scripts","Linux - 常用脚本示例",{"path":686,"title":687,"description":11},"\u002Ftutorials\u002Fcloud\u002Flinux\u002Flinux-service","Linux - 服务管理",{"path":689,"title":690,"description":11},"\u002Ftutorials\u002Fcloud\u002Flinux\u002Flinux-user-permission","Linux - 用户与权限管理",{"path":692,"title":693,"description":11},"\u002Ftutorials\u002Fcloud\u002Fnginx\u002Fnginx-https","Nginx - HTTPS 配置",{"path":695,"title":696,"description":11},"\u002Ftutorials\u002Fcloud\u002Fnginx\u002Fnginx-install","Nginx - 安装与配置",{"path":698,"title":699,"description":11},"\u002Ftutorials\u002Fcloud\u002Fnginx\u002Fnginx-loadbalance","Nginx - 负载均衡",{"path":701,"title":702,"description":11},"\u002Ftutorials\u002Fcloud\u002Fnginx\u002Fnginx-optimization","Nginx - 性能优化",{"path":704,"title":705,"description":11},"\u002Ftutorials\u002Fcloud\u002Fnginx\u002Fnginx-proxy","Nginx - 反向代理",{"path":707,"title":708,"description":11},"\u002Ftutorials\u002Fcloud\u002Fnginx\u002Fnginx-static","Nginx - 静态资源服务",{"path":710,"title":711,"description":11},"\u002Ftutorials\u002Fcloud\u002Fnginx\u002Fnginx-vhost","Nginx - 虚拟主机配置",{"path":713,"title":714,"description":715},"\u002Ftutorials\u002Fdatabase\u002Fmysql\u002Fmysql-architecture","MySQL 高可用架构","主从复制、读写分离、分库分表。",{"path":717,"title":718,"description":719},"\u002Ftutorials\u002Fdatabase\u002Fmysql\u002Fmysql-index","MySQL 索引","索引是帮助 MySQL 高效获取数据的有序数据结构。",{"path":721,"title":722,"description":723},"\u002Ftutorials\u002Fdatabase\u002Fmysql\u002Fmysql-lock","MySQL 锁","锁用于解决并发访问时的数据一致性问题。",{"path":725,"title":726,"description":727},"\u002Ftutorials\u002Fdatabase\u002Fmysql\u002Fmysql-optimize","MySQL 性能优化","SQL 优化是后端开发必备技能。",{"path":729,"title":730,"description":731},"\u002Ftutorials\u002Fdatabase\u002Fmysql\u002Fmysql-transaction","MySQL 事务","事务是一组不可分割的操作，要么全部成功，要么全部失败。",{"path":733,"title":734,"description":735},"\u002Ftutorials\u002Fdatabase\u002Fmysql\u002Fsql-advanced","SQL 进阶","多表查询、子查询、函数、视图、存储过程。",{"path":737,"title":738,"description":739},"\u002Ftutorials\u002Fdatabase\u002Fmysql\u002Fsql-basic","SQL 基础","SQL（Structured Query Language）是操作关系型数据库的标准语言。",{"path":741,"title":742,"description":743},"\u002Ftutorials\u002Fdatabase\u002Fredis\u002Fredis-advanced","Redis 进阶功能","事务、发布订阅、Lua 脚本、Pipeline。",{"path":745,"title":746,"description":747},"\u002Ftutorials\u002Fdatabase\u002Fredis\u002Fredis-basic","Redis 基础","Redis 安装配置与基本命令。",{"path":749,"title":750,"description":751},"\u002Ftutorials\u002Fdatabase\u002Fredis\u002Fredis-cluster","Redis 高可用","主从复制、哨兵、Cluster 集群。",{"path":753,"title":754,"description":755},"\u002Ftutorials\u002Fdatabase\u002Fredis\u002Fredis-datatype","Redis 数据类型","Redis 5 种基本数据类型 + 4 种特殊类型。",{"path":757,"title":758,"description":759},"\u002Ftutorials\u002Fdatabase\u002Fredis\u002Fredis-optimize","Redis 性能优化","内存优化、缓存问题、最佳实践。",{"path":761,"title":762,"description":763},"\u002Ftutorials\u002Fdatabase\u002Fredis\u002Fredis-persistence","Redis 持久化","Redis 提供 RDB 和 AOF 两种持久化方式。",{"path":765,"title":766,"description":767},"\u002Ftutorials\u002Fdatabase\u002Fredis\u002Fredis-principle","Redis 底层原理","数据结构、线程模型、网络模型。",{"path":769,"title":770,"description":771},"\u002Ftutorials\u002Fdev-idea\u002Fdesign-patterns\u002Fbehaiver-patterns\u002Fobserver-pattern","观察者模式","观察者模式属于行为型模式，定义了对象之间的一对多的依赖关系，在这种模式中，当一个对象的状态发生变化时，所有依赖于它的对象都会得到通知，并且执行相关操作。观察者模式又被成为“发布—订阅模式”，即发布者发生改变后，会通知所有订阅者。",{"path":773,"title":774,"description":11},"\u002Ftutorials\u002Fdev-idea\u002Fdesign-patterns\u002Fcreate-patterns\u002Ffactory-pattern","工厂模式",{"path":776,"title":777,"description":778},"\u002Ftutorials\u002Fdev-idea\u002Fdesign-patterns\u002Fcreate-patterns\u002Fsingleton-pattern","单例模式","单例模式是最常用的设计模式之一，他可以保证在整个应用中，某个类只存在一个实例化对象，即全局使用到该类的只有一个对象，这种模式在需要限制某些类的实例数量时非常有用，通常全局只需要一个该对象即可，如一些配置文件映射对象、数据库连接对象等。",{"path":780,"title":781,"description":782},"\u002Ftutorials\u002Fdev-idea\u002Fdesign-patterns\u002Fstructural-patterns\u002Fadapter-pattern","适配器模式","适配器模式是一种结构型模式，可以将一个类的接口转换成客户端所期望的另一种接口，适配器模式可以帮助开发人员在不修改现有代码的情况下，将不兼容的类组合在一起。",{"path":784,"title":785,"description":786},"\u002Ftutorials\u002Fdev-tools\u002Fgit\u002Fgit-basic-operations","Git 创建版本库","在 Git 上创建版本库有两种方式，一种是直接拷贝远程 Git 仓库到本地，另外一种是我们自己创建本地的版本库。",{"path":788,"title":789,"description":11},"\u002Ftutorials\u002Fdev-tools\u002Fgit\u002Fgit-branch-manage","Git 分支管理",{"path":791,"title":792,"description":11},"\u002Ftutorials\u002Fdev-tools\u002Fgit\u002Fgit-content-operations","Git 仓库内容操作",{"path":794,"title":795,"description":11},"\u002Ftutorials\u002Fdev-tools\u002Fgit\u002Fgit-introduce-install","Git 介绍和安装",{"path":797,"title":798,"description":11},"\u002Ftutorials\u002Fdev-tools\u002Fgit\u002Fgit-remote-manage","Git 远程管理",{"path":800,"title":801,"description":11},"\u002Ftutorials\u002Fdev-tools\u002Fgit\u002Fgit-workspace-index-repo","Git 工作原理",{"path":803,"title":804,"description":11},"\u002Ftutorials\u002Fdev-tools\u002Fhomebrew","HomeBrew 教程",{"path":806,"title":807,"description":11},"\u002Ftutorials\u002Fdev-tools\u002Fidea\u002Fshortcuts","快捷键",{"path":809,"title":810,"description":11},"\u002Ftutorials\u002Fdev-tools\u002Fmaven\u002Fintroduce-install-config","Maven - 介绍、安装、配置",{"path":812,"title":813,"description":11},"\u002Ftutorials\u002Ffront-end\u002Fvue3\u002Fbasic-knowledge","2. 基础知识",{"path":815,"title":816,"description":817},"\u002Ftutorials\u002Ffront-end\u002Fvue3\u002Fcomponent-communication","9. 组件通信","在前面的章节内，介绍了 Vue 中最核心的内容——组件的介绍和使用，和 Java 等编程语言相反，组件并不近似于这些变成语言中的类，类可以通过类或者其实例化的对象来相互交互，但 Vue 组件之间的作用域是相互独立的，这就意味着不同组件之间的数据无法相互引用。",{"path":819,"title":820,"description":821},"\u002Ftutorials\u002Ffront-end\u002Fvue3\u002Fcomputed","4. 计算属性","虽然直接在模板中使用表达式方便，但是如果在模板中添加很多逻辑，会让模板变的臃肿且难维护，耦合度较高。有没有一种简单的方式来实现呢？答案是有的。",{"path":823,"title":824,"description":11},"\u002Ftutorials\u002Ffront-end\u002Fvue3\u002Fcreate-vue-project","1. 环境搭建及安装",{"path":826,"title":827,"description":828},"\u002Ftutorials\u002Ffront-end\u002Fvue3\u002Flife-cycle","6. 生命周期","生命周期是指组件从创建、挂载、更新到销毁的整个过程中所经历的一系列阶段。在 Vue 中，每个组件都有自己的生命周期，可以通过生命周期钩子函数来监听和处理组件在不同阶段的行为和状态。",{"path":830,"title":831,"description":11},"\u002Ftutorials\u002Ffront-end\u002Fvue3\u002Fother-api","10. 其他 API",{"path":833,"title":834,"description":11},"\u002Ftutorials\u002Ffront-end\u002Fvue3\u002Fpinia","8. Pinia",{"path":836,"title":837,"description":11},"\u002Ftutorials\u002Ffront-end\u002Fvue3\u002Frouter","7. 路由",{"path":839,"title":840,"description":11},"\u002Ftutorials\u002Ffront-end\u002Fvue3\u002Ftemplate-grammar","3. 指令及模板语法",{"path":842,"title":843,"description":11},"\u002Ftutorials\u002Ffront-end\u002Fvue3\u002Fvue3-new-component","11. Vue3 新组件",{"path":845,"title":846,"description":847},"\u002Ftutorials\u002Ffront-end\u002Fvue3\u002Fwatch","5. 监视","Watch 是 Vue 提供的一个用于监视响应式数据变化并执行相应操作的 API，能够对响应式数据的变化做出一些操作的功能。Vue3 中的 Watch 支持多种用法，包括监视响应式对象、ref 对象、数组、函数等。",{"path":849,"title":850,"description":11},"\u002Ftutorials\u002Fmq\u002Fkafka\u002Fkafka-introduction","Kafka 简介与安装",{"path":852,"title":853,"description":11},"\u002Ftutorials\u002Fmq\u002Fkafka\u002Fkafka-producer-consumer","Kafka 生产者与消费者",{"path":855,"title":856,"description":857},"\u002Ftutorials\u002Fmq\u002Fkafka\u002Fkafka-springboot","Spring Boot 整合 Kafka","Spring Kafka 提供了对 Apache Kafka 的便捷集成。",{"path":859,"title":860,"description":861},"\u002Ftutorials\u002Fmq\u002Frabbitmq\u002Frabbitmq-exchange","RabbitMQ Exchange 详解","Exchange（交换机）是 RabbitMQ 的核心组件，负责接收生产者发送的消息，并根据规则将消息路由到一个或多个队列。",{"path":863,"title":864,"description":11},"\u002Ftutorials\u002Fmq\u002Frabbitmq\u002Frabbitmq-introduction","RabbitMQ 简介与安装",{"path":866,"title":867,"description":868},"\u002Ftutorials\u002Fmq\u002Frabbitmq\u002Frabbitmq-reliability","RabbitMQ 消息可靠性","消息可靠性是消息队列的核心要求，RabbitMQ 提供了多种机制来保证消息不丢失。",{"path":870,"title":871,"description":872},"\u002Ftutorials\u002Fmq\u002Frabbitmq\u002Frabbitmq-springboot","Spring Boot 整合 RabbitMQ","Spring AMQP 提供了对 RabbitMQ 的便捷集成，大大简化了开发工作。",{"path":874,"title":875,"description":11},"\u002Ftutorials\u002Fmq\u002Frocketmq\u002Frocketmq-client","RocketMQ 客户端使用",{"path":877,"title":878,"description":11},"\u002Ftutorials\u002Fmq\u002Frocketmq\u002Frocketmq-concepts","RocketMQ 核心概念",{"path":880,"title":881,"description":11},"\u002Ftutorials\u002Fmq\u002Frocketmq\u002Frocketmq-installation","RocketMQ 安装部署",{"path":883,"title":884,"description":885},"\u002Ftutorials\u002Fmq\u002Frocketmq\u002Frocketmq-message-type","RocketMQ 消息类型","RocketMQ 支持多种消息类型，满足不同业务场景需求。",{"id":887,"title":496,"body":888,"description":11,"extension":6278,"meta":6279,"navigation":2387,"path":495,"seo":6280,"stem":6281,"__hash__":6282},"docs\u002Fother\u002Fspring-series\u002Fspring\u002Fspring-aop.md",{"type":889,"value":890,"toc":6267},"minimark",[891,895,903,910,1066,1071,1479,1484,2038,6263],[892,893,894],"h2",{"id":894},"场景模拟",[896,897,898,899],"p",{},"还是老规矩，为了避免和之前的项目冲突，我们这里创建一个新的子模块 ",[900,901,902],"code",{},"spring6-aop",[904,905,906],"ul",{},[907,908,909],"li",{},"声明计算器接口 Calculator",[911,912,916],"pre",{"className":913,"code":914,"language":915,"meta":11,"style":11},"language-java shiki shiki-themes github-light github-light github-dark","public interface Calculator {\n    \n    int add(int i, int j);\n    \n    int sub(int i, int j);\n    \n    int mul(int i, int j);\n    \n    int div(int i, int j);\n    \n}\n","java",[900,917,918,938,944,974,979,1001,1006,1028,1033,1055,1060],{"__ignoreMap":11},[919,920,923,927,930,934],"span",{"class":921,"line":922},"line",1,[919,924,926],{"class":925},"s8jYJ","public",[919,928,929],{"class":925}," interface",[919,931,933],{"class":932},"snPdu"," Calculator",[919,935,937],{"class":936},"sxrX7"," {\n",[919,939,941],{"class":921,"line":940},2,[919,942,943],{"class":936},"    \n",[919,945,947,950,953,956,959,963,966,968,971],{"class":921,"line":946},3,[919,948,949],{"class":925},"    int",[919,951,952],{"class":932}," add",[919,954,955],{"class":936},"(",[919,957,958],{"class":925},"int",[919,960,962],{"class":961},"sP4rz"," i",[919,964,965],{"class":936},", ",[919,967,958],{"class":925},[919,969,970],{"class":961}," j",[919,972,973],{"class":936},");\n",[919,975,977],{"class":921,"line":976},4,[919,978,943],{"class":936},[919,980,982,984,987,989,991,993,995,997,999],{"class":921,"line":981},5,[919,983,949],{"class":925},[919,985,986],{"class":932}," sub",[919,988,955],{"class":936},[919,990,958],{"class":925},[919,992,962],{"class":961},[919,994,965],{"class":936},[919,996,958],{"class":925},[919,998,970],{"class":961},[919,1000,973],{"class":936},[919,1002,1004],{"class":921,"line":1003},6,[919,1005,943],{"class":936},[919,1007,1009,1011,1014,1016,1018,1020,1022,1024,1026],{"class":921,"line":1008},7,[919,1010,949],{"class":925},[919,1012,1013],{"class":932}," mul",[919,1015,955],{"class":936},[919,1017,958],{"class":925},[919,1019,962],{"class":961},[919,1021,965],{"class":936},[919,1023,958],{"class":925},[919,1025,970],{"class":961},[919,1027,973],{"class":936},[919,1029,1031],{"class":921,"line":1030},8,[919,1032,943],{"class":936},[919,1034,1036,1038,1041,1043,1045,1047,1049,1051,1053],{"class":921,"line":1035},9,[919,1037,949],{"class":925},[919,1039,1040],{"class":932}," div",[919,1042,955],{"class":936},[919,1044,958],{"class":925},[919,1046,962],{"class":961},[919,1048,965],{"class":936},[919,1050,958],{"class":925},[919,1052,970],{"class":961},[919,1054,973],{"class":936},[919,1056,1058],{"class":921,"line":1057},10,[919,1059,943],{"class":936},[919,1061,1063],{"class":921,"line":1062},11,[919,1064,1065],{"class":936},"}\n",[904,1067,1068],{},[907,1069,1070],{},"创建一般实现类",[911,1072,1074],{"className":913,"code":1073,"language":915,"meta":11,"style":11},"public class CalculatorImpl implements Calculator {\n    \n    @Override\n    public int add(int i, int j) {\n    \n        int result = i + j;\n    \n        System.out.println(\"方法内部 result = \" + result);\n    \n        return result;\n    }\n    \n    @Override\n    public int sub(int i, int j) {\n    \n        int result = i - j;\n    \n        System.out.println(\"方法内部 result = \" + result);\n    \n        return result;\n    }\n    \n    @Override\n    public int mul(int i, int j) {\n    \n        int result = i * j;\n    \n        System.out.println(\"方法内部 result = \" + result);\n    \n        return result;\n    }\n    \n    @Override\n    public int div(int i, int j) {\n    \n        int result = i \u002F j;\n    \n        System.out.println(\"方法内部 result = \" + result);\n    \n        return result;\n    }\n}\n",[900,1075,1076,1093,1097,1105,1130,1134,1154,1158,1178,1182,1190,1195,1200,1207,1230,1235,1251,1256,1271,1276,1283,1288,1293,1300,1323,1328,1344,1349,1364,1369,1376,1381,1386,1393,1416,1421,1437,1442,1457,1462,1469,1474],{"__ignoreMap":11},[919,1077,1078,1080,1083,1086,1089,1091],{"class":921,"line":922},[919,1079,926],{"class":925},[919,1081,1082],{"class":925}," class",[919,1084,1085],{"class":932}," CalculatorImpl",[919,1087,1088],{"class":925}," implements",[919,1090,933],{"class":932},[919,1092,937],{"class":936},[919,1094,1095],{"class":921,"line":940},[919,1096,943],{"class":936},[919,1098,1099,1102],{"class":921,"line":946},[919,1100,1101],{"class":936},"    @",[919,1103,1104],{"class":925},"Override\n",[919,1106,1107,1110,1113,1115,1117,1119,1121,1123,1125,1127],{"class":921,"line":976},[919,1108,1109],{"class":925},"    public",[919,1111,1112],{"class":925}," int",[919,1114,952],{"class":932},[919,1116,955],{"class":936},[919,1118,958],{"class":925},[919,1120,962],{"class":961},[919,1122,965],{"class":936},[919,1124,958],{"class":925},[919,1126,970],{"class":961},[919,1128,1129],{"class":936},") {\n",[919,1131,1132],{"class":921,"line":981},[919,1133,943],{"class":936},[919,1135,1136,1139,1142,1145,1148,1151],{"class":921,"line":1003},[919,1137,1138],{"class":925},"        int",[919,1140,1141],{"class":936}," result ",[919,1143,1144],{"class":925},"=",[919,1146,1147],{"class":936}," i ",[919,1149,1150],{"class":925},"+",[919,1152,1153],{"class":936}," j;\n",[919,1155,1156],{"class":921,"line":1008},[919,1157,943],{"class":936},[919,1159,1160,1163,1166,1168,1172,1175],{"class":921,"line":1030},[919,1161,1162],{"class":936},"        System.out.",[919,1164,1165],{"class":932},"println",[919,1167,955],{"class":936},[919,1169,1171],{"class":1170},"sIIMD","\"方法内部 result = \"",[919,1173,1174],{"class":925}," +",[919,1176,1177],{"class":936}," result);\n",[919,1179,1180],{"class":921,"line":1035},[919,1181,943],{"class":936},[919,1183,1184,1187],{"class":921,"line":1057},[919,1185,1186],{"class":925},"        return",[919,1188,1189],{"class":936}," result;\n",[919,1191,1192],{"class":921,"line":1062},[919,1193,1194],{"class":936},"    }\n",[919,1196,1198],{"class":921,"line":1197},12,[919,1199,943],{"class":936},[919,1201,1203,1205],{"class":921,"line":1202},13,[919,1204,1101],{"class":936},[919,1206,1104],{"class":925},[919,1208,1210,1212,1214,1216,1218,1220,1222,1224,1226,1228],{"class":921,"line":1209},14,[919,1211,1109],{"class":925},[919,1213,1112],{"class":925},[919,1215,986],{"class":932},[919,1217,955],{"class":936},[919,1219,958],{"class":925},[919,1221,962],{"class":961},[919,1223,965],{"class":936},[919,1225,958],{"class":925},[919,1227,970],{"class":961},[919,1229,1129],{"class":936},[919,1231,1233],{"class":921,"line":1232},15,[919,1234,943],{"class":936},[919,1236,1238,1240,1242,1244,1246,1249],{"class":921,"line":1237},16,[919,1239,1138],{"class":925},[919,1241,1141],{"class":936},[919,1243,1144],{"class":925},[919,1245,1147],{"class":936},[919,1247,1248],{"class":925},"-",[919,1250,1153],{"class":936},[919,1252,1254],{"class":921,"line":1253},17,[919,1255,943],{"class":936},[919,1257,1259,1261,1263,1265,1267,1269],{"class":921,"line":1258},18,[919,1260,1162],{"class":936},[919,1262,1165],{"class":932},[919,1264,955],{"class":936},[919,1266,1171],{"class":1170},[919,1268,1174],{"class":925},[919,1270,1177],{"class":936},[919,1272,1274],{"class":921,"line":1273},19,[919,1275,943],{"class":936},[919,1277,1279,1281],{"class":921,"line":1278},20,[919,1280,1186],{"class":925},[919,1282,1189],{"class":936},[919,1284,1286],{"class":921,"line":1285},21,[919,1287,1194],{"class":936},[919,1289,1291],{"class":921,"line":1290},22,[919,1292,943],{"class":936},[919,1294,1296,1298],{"class":921,"line":1295},23,[919,1297,1101],{"class":936},[919,1299,1104],{"class":925},[919,1301,1303,1305,1307,1309,1311,1313,1315,1317,1319,1321],{"class":921,"line":1302},24,[919,1304,1109],{"class":925},[919,1306,1112],{"class":925},[919,1308,1013],{"class":932},[919,1310,955],{"class":936},[919,1312,958],{"class":925},[919,1314,962],{"class":961},[919,1316,965],{"class":936},[919,1318,958],{"class":925},[919,1320,970],{"class":961},[919,1322,1129],{"class":936},[919,1324,1326],{"class":921,"line":1325},25,[919,1327,943],{"class":936},[919,1329,1331,1333,1335,1337,1339,1342],{"class":921,"line":1330},26,[919,1332,1138],{"class":925},[919,1334,1141],{"class":936},[919,1336,1144],{"class":925},[919,1338,1147],{"class":936},[919,1340,1341],{"class":925},"*",[919,1343,1153],{"class":936},[919,1345,1347],{"class":921,"line":1346},27,[919,1348,943],{"class":936},[919,1350,1352,1354,1356,1358,1360,1362],{"class":921,"line":1351},28,[919,1353,1162],{"class":936},[919,1355,1165],{"class":932},[919,1357,955],{"class":936},[919,1359,1171],{"class":1170},[919,1361,1174],{"class":925},[919,1363,1177],{"class":936},[919,1365,1367],{"class":921,"line":1366},29,[919,1368,943],{"class":936},[919,1370,1372,1374],{"class":921,"line":1371},30,[919,1373,1186],{"class":925},[919,1375,1189],{"class":936},[919,1377,1379],{"class":921,"line":1378},31,[919,1380,1194],{"class":936},[919,1382,1384],{"class":921,"line":1383},32,[919,1385,943],{"class":936},[919,1387,1389,1391],{"class":921,"line":1388},33,[919,1390,1101],{"class":936},[919,1392,1104],{"class":925},[919,1394,1396,1398,1400,1402,1404,1406,1408,1410,1412,1414],{"class":921,"line":1395},34,[919,1397,1109],{"class":925},[919,1399,1112],{"class":925},[919,1401,1040],{"class":932},[919,1403,955],{"class":936},[919,1405,958],{"class":925},[919,1407,962],{"class":961},[919,1409,965],{"class":936},[919,1411,958],{"class":925},[919,1413,970],{"class":961},[919,1415,1129],{"class":936},[919,1417,1419],{"class":921,"line":1418},35,[919,1420,943],{"class":936},[919,1422,1424,1426,1428,1430,1432,1435],{"class":921,"line":1423},36,[919,1425,1138],{"class":925},[919,1427,1141],{"class":936},[919,1429,1144],{"class":925},[919,1431,1147],{"class":936},[919,1433,1434],{"class":925},"\u002F",[919,1436,1153],{"class":936},[919,1438,1440],{"class":921,"line":1439},37,[919,1441,943],{"class":936},[919,1443,1445,1447,1449,1451,1453,1455],{"class":921,"line":1444},38,[919,1446,1162],{"class":936},[919,1448,1165],{"class":932},[919,1450,955],{"class":936},[919,1452,1171],{"class":1170},[919,1454,1174],{"class":925},[919,1456,1177],{"class":936},[919,1458,1460],{"class":921,"line":1459},39,[919,1461,943],{"class":936},[919,1463,1465,1467],{"class":921,"line":1464},40,[919,1466,1186],{"class":925},[919,1468,1189],{"class":936},[919,1470,1472],{"class":921,"line":1471},41,[919,1473,1194],{"class":936},[919,1475,1477],{"class":921,"line":1476},42,[919,1478,1065],{"class":936},[904,1480,1481],{},[907,1482,1483],{},"创建带日志功能的实现类",[911,1485,1487],{"className":913,"code":1486,"language":915,"meta":11,"style":11},"public class CalculatorLogImpl implements Calculator {\n    \n    @Override\n    public int add(int i, int j) {\n    \n        System.out.println(\"[日志] add 方法开始了，参数是：\" + i + \",\" + j);\n    \n        int result = i + j;\n    \n        System.out.println(\"方法内部 result = \" + result);\n    \n        System.out.println(\"[日志] add 方法结束了，结果是：\" + result);\n    \n        return result;\n    }\n    \n    @Override\n    public int sub(int i, int j) {\n    \n        System.out.println(\"[日志] sub 方法开始了，参数是：\" + i + \",\" + j);\n    \n        int result = i - j;\n    \n        System.out.println(\"方法内部 result = \" + result);\n    \n        System.out.println(\"[日志] sub 方法结束了，结果是：\" + result);\n    \n        return result;\n    }\n    \n    @Override\n    public int mul(int i, int j) {\n    \n        System.out.println(\"[日志] mul 方法开始了，参数是：\" + i + \",\" + j);\n    \n        int result = i * j;\n    \n        System.out.println(\"方法内部 result = \" + result);\n    \n        System.out.println(\"[日志] mul 方法结束了，结果是：\" + result);\n    \n        return result;\n    }\n    \n    @Override\n    public int div(int i, int j) {\n    \n        System.out.println(\"[日志] div 方法开始了，参数是：\" + i + \",\" + j);\n    \n        int result = i \u002F j;\n    \n        System.out.println(\"方法内部 result = \" + result);\n    \n        System.out.println(\"[日志] div 方法结束了，结果是：\" + result);\n    \n        return result;\n    }\n}\n",[900,1488,1489,1504,1508,1514,1536,1540,1565,1569,1583,1587,1601,1605,1620,1624,1630,1634,1638,1644,1666,1670,1693,1697,1711,1715,1729,1733,1748,1752,1758,1762,1766,1772,1794,1798,1821,1825,1839,1843,1857,1861,1876,1880,1886,1891,1896,1903,1926,1931,1955,1960,1975,1980,1995,2000,2016,2021,2028,2033],{"__ignoreMap":11},[919,1490,1491,1493,1495,1498,1500,1502],{"class":921,"line":922},[919,1492,926],{"class":925},[919,1494,1082],{"class":925},[919,1496,1497],{"class":932}," CalculatorLogImpl",[919,1499,1088],{"class":925},[919,1501,933],{"class":932},[919,1503,937],{"class":936},[919,1505,1506],{"class":921,"line":940},[919,1507,943],{"class":936},[919,1509,1510,1512],{"class":921,"line":946},[919,1511,1101],{"class":936},[919,1513,1104],{"class":925},[919,1515,1516,1518,1520,1522,1524,1526,1528,1530,1532,1534],{"class":921,"line":976},[919,1517,1109],{"class":925},[919,1519,1112],{"class":925},[919,1521,952],{"class":932},[919,1523,955],{"class":936},[919,1525,958],{"class":925},[919,1527,962],{"class":961},[919,1529,965],{"class":936},[919,1531,958],{"class":925},[919,1533,970],{"class":961},[919,1535,1129],{"class":936},[919,1537,1538],{"class":921,"line":981},[919,1539,943],{"class":936},[919,1541,1542,1544,1546,1548,1551,1553,1555,1557,1560,1562],{"class":921,"line":1003},[919,1543,1162],{"class":936},[919,1545,1165],{"class":932},[919,1547,955],{"class":936},[919,1549,1550],{"class":1170},"\"[日志] add 方法开始了，参数是：\"",[919,1552,1174],{"class":925},[919,1554,1147],{"class":936},[919,1556,1150],{"class":925},[919,1558,1559],{"class":1170}," \",\"",[919,1561,1174],{"class":925},[919,1563,1564],{"class":936}," j);\n",[919,1566,1567],{"class":921,"line":1008},[919,1568,943],{"class":936},[919,1570,1571,1573,1575,1577,1579,1581],{"class":921,"line":1030},[919,1572,1138],{"class":925},[919,1574,1141],{"class":936},[919,1576,1144],{"class":925},[919,1578,1147],{"class":936},[919,1580,1150],{"class":925},[919,1582,1153],{"class":936},[919,1584,1585],{"class":921,"line":1035},[919,1586,943],{"class":936},[919,1588,1589,1591,1593,1595,1597,1599],{"class":921,"line":1057},[919,1590,1162],{"class":936},[919,1592,1165],{"class":932},[919,1594,955],{"class":936},[919,1596,1171],{"class":1170},[919,1598,1174],{"class":925},[919,1600,1177],{"class":936},[919,1602,1603],{"class":921,"line":1062},[919,1604,943],{"class":936},[919,1606,1607,1609,1611,1613,1616,1618],{"class":921,"line":1197},[919,1608,1162],{"class":936},[919,1610,1165],{"class":932},[919,1612,955],{"class":936},[919,1614,1615],{"class":1170},"\"[日志] add 方法结束了，结果是：\"",[919,1617,1174],{"class":925},[919,1619,1177],{"class":936},[919,1621,1622],{"class":921,"line":1202},[919,1623,943],{"class":936},[919,1625,1626,1628],{"class":921,"line":1209},[919,1627,1186],{"class":925},[919,1629,1189],{"class":936},[919,1631,1632],{"class":921,"line":1232},[919,1633,1194],{"class":936},[919,1635,1636],{"class":921,"line":1237},[919,1637,943],{"class":936},[919,1639,1640,1642],{"class":921,"line":1253},[919,1641,1101],{"class":936},[919,1643,1104],{"class":925},[919,1645,1646,1648,1650,1652,1654,1656,1658,1660,1662,1664],{"class":921,"line":1258},[919,1647,1109],{"class":925},[919,1649,1112],{"class":925},[919,1651,986],{"class":932},[919,1653,955],{"class":936},[919,1655,958],{"class":925},[919,1657,962],{"class":961},[919,1659,965],{"class":936},[919,1661,958],{"class":925},[919,1663,970],{"class":961},[919,1665,1129],{"class":936},[919,1667,1668],{"class":921,"line":1273},[919,1669,943],{"class":936},[919,1671,1672,1674,1676,1678,1681,1683,1685,1687,1689,1691],{"class":921,"line":1278},[919,1673,1162],{"class":936},[919,1675,1165],{"class":932},[919,1677,955],{"class":936},[919,1679,1680],{"class":1170},"\"[日志] sub 方法开始了，参数是：\"",[919,1682,1174],{"class":925},[919,1684,1147],{"class":936},[919,1686,1150],{"class":925},[919,1688,1559],{"class":1170},[919,1690,1174],{"class":925},[919,1692,1564],{"class":936},[919,1694,1695],{"class":921,"line":1285},[919,1696,943],{"class":936},[919,1698,1699,1701,1703,1705,1707,1709],{"class":921,"line":1290},[919,1700,1138],{"class":925},[919,1702,1141],{"class":936},[919,1704,1144],{"class":925},[919,1706,1147],{"class":936},[919,1708,1248],{"class":925},[919,1710,1153],{"class":936},[919,1712,1713],{"class":921,"line":1295},[919,1714,943],{"class":936},[919,1716,1717,1719,1721,1723,1725,1727],{"class":921,"line":1302},[919,1718,1162],{"class":936},[919,1720,1165],{"class":932},[919,1722,955],{"class":936},[919,1724,1171],{"class":1170},[919,1726,1174],{"class":925},[919,1728,1177],{"class":936},[919,1730,1731],{"class":921,"line":1325},[919,1732,943],{"class":936},[919,1734,1735,1737,1739,1741,1744,1746],{"class":921,"line":1330},[919,1736,1162],{"class":936},[919,1738,1165],{"class":932},[919,1740,955],{"class":936},[919,1742,1743],{"class":1170},"\"[日志] sub 方法结束了，结果是：\"",[919,1745,1174],{"class":925},[919,1747,1177],{"class":936},[919,1749,1750],{"class":921,"line":1346},[919,1751,943],{"class":936},[919,1753,1754,1756],{"class":921,"line":1351},[919,1755,1186],{"class":925},[919,1757,1189],{"class":936},[919,1759,1760],{"class":921,"line":1366},[919,1761,1194],{"class":936},[919,1763,1764],{"class":921,"line":1371},[919,1765,943],{"class":936},[919,1767,1768,1770],{"class":921,"line":1378},[919,1769,1101],{"class":936},[919,1771,1104],{"class":925},[919,1773,1774,1776,1778,1780,1782,1784,1786,1788,1790,1792],{"class":921,"line":1383},[919,1775,1109],{"class":925},[919,1777,1112],{"class":925},[919,1779,1013],{"class":932},[919,1781,955],{"class":936},[919,1783,958],{"class":925},[919,1785,962],{"class":961},[919,1787,965],{"class":936},[919,1789,958],{"class":925},[919,1791,970],{"class":961},[919,1793,1129],{"class":936},[919,1795,1796],{"class":921,"line":1388},[919,1797,943],{"class":936},[919,1799,1800,1802,1804,1806,1809,1811,1813,1815,1817,1819],{"class":921,"line":1395},[919,1801,1162],{"class":936},[919,1803,1165],{"class":932},[919,1805,955],{"class":936},[919,1807,1808],{"class":1170},"\"[日志] mul 方法开始了，参数是：\"",[919,1810,1174],{"class":925},[919,1812,1147],{"class":936},[919,1814,1150],{"class":925},[919,1816,1559],{"class":1170},[919,1818,1174],{"class":925},[919,1820,1564],{"class":936},[919,1822,1823],{"class":921,"line":1418},[919,1824,943],{"class":936},[919,1826,1827,1829,1831,1833,1835,1837],{"class":921,"line":1423},[919,1828,1138],{"class":925},[919,1830,1141],{"class":936},[919,1832,1144],{"class":925},[919,1834,1147],{"class":936},[919,1836,1341],{"class":925},[919,1838,1153],{"class":936},[919,1840,1841],{"class":921,"line":1439},[919,1842,943],{"class":936},[919,1844,1845,1847,1849,1851,1853,1855],{"class":921,"line":1444},[919,1846,1162],{"class":936},[919,1848,1165],{"class":932},[919,1850,955],{"class":936},[919,1852,1171],{"class":1170},[919,1854,1174],{"class":925},[919,1856,1177],{"class":936},[919,1858,1859],{"class":921,"line":1459},[919,1860,943],{"class":936},[919,1862,1863,1865,1867,1869,1872,1874],{"class":921,"line":1464},[919,1864,1162],{"class":936},[919,1866,1165],{"class":932},[919,1868,955],{"class":936},[919,1870,1871],{"class":1170},"\"[日志] mul 方法结束了，结果是：\"",[919,1873,1174],{"class":925},[919,1875,1177],{"class":936},[919,1877,1878],{"class":921,"line":1471},[919,1879,943],{"class":936},[919,1881,1882,1884],{"class":921,"line":1476},[919,1883,1186],{"class":925},[919,1885,1189],{"class":936},[919,1887,1889],{"class":921,"line":1888},43,[919,1890,1194],{"class":936},[919,1892,1894],{"class":921,"line":1893},44,[919,1895,943],{"class":936},[919,1897,1899,1901],{"class":921,"line":1898},45,[919,1900,1101],{"class":936},[919,1902,1104],{"class":925},[919,1904,1906,1908,1910,1912,1914,1916,1918,1920,1922,1924],{"class":921,"line":1905},46,[919,1907,1109],{"class":925},[919,1909,1112],{"class":925},[919,1911,1040],{"class":932},[919,1913,955],{"class":936},[919,1915,958],{"class":925},[919,1917,962],{"class":961},[919,1919,965],{"class":936},[919,1921,958],{"class":925},[919,1923,970],{"class":961},[919,1925,1129],{"class":936},[919,1927,1929],{"class":921,"line":1928},47,[919,1930,943],{"class":936},[919,1932,1934,1936,1938,1940,1943,1945,1947,1949,1951,1953],{"class":921,"line":1933},48,[919,1935,1162],{"class":936},[919,1937,1165],{"class":932},[919,1939,955],{"class":936},[919,1941,1942],{"class":1170},"\"[日志] div 方法开始了，参数是：\"",[919,1944,1174],{"class":925},[919,1946,1147],{"class":936},[919,1948,1150],{"class":925},[919,1950,1559],{"class":1170},[919,1952,1174],{"class":925},[919,1954,1564],{"class":936},[919,1956,1958],{"class":921,"line":1957},49,[919,1959,943],{"class":936},[919,1961,1963,1965,1967,1969,1971,1973],{"class":921,"line":1962},50,[919,1964,1138],{"class":925},[919,1966,1141],{"class":936},[919,1968,1144],{"class":925},[919,1970,1147],{"class":936},[919,1972,1434],{"class":925},[919,1974,1153],{"class":936},[919,1976,1978],{"class":921,"line":1977},51,[919,1979,943],{"class":936},[919,1981,1983,1985,1987,1989,1991,1993],{"class":921,"line":1982},52,[919,1984,1162],{"class":936},[919,1986,1165],{"class":932},[919,1988,955],{"class":936},[919,1990,1171],{"class":1170},[919,1992,1174],{"class":925},[919,1994,1177],{"class":936},[919,1996,1998],{"class":921,"line":1997},53,[919,1999,943],{"class":936},[919,2001,2003,2005,2007,2009,2012,2014],{"class":921,"line":2002},54,[919,2004,1162],{"class":936},[919,2006,1165],{"class":932},[919,2008,955],{"class":936},[919,2010,2011],{"class":1170},"\"[日志] div 方法结束了，结果是：\"",[919,2013,1174],{"class":925},[919,2015,1177],{"class":936},[919,2017,2019],{"class":921,"line":2018},55,[919,2020,943],{"class":936},[919,2022,2024,2026],{"class":921,"line":2023},56,[919,2025,1186],{"class":925},[919,2027,1189],{"class":936},[919,2029,2031],{"class":921,"line":2030},57,[919,2032,1194],{"class":936},[919,2034,2036],{"class":921,"line":2035},58,[919,2037,1065],{"class":936},[2039,2040,2042,2043,2046,2054,2063,2066,2073,2076,2079,2083,2094,2100,2103,2108,2113,2124,2129,2137,2141,2146,2348,2351,2354,2357,2362,2367,2859,2864,2959,2965,2971,2975,2978,2981,2984,2991,2994,2997,3000,3005,3012,3017,3020,3065,3070,3077,3080,3085,3092,3095,3102,3105,3112,3115,3121,3126,3133,3136,3139,3142,3147,3150],"warning",{"title":2041},"提出问题","\n1. **现有代码缺陷**\n",[896,2044,2045],{},"针对带日志功能的实现类，我们发现有如下缺陷：",[904,2047,2048,2051],{},[907,2049,2050],{},"对核心业务功能有干扰，导致程序员在开发核心业务功能时分散了精力",[907,2052,2053],{},"附加功能分散在各个业务功能方法中，不利于统一维护",[2055,2056,2057],"ol",{"start":940},[907,2058,2059],{},[2060,2061,2062],"strong",{},"解决思路",[896,2064,2065],{},"解决这两个问题，核心就是：解耦。我们需要把附加功能从业务功能代码中抽取出来。",[2055,2067,2068],{"start":946},[907,2069,2070],{},[2060,2071,2072],{},"困难",[896,2074,2075],{},"解决问题的困难：要抽取的代码在方法内部，靠以前把子类中的重复代码抽取到父类的方式没法解决。所以需要引入新的技术。\n",[892,2077,2078],{"id":2078},"代理模式",[2080,2081,2082],"note",{},"\n对代理模式还不熟悉的朋友，可以看我写的这章笔记。\n\u002F\u002F TODO: 待更新【设计模式-代理模式】\n",[896,2084,2085,2086,2089,2090,2093],{},"二十三种设计模式中的一种，属于结构型模式。它的作用就是通过提供一个代理类，让我们在调用目标方法的时候，不再是直接对目标方法进行调用，而是通过代理类",[2060,2087,2088],{},"间接","调用。让不属于目标方法核心逻辑的代码从目标方法中剥离出来——",[2060,2091,2092],{},"解耦","。调用目标方法时先调用代理对象的方法，减少对目标方法的调用和打扰，同时让附加功能能够集中在一起也有利于统一维护。",[896,2095,2096],{},[2097,2098],"img",{"alt":11,"src":2099},"\u002Fassets\u002Fjava\u002Fspring\u002Fspring-aop\u002F2024-01-01-20-33-05.png",[896,2101,2102],{},"使用代理后：",[896,2104,2105],{},[2097,2106],{"alt":11,"src":2107},"\u002Fassets\u002Fjava\u002Fspring\u002Fspring-aop\u002F2024-01-01-20-33-14.png",[896,2109,2110],{},[2060,2111,2112],{},"②生活中的代理",[904,2114,2115,2118,2121],{},[907,2116,2117],{},"广告商找大明星拍广告需要经过经纪人",[907,2119,2120],{},"合作伙伴找大老板谈合作要约见面时间需要经过秘书",[907,2122,2123],{},"房产中介是买卖双方的代理",[896,2125,2126],{},[2060,2127,2128],{},"③相关术语",[904,2130,2131,2134],{},[907,2132,2133],{},"代理：将非核心逻辑剥离出来以后，封装这些非核心逻辑的类、对象、方法。",[907,2135,2136],{},"目标：被代理“套用”了非核心逻辑代码的类、对象、方法。",[2138,2139,2140],"h3",{"id":2140},"静态代理",[904,2142,2143],{},[907,2144,2145],{},"创建静态代理类",[911,2147,2149],{"className":913,"code":2148,"language":915,"meta":11,"style":11},"public class CalculatorStaticProxy implements Calculator {\n    \n    \u002F\u002F 将被代理的目标对象声明为成员变量\n    private Calculator target;\n    \n    public CalculatorStaticProxy(Calculator target) {\n        this.target = target;\n    }\n    \n    @Override\n    public int add(int i, int j) {\n    \n        \u002F\u002F 附加功能由代理类中的代理方法来实现\n        System.out.println(\"[日志] add 方法开始了，参数是：\" + i + \",\" + j);\n    \n        \u002F\u002F 通过目标对象来实现核心业务逻辑\n        int addResult = target.add(i, j);\n    \n        System.out.println(\"[日志] add 方法结束了，结果是：\" + addResult);\n    \n        return addResult;\n    }\n}\n",[900,2150,2151,2166,2170,2176,2184,2188,2202,2216,2220,2224,2230,2252,2256,2261,2283,2287,2292,2310,2314,2329,2333,2340,2344],{"__ignoreMap":11},[919,2152,2153,2155,2157,2160,2162,2164],{"class":921,"line":922},[919,2154,926],{"class":925},[919,2156,1082],{"class":925},[919,2158,2159],{"class":932}," CalculatorStaticProxy",[919,2161,1088],{"class":925},[919,2163,933],{"class":932},[919,2165,937],{"class":936},[919,2167,2168],{"class":921,"line":940},[919,2169,943],{"class":936},[919,2171,2172],{"class":921,"line":946},[919,2173,2175],{"class":2174},"sCsY4","    \u002F\u002F 将被代理的目标对象声明为成员变量\n",[919,2177,2178,2181],{"class":921,"line":976},[919,2179,2180],{"class":925},"    private",[919,2182,2183],{"class":936}," Calculator target;\n",[919,2185,2186],{"class":921,"line":981},[919,2187,943],{"class":936},[919,2189,2190,2192,2194,2197,2200],{"class":921,"line":1003},[919,2191,1109],{"class":925},[919,2193,2159],{"class":932},[919,2195,2196],{"class":936},"(Calculator ",[919,2198,2199],{"class":961},"target",[919,2201,1129],{"class":936},[919,2203,2204,2208,2211,2213],{"class":921,"line":1008},[919,2205,2207],{"class":2206},"sBjJW","        this",[919,2209,2210],{"class":936},".target ",[919,2212,1144],{"class":925},[919,2214,2215],{"class":936}," target;\n",[919,2217,2218],{"class":921,"line":1030},[919,2219,1194],{"class":936},[919,2221,2222],{"class":921,"line":1035},[919,2223,943],{"class":936},[919,2225,2226,2228],{"class":921,"line":1057},[919,2227,1101],{"class":936},[919,2229,1104],{"class":925},[919,2231,2232,2234,2236,2238,2240,2242,2244,2246,2248,2250],{"class":921,"line":1062},[919,2233,1109],{"class":925},[919,2235,1112],{"class":925},[919,2237,952],{"class":932},[919,2239,955],{"class":936},[919,2241,958],{"class":925},[919,2243,962],{"class":961},[919,2245,965],{"class":936},[919,2247,958],{"class":925},[919,2249,970],{"class":961},[919,2251,1129],{"class":936},[919,2253,2254],{"class":921,"line":1197},[919,2255,943],{"class":936},[919,2257,2258],{"class":921,"line":1202},[919,2259,2260],{"class":2174},"        \u002F\u002F 附加功能由代理类中的代理方法来实现\n",[919,2262,2263,2265,2267,2269,2271,2273,2275,2277,2279,2281],{"class":921,"line":1209},[919,2264,1162],{"class":936},[919,2266,1165],{"class":932},[919,2268,955],{"class":936},[919,2270,1550],{"class":1170},[919,2272,1174],{"class":925},[919,2274,1147],{"class":936},[919,2276,1150],{"class":925},[919,2278,1559],{"class":1170},[919,2280,1174],{"class":925},[919,2282,1564],{"class":936},[919,2284,2285],{"class":921,"line":1232},[919,2286,943],{"class":936},[919,2288,2289],{"class":921,"line":1237},[919,2290,2291],{"class":2174},"        \u002F\u002F 通过目标对象来实现核心业务逻辑\n",[919,2293,2294,2296,2299,2301,2304,2307],{"class":921,"line":1253},[919,2295,1138],{"class":925},[919,2297,2298],{"class":936}," addResult ",[919,2300,1144],{"class":925},[919,2302,2303],{"class":936}," target.",[919,2305,2306],{"class":932},"add",[919,2308,2309],{"class":936},"(i, j);\n",[919,2311,2312],{"class":921,"line":1258},[919,2313,943],{"class":936},[919,2315,2316,2318,2320,2322,2324,2326],{"class":921,"line":1273},[919,2317,1162],{"class":936},[919,2319,1165],{"class":932},[919,2321,955],{"class":936},[919,2323,1615],{"class":1170},[919,2325,1174],{"class":925},[919,2327,2328],{"class":936}," addResult);\n",[919,2330,2331],{"class":921,"line":1278},[919,2332,943],{"class":936},[919,2334,2335,2337],{"class":921,"line":1285},[919,2336,1186],{"class":925},[919,2338,2339],{"class":936}," addResult;\n",[919,2341,2342],{"class":921,"line":1290},[919,2343,1194],{"class":936},[919,2345,2346],{"class":921,"line":1295},[919,2347,1065],{"class":936},[896,2349,2350],{},"静态代理确实实现了解耦，但是由于代码都写死了，完全不具备任何的灵活性。就拿日志功能来说，将来其他地方也需要附加日志，那还得再声明更多个静态代理类，那就产生了大量重复的代码，日志功能还是分散的，没有统一管理。",[896,2352,2353],{},"提出进一步的需求：将日志功能集中到一个代理类中，将来有任何日志需求，都通过这一个代理类来实现。这就需要使用动态代理技术了。",[2138,2355,2356],{"id":2356},"动态代理",[896,2358,2359],{},[2097,2360],{"alt":11,"src":2361},"\u002Fassets\u002Fjava\u002Fspring\u002Fspring-aop\u002F2024-01-01-20-37-03.png",[904,2363,2364],{},[907,2365,2366],{},"生产代理对象的工厂类：",[911,2368,2370],{"className":913,"code":2369,"language":915,"meta":11,"style":11},"public class ProxyFactory {\n\n    private Object target;\n\n    public ProxyFactory(Object target) {\n        this.target = target;\n    }\n\n    public Object getProxy(){\n\n        \u002F**\n         * newProxyInstance()：创建一个代理实例\n         * 其中有三个参数：\n         * 1、classLoader：加载动态生成的代理类的类加载器\n         * 2、interfaces：目标对象实现的所有接口的class对象所组成的数组\n         * 3、invocationHandler：设置代理对象实现目标对象方法的过程，即代理类中如何重写接口中的抽象方法\n         *\u002F\n        ClassLoader classLoader = target.getClass().getClassLoader();\n        Class\u003C?>[] interfaces = target.getClass().getInterfaces();\n        InvocationHandler invocationHandler = new InvocationHandler() {\n            @Override\n            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {\n                \u002F**\n                 * proxy：代理对象\n                 * method：代理对象需要实现的方法，即其中需要重写的方法\n                 * args：method所对应方法的参数\n                 *\u002F\n                Object result = null;\n                try {\n                    System.out.println(\"[动态代理][日志] \"+method.getName()+\"，参数：\"+ Arrays.toString(args));\n                    result = method.invoke(target, args);\n                    System.out.println(\"[动态代理][日志] \"+method.getName()+\"，结果：\"+ result);\n                } catch (Exception e) {\n                    e.printStackTrace();\n                    System.out.println(\"[动态代理][日志] \"+method.getName()+\"，异常：\"+e.getMessage());\n                } finally {\n                    System.out.println(\"[动态代理][日志] \"+method.getName()+\"，方法执行完毕\");\n                }\n                return result;\n            }\n        };\n\n        return Proxy.newProxyInstance(classLoader, interfaces, invocationHandler);\n    }\n}\n",[900,2371,2372,2383,2389,2396,2400,2413,2423,2427,2431,2444,2448,2453,2458,2463,2468,2473,2478,2483,2504,2528,2544,2551,2592,2597,2602,2607,2612,2617,2630,2637,2676,2691,2718,2734,2744,2778,2787,2812,2817,2824,2829,2834,2838,2851,2855],{"__ignoreMap":11},[919,2373,2374,2376,2378,2381],{"class":921,"line":922},[919,2375,926],{"class":925},[919,2377,1082],{"class":925},[919,2379,2380],{"class":932}," ProxyFactory",[919,2382,937],{"class":936},[919,2384,2385],{"class":921,"line":940},[919,2386,2388],{"emptyLinePlaceholder":2387},true,"\n",[919,2390,2391,2393],{"class":921,"line":946},[919,2392,2180],{"class":925},[919,2394,2395],{"class":936}," Object target;\n",[919,2397,2398],{"class":921,"line":976},[919,2399,2388],{"emptyLinePlaceholder":2387},[919,2401,2402,2404,2406,2409,2411],{"class":921,"line":981},[919,2403,1109],{"class":925},[919,2405,2380],{"class":932},[919,2407,2408],{"class":936},"(Object ",[919,2410,2199],{"class":961},[919,2412,1129],{"class":936},[919,2414,2415,2417,2419,2421],{"class":921,"line":1003},[919,2416,2207],{"class":2206},[919,2418,2210],{"class":936},[919,2420,1144],{"class":925},[919,2422,2215],{"class":936},[919,2424,2425],{"class":921,"line":1008},[919,2426,1194],{"class":936},[919,2428,2429],{"class":921,"line":1030},[919,2430,2388],{"emptyLinePlaceholder":2387},[919,2432,2433,2435,2438,2441],{"class":921,"line":1035},[919,2434,1109],{"class":925},[919,2436,2437],{"class":936}," Object ",[919,2439,2440],{"class":932},"getProxy",[919,2442,2443],{"class":936},"(){\n",[919,2445,2446],{"class":921,"line":1057},[919,2447,2388],{"emptyLinePlaceholder":2387},[919,2449,2450],{"class":921,"line":1062},[919,2451,2452],{"class":2174},"        \u002F**\n",[919,2454,2455],{"class":921,"line":1197},[919,2456,2457],{"class":2174},"         * newProxyInstance()：创建一个代理实例\n",[919,2459,2460],{"class":921,"line":1202},[919,2461,2462],{"class":2174},"         * 其中有三个参数：\n",[919,2464,2465],{"class":921,"line":1209},[919,2466,2467],{"class":2174},"         * 1、classLoader：加载动态生成的代理类的类加载器\n",[919,2469,2470],{"class":921,"line":1232},[919,2471,2472],{"class":2174},"         * 2、interfaces：目标对象实现的所有接口的class对象所组成的数组\n",[919,2474,2475],{"class":921,"line":1237},[919,2476,2477],{"class":2174},"         * 3、invocationHandler：设置代理对象实现目标对象方法的过程，即代理类中如何重写接口中的抽象方法\n",[919,2479,2480],{"class":921,"line":1253},[919,2481,2482],{"class":2174},"         *\u002F\n",[919,2484,2485,2488,2490,2492,2495,2498,2501],{"class":921,"line":1258},[919,2486,2487],{"class":936},"        ClassLoader classLoader ",[919,2489,1144],{"class":925},[919,2491,2303],{"class":936},[919,2493,2494],{"class":932},"getClass",[919,2496,2497],{"class":936},"().",[919,2499,2500],{"class":932},"getClassLoader",[919,2502,2503],{"class":936},"();\n",[919,2505,2506,2509,2512,2515,2517,2519,2521,2523,2526],{"class":921,"line":1273},[919,2507,2508],{"class":936},"        Class\u003C",[919,2510,2511],{"class":925},"?",[919,2513,2514],{"class":936},">[] interfaces ",[919,2516,1144],{"class":925},[919,2518,2303],{"class":936},[919,2520,2494],{"class":932},[919,2522,2497],{"class":936},[919,2524,2525],{"class":932},"getInterfaces",[919,2527,2503],{"class":936},[919,2529,2530,2533,2535,2538,2541],{"class":921,"line":1278},[919,2531,2532],{"class":936},"        InvocationHandler invocationHandler ",[919,2534,1144],{"class":925},[919,2536,2537],{"class":925}," new",[919,2539,2540],{"class":932}," InvocationHandler",[919,2542,2543],{"class":936},"() {\n",[919,2545,2546,2549],{"class":921,"line":1285},[919,2547,2548],{"class":936},"            @",[919,2550,1104],{"class":925},[919,2552,2553,2556,2558,2561,2563,2566,2569,2572,2574,2577,2580,2583,2586,2589],{"class":921,"line":1290},[919,2554,2555],{"class":925},"            public",[919,2557,2437],{"class":936},[919,2559,2560],{"class":932},"invoke",[919,2562,2408],{"class":936},[919,2564,2565],{"class":961},"proxy",[919,2567,2568],{"class":936},", Method ",[919,2570,2571],{"class":961},"method",[919,2573,965],{"class":936},[919,2575,2576],{"class":925},"Object",[919,2578,2579],{"class":936},"[] ",[919,2581,2582],{"class":961},"args",[919,2584,2585],{"class":936},") ",[919,2587,2588],{"class":925},"throws",[919,2590,2591],{"class":936}," Throwable {\n",[919,2593,2594],{"class":921,"line":1295},[919,2595,2596],{"class":2174},"                \u002F**\n",[919,2598,2599],{"class":921,"line":1302},[919,2600,2601],{"class":2174},"                 * proxy：代理对象\n",[919,2603,2604],{"class":921,"line":1325},[919,2605,2606],{"class":2174},"                 * method：代理对象需要实现的方法，即其中需要重写的方法\n",[919,2608,2609],{"class":921,"line":1330},[919,2610,2611],{"class":2174},"                 * args：method所对应方法的参数\n",[919,2613,2614],{"class":921,"line":1346},[919,2615,2616],{"class":2174},"                 *\u002F\n",[919,2618,2619,2622,2624,2627],{"class":921,"line":1351},[919,2620,2621],{"class":936},"                Object result ",[919,2623,1144],{"class":925},[919,2625,2626],{"class":2206}," null",[919,2628,2629],{"class":936},";\n",[919,2631,2632,2635],{"class":921,"line":1366},[919,2633,2634],{"class":925},"                try",[919,2636,937],{"class":936},[919,2638,2639,2642,2644,2646,2649,2651,2654,2657,2660,2662,2665,2667,2670,2673],{"class":921,"line":1371},[919,2640,2641],{"class":936},"                    System.out.",[919,2643,1165],{"class":932},[919,2645,955],{"class":936},[919,2647,2648],{"class":1170},"\"[动态代理][日志] \"",[919,2650,1150],{"class":925},[919,2652,2653],{"class":936},"method.",[919,2655,2656],{"class":932},"getName",[919,2658,2659],{"class":936},"()",[919,2661,1150],{"class":925},[919,2663,2664],{"class":1170},"\"，参数：\"",[919,2666,1150],{"class":925},[919,2668,2669],{"class":936}," Arrays.",[919,2671,2672],{"class":932},"toString",[919,2674,2675],{"class":936},"(args));\n",[919,2677,2678,2681,2683,2686,2688],{"class":921,"line":1378},[919,2679,2680],{"class":936},"                    result ",[919,2682,1144],{"class":925},[919,2684,2685],{"class":936}," method.",[919,2687,2560],{"class":932},[919,2689,2690],{"class":936},"(target, args);\n",[919,2692,2693,2695,2697,2699,2701,2703,2705,2707,2709,2711,2714,2716],{"class":921,"line":1383},[919,2694,2641],{"class":936},[919,2696,1165],{"class":932},[919,2698,955],{"class":936},[919,2700,2648],{"class":1170},[919,2702,1150],{"class":925},[919,2704,2653],{"class":936},[919,2706,2656],{"class":932},[919,2708,2659],{"class":936},[919,2710,1150],{"class":925},[919,2712,2713],{"class":1170},"\"，结果：\"",[919,2715,1150],{"class":925},[919,2717,1177],{"class":936},[919,2719,2720,2723,2726,2729,2732],{"class":921,"line":1388},[919,2721,2722],{"class":936},"                } ",[919,2724,2725],{"class":925},"catch",[919,2727,2728],{"class":936}," (Exception ",[919,2730,2731],{"class":961},"e",[919,2733,1129],{"class":936},[919,2735,2736,2739,2742],{"class":921,"line":1395},[919,2737,2738],{"class":936},"                    e.",[919,2740,2741],{"class":932},"printStackTrace",[919,2743,2503],{"class":936},[919,2745,2746,2748,2750,2752,2754,2756,2758,2760,2762,2764,2767,2769,2772,2775],{"class":921,"line":1418},[919,2747,2641],{"class":936},[919,2749,1165],{"class":932},[919,2751,955],{"class":936},[919,2753,2648],{"class":1170},[919,2755,1150],{"class":925},[919,2757,2653],{"class":936},[919,2759,2656],{"class":932},[919,2761,2659],{"class":936},[919,2763,1150],{"class":925},[919,2765,2766],{"class":1170},"\"，异常：\"",[919,2768,1150],{"class":925},[919,2770,2771],{"class":936},"e.",[919,2773,2774],{"class":932},"getMessage",[919,2776,2777],{"class":936},"());\n",[919,2779,2780,2782,2785],{"class":921,"line":1423},[919,2781,2722],{"class":936},[919,2783,2784],{"class":925},"finally",[919,2786,937],{"class":936},[919,2788,2789,2791,2793,2795,2797,2799,2801,2803,2805,2807,2810],{"class":921,"line":1439},[919,2790,2641],{"class":936},[919,2792,1165],{"class":932},[919,2794,955],{"class":936},[919,2796,2648],{"class":1170},[919,2798,1150],{"class":925},[919,2800,2653],{"class":936},[919,2802,2656],{"class":932},[919,2804,2659],{"class":936},[919,2806,1150],{"class":925},[919,2808,2809],{"class":1170},"\"，方法执行完毕\"",[919,2811,973],{"class":936},[919,2813,2814],{"class":921,"line":1444},[919,2815,2816],{"class":936},"                }\n",[919,2818,2819,2822],{"class":921,"line":1459},[919,2820,2821],{"class":925},"                return",[919,2823,1189],{"class":936},[919,2825,2826],{"class":921,"line":1464},[919,2827,2828],{"class":936},"            }\n",[919,2830,2831],{"class":921,"line":1471},[919,2832,2833],{"class":936},"        };\n",[919,2835,2836],{"class":921,"line":1476},[919,2837,2388],{"emptyLinePlaceholder":2387},[919,2839,2840,2842,2845,2848],{"class":921,"line":1888},[919,2841,1186],{"class":925},[919,2843,2844],{"class":936}," Proxy.",[919,2846,2847],{"class":932},"newProxyInstance",[919,2849,2850],{"class":936},"(classLoader, interfaces, invocationHandler);\n",[919,2852,2853],{"class":921,"line":1893},[919,2854,1194],{"class":936},[919,2856,2857],{"class":921,"line":1898},[919,2858,1065],{"class":936},[904,2860,2861],{},[907,2862,2863],{},"测试",[911,2865,2867],{"className":913,"code":2866,"language":915,"meta":11,"style":11},"@Test\npublic void testDynamicProxy(){\n    ProxyFactory factory = new ProxyFactory(new CalculatorLogImpl());\n    Calculator proxy = (Calculator) factory.getProxy();\n    proxy.div(1,1);    \u002F\u002F 参数正常时可以正常运行\n    \u002F\u002F proxy.div(1,0); \u002F\u002F 在数学中，除法的除数不能为0，否则没意义。在实际的 Java 运算中则会报错。\n}\n",[900,2868,2869,2877,2889,2909,2923,2947,2955],{"__ignoreMap":11},[919,2870,2871,2874],{"class":921,"line":922},[919,2872,2873],{"class":936},"@",[919,2875,2876],{"class":925},"Test\n",[919,2878,2879,2881,2884,2887],{"class":921,"line":940},[919,2880,926],{"class":925},[919,2882,2883],{"class":925}," void",[919,2885,2886],{"class":932}," testDynamicProxy",[919,2888,2443],{"class":936},[919,2890,2891,2894,2896,2898,2900,2902,2905,2907],{"class":921,"line":946},[919,2892,2893],{"class":936},"    ProxyFactory factory ",[919,2895,1144],{"class":925},[919,2897,2537],{"class":925},[919,2899,2380],{"class":932},[919,2901,955],{"class":936},[919,2903,2904],{"class":925},"new",[919,2906,1497],{"class":932},[919,2908,2777],{"class":936},[919,2910,2911,2914,2916,2919,2921],{"class":921,"line":976},[919,2912,2913],{"class":936},"    Calculator proxy ",[919,2915,1144],{"class":925},[919,2917,2918],{"class":936}," (Calculator) factory.",[919,2920,2440],{"class":932},[919,2922,2503],{"class":936},[919,2924,2925,2928,2931,2933,2936,2939,2941,2944],{"class":921,"line":981},[919,2926,2927],{"class":936},"    proxy.",[919,2929,2930],{"class":932},"div",[919,2932,955],{"class":936},[919,2934,2935],{"class":2206},"1",[919,2937,2938],{"class":936},",",[919,2940,2935],{"class":2206},[919,2942,2943],{"class":936},");    ",[919,2945,2946],{"class":2174},"\u002F\u002F 参数正常时可以正常运行\n",[919,2948,2949,2952],{"class":921,"line":1003},[919,2950,2951],{"class":2174},"    \u002F\u002F proxy.div(1,0);",[919,2953,2954],{"class":2174}," \u002F\u002F 在数学中，除法的除数不能为0，否则没意义。在实际的 Java 运算中则会报错。\n",[919,2956,2957],{"class":921,"line":1008},[919,2958,1065],{"class":936},[896,2960,2961],{},[2097,2962],{"alt":2963,"src":2964},"参数正常","\u002Fassets\u002Fjava\u002Fspring\u002Fspring-aop\u002F2024-01-01-20-40-05.png",[896,2966,2967],{},[2097,2968],{"alt":2969,"src":2970},"参数异常","\u002Fassets\u002Fjava\u002Fspring\u002Fspring-aop\u002F2024-01-01-20-40-47.png",[892,2972,2974],{"id":2973},"aop概念及相关术语","AOP概念及相关术语",[2138,2976,2977],{"id":2977},"概述",[896,2979,2980],{},"AOP（Aspect Oriented Programming）是一种设计思想，是软件设计领域中的面向切面编程，它是面向对象编程的一种补充和完善，它以通过预编译方式和运行期动态代理方式实现，在不修改源代码的情况下，给程序动态统一添加额外功能的一种技术。利用AOP可以对业务逻辑的各个部分进行隔离，从而使得业务逻辑各部分之间的耦合度降低，提高程序的可重用性，同时提高了开发的效率。",[2138,2982,2983],{"id":2983},"相关术语",[2055,2985,2986],{},[907,2987,2988],{},[2060,2989,2990],{},"横切关注点",[896,2992,2993],{},"分散在每个各个模块中解决同一样的问题，如用户验证、日志管理、事务处理、数据缓存都属于横切关注点。",[896,2995,2996],{},"从每个方法中抽取出来的同一类非核心业务。在同一个项目中，我们可以使用多个横切关注点对相关方法进行多个不同方面的增强。",[896,2998,2999],{},"这个概念不是语法层面的，而是根据附加功能的逻辑上的需要：有十个附加功能，就有十个横切关注点。",[896,3001,3002],{},[2097,3003],{"alt":11,"src":3004},"\u002Fassets\u002Fjava\u002Fspring\u002Fspring-aop\u002F2024-01-01-20-47-24.png",[2055,3006,3007],{"start":940},[907,3008,3009],{},[2060,3010,3011],{},"通知（增强）",[896,3013,3014],{},[2060,3015,3016],{},"增强，通俗说，就是你想要增强的功能，比如 安全，事务，日志等。",[896,3018,3019],{},"每一个横切关注点上要做的事情都需要写一个方法来实现，这样的方法就叫通知方法。",[904,3021,3022,3029,3040,3049,3058],{},[907,3023,3024,3025,3028],{},"前置通知：在被代理的目标方法",[2060,3026,3027],{},"前","执行",[907,3030,3031,3032,3035,3036,3039],{},"返回通知：在被代理的目标方法",[2060,3033,3034],{},"成功结束","后执行（",[2060,3037,3038],{},"寿终正寝","）",[907,3041,3042,3043,3035,3046,3039],{},"异常通知：在被代理的目标方法",[2060,3044,3045],{},"异常结束",[2060,3047,3048],{},"死于非命",[907,3050,3051,3052,3035,3055,3039],{},"后置通知：在被代理的目标方法",[2060,3053,3054],{},"最终结束",[2060,3056,3057],{},"盖棺定论",[907,3059,3060,3061,3064],{},"环绕通知：使用try...catch...finally结构围绕",[2060,3062,3063],{},"整个","被代理的目标方法，包括上面四种通知对应的所有位置",[896,3066,3067],{},[2097,3068],{"alt":11,"src":3069},"\u002Fassets\u002Fjava\u002Fspring\u002Fspring-aop\u002F2024-01-01-20-47-39.png",[2055,3071,3072],{"start":946},[907,3073,3074],{},[2060,3075,3076],{},"切面",[896,3078,3079],{},"封装通知方法的类。",[896,3081,3082],{},[2097,3083],{"alt":11,"src":3084},"\u002Fassets\u002Fjava\u002Fspring\u002Fspring-aop\u002F2024-01-01-20-47-51.png",[2055,3086,3087],{"start":976},[907,3088,3089],{},[2060,3090,3091],{},"目标",[896,3093,3094],{},"被代理的目标对象。",[2055,3096,3097],{"start":981},[907,3098,3099],{},[2060,3100,3101],{},"代理",[896,3103,3104],{},"向目标对象应用通知之后创建的代理对象。",[2055,3106,3107],{"start":1003},[907,3108,3109],{},[2060,3110,3111],{},"连接点",[896,3113,3114],{},"这也是一个纯逻辑概念，不是语法定义的。",[896,3116,3117,3118],{},"把方法排成一排，每一个横切位置看成x轴方向，把方法从上到下执行的顺序看成y轴，x轴和y轴的交叉点就是连接点。",[2060,3119,3120],{},"通俗说，就是spring允许你使用通知的地方",[896,3122,3123],{},[2097,3124],{"alt":11,"src":3125},"\u002Fassets\u002Fjava\u002Fspring\u002Fspring-aop\u002F2024-01-01-20-48-23.png",[2055,3127,3128],{"start":1008},[907,3129,3130],{},[2060,3131,3132],{},"切入点",[896,3134,3135],{},"定位连接点的方式。",[896,3137,3138],{},"每个类的方法中都包含多个连接点，所以连接点是类中客观存在的事物（从逻辑上来说）。",[896,3140,3141],{},"如果把连接点看作数据库中的记录，那么切入点就是查询记录的 SQL 语句。",[896,3143,3144],{},[2060,3145,3146],{},"Spring 的 AOP 技术可以通过切入点定位到特定的连接点。通俗说，要实际去增强的方法",[896,3148,3149],{},"切点通过 org.springframework.aop.Pointcut 接口进行描述，它使用类和方法作为连接点的查询条件。",[2080,3151,3153,3154,3163,3167,3170,3178,3213,3216,3221,3224,3626,3631,3636,3754,3759,4117,4120,4733,4738,4921,4926,5113,5116,5122,5125,5158,5161,5164,5172,5177,5249,5254,5257,5264,5295,5302,5392,5399,5485,5488,5493,5496,5591,5596,5599,5681,5686,5689,5771,5774,5963,5966,5973,5981,5984,5992,5997,6001,6004,6007,6010],{"title":3152},"作用","\n- 简化代码：把方法中固定位置的重复的代码**抽取**出来，让被抽取的方法更专注于自己的核心功能，提高内聚性。\n",[904,3155,3156],{},[907,3157,3158,3159,3162],{},"代码增强：把特定的功能封装到切面类中，看哪里有需要，就往上套，被",[2060,3160,3161],{},"套用","了切面逻辑的方法就被切面给增强了。\n\n",[892,3164,3166],{"id":3165},"基于注解的aop","基于注解的AOP",[2138,3168,3169],{"id":3169},"技术说明",[896,3171,3172,3175],{},[2097,3173],{"alt":11,"src":3174},"\u002Fassets\u002Fjava\u002Fspring\u002Fspring-aop\u002F2024-01-01-20-56-27.png",[2097,3176],{"alt":11,"src":3177},"\u002Fassets\u002Fjava\u002Fspring\u002Fspring-aop\u002F2024-01-01-20-56-44.png",[904,3179,3180,3183,3186,3189,3192,3199,3206],{},[907,3181,3182],{},"动态代理分为JDK动态代理和cglib动态代理",[907,3184,3185],{},"当目标类有接口的情况使用JDK动态代理和cglib动态代理，没有接口时只能使用cglib动态代理",[907,3187,3188],{},"JDK动态代理动态生成的代理类会在com.sun.proxy包下，类名为$proxy1，和目标类实现相同的接口",[907,3190,3191],{},"cglib动态代理动态生成的代理类会和目标在在相同的包下，会继承目标类",[907,3193,3194,3195,3198],{},"动态代理（InvocationHandler）：JDK原生的实现方式，需要被代理的目标类必须实现接口。因为这个技术要求",[2060,3196,3197],{},"代理对象和目标对象实现同样的接口","（兄弟两个拜把子模式）。",[907,3200,3201,3202,3205],{},"cglib：通过",[2060,3203,3204],{},"继承被代理的目标类","（认干爹模式）实现代理，所以不需要目标类实现接口。",[907,3207,3208,3209,3212],{},"AspectJ：是AOP思想的一种实现。本质上是静态代理，",[2060,3210,3211],{},"将代理逻辑“织入”被代理的目标类编译得到的字节码文件","，所以最终效果是动态的。weaver就是织入器。Spring只是借用了AspectJ中的注解。",[2138,3214,3215],{"id":3215},"准备工作",[904,3217,3218],{},[907,3219,3220],{},"添加依赖",[896,3222,3223],{},"在 IOC 所需依赖的基础上再加入下面依赖即可：",[911,3225,3229],{"className":3226,"code":3227,"language":3228,"meta":11,"style":11},"language-xml shiki shiki-themes github-light github-light github-dark","\u003Cdependencies>\n    \u003C!--spring context依赖-->\n    \u003C!--当你引入Spring Context依赖之后，表示将Spring的基础引入了-->\n    \u003Cdependency>\n        \u003CgroupId>org.springframework\u003C\u002FgroupId>\n        \u003CartifactId>spring-context\u003C\u002FartifactId>\n        \u003Cversion>6.0.2\u003C\u002Fversion>\n    \u003C\u002Fdependency>\n\n    \u003C!--spring aop依赖-->\n    \u003Cdependency>\n        \u003CgroupId>org.springframework\u003C\u002FgroupId>\n        \u003CartifactId>spring-aop\u003C\u002FartifactId>\n        \u003Cversion>6.0.2\u003C\u002Fversion>\n    \u003C\u002Fdependency>\n    \u003C!--spring aspects依赖-->\n    \u003Cdependency>\n        \u003CgroupId>org.springframework\u003C\u002FgroupId>\n        \u003CartifactId>spring-aspects\u003C\u002FartifactId>\n        \u003Cversion>6.0.11\u003C\u002Fversion>\n    \u003C\u002Fdependency>\n\n    \u003C!--junit5测试-->\n    \u003Cdependency>\n        \u003CgroupId>org.junit.jupiter\u003C\u002FgroupId>\n        \u003CartifactId>junit-jupiter-api\u003C\u002FartifactId>\n        \u003Cversion>5.3.1\u003C\u002Fversion>\n    \u003C\u002Fdependency>\n\n    \u003C!--log4j2的依赖-->\n    \u003Cdependency>\n        \u003CgroupId>org.apache.logging.log4j\u003C\u002FgroupId>\n        \u003CartifactId>log4j-core\u003C\u002FartifactId>\n        \u003Cversion>2.19.0\u003C\u002Fversion>\n    \u003C\u002Fdependency>\n    \u003Cdependency>\n        \u003CgroupId>org.apache.logging.log4j\u003C\u002FgroupId>\n        \u003CartifactId>log4j-slf4j2-impl\u003C\u002FartifactId>\n        \u003Cversion>2.19.0\u003C\u002Fversion>\n    \u003C\u002Fdependency>\n\u003C\u002Fdependencies>\n","xml",[900,3230,3231,3243,3248,3253,3263,3278,3292,3306,3315,3319,3324,3332,3344,3357,3369,3377,3382,3390,3402,3415,3428,3436,3440,3445,3453,3466,3479,3492,3500,3504,3509,3517,3530,3543,3556,3564,3572,3584,3597,3609,3617],{"__ignoreMap":11},[919,3232,3233,3236,3240],{"class":921,"line":922},[919,3234,3235],{"class":936},"\u003C",[919,3237,3239],{"class":3238},"sovSZ","dependencies",[919,3241,3242],{"class":936},">\n",[919,3244,3245],{"class":921,"line":940},[919,3246,3247],{"class":2174},"    \u003C!--spring context依赖-->\n",[919,3249,3250],{"class":921,"line":946},[919,3251,3252],{"class":2174},"    \u003C!--当你引入Spring Context依赖之后，表示将Spring的基础引入了-->\n",[919,3254,3255,3258,3261],{"class":921,"line":976},[919,3256,3257],{"class":936},"    \u003C",[919,3259,3260],{"class":3238},"dependency",[919,3262,3242],{"class":936},[919,3264,3265,3268,3271,3274,3276],{"class":921,"line":981},[919,3266,3267],{"class":936},"        \u003C",[919,3269,3270],{"class":3238},"groupId",[919,3272,3273],{"class":936},">org.springframework\u003C\u002F",[919,3275,3270],{"class":3238},[919,3277,3242],{"class":936},[919,3279,3280,3282,3285,3288,3290],{"class":921,"line":1003},[919,3281,3267],{"class":936},[919,3283,3284],{"class":3238},"artifactId",[919,3286,3287],{"class":936},">spring-context\u003C\u002F",[919,3289,3284],{"class":3238},[919,3291,3242],{"class":936},[919,3293,3294,3296,3299,3302,3304],{"class":921,"line":1008},[919,3295,3267],{"class":936},[919,3297,3298],{"class":3238},"version",[919,3300,3301],{"class":936},">6.0.2\u003C\u002F",[919,3303,3298],{"class":3238},[919,3305,3242],{"class":936},[919,3307,3308,3311,3313],{"class":921,"line":1030},[919,3309,3310],{"class":936},"    \u003C\u002F",[919,3312,3260],{"class":3238},[919,3314,3242],{"class":936},[919,3316,3317],{"class":921,"line":1035},[919,3318,2388],{"emptyLinePlaceholder":2387},[919,3320,3321],{"class":921,"line":1057},[919,3322,3323],{"class":2174},"    \u003C!--spring aop依赖-->\n",[919,3325,3326,3328,3330],{"class":921,"line":1062},[919,3327,3257],{"class":936},[919,3329,3260],{"class":3238},[919,3331,3242],{"class":936},[919,3333,3334,3336,3338,3340,3342],{"class":921,"line":1197},[919,3335,3267],{"class":936},[919,3337,3270],{"class":3238},[919,3339,3273],{"class":936},[919,3341,3270],{"class":3238},[919,3343,3242],{"class":936},[919,3345,3346,3348,3350,3353,3355],{"class":921,"line":1202},[919,3347,3267],{"class":936},[919,3349,3284],{"class":3238},[919,3351,3352],{"class":936},">spring-aop\u003C\u002F",[919,3354,3284],{"class":3238},[919,3356,3242],{"class":936},[919,3358,3359,3361,3363,3365,3367],{"class":921,"line":1209},[919,3360,3267],{"class":936},[919,3362,3298],{"class":3238},[919,3364,3301],{"class":936},[919,3366,3298],{"class":3238},[919,3368,3242],{"class":936},[919,3370,3371,3373,3375],{"class":921,"line":1232},[919,3372,3310],{"class":936},[919,3374,3260],{"class":3238},[919,3376,3242],{"class":936},[919,3378,3379],{"class":921,"line":1237},[919,3380,3381],{"class":2174},"    \u003C!--spring aspects依赖-->\n",[919,3383,3384,3386,3388],{"class":921,"line":1253},[919,3385,3257],{"class":936},[919,3387,3260],{"class":3238},[919,3389,3242],{"class":936},[919,3391,3392,3394,3396,3398,3400],{"class":921,"line":1258},[919,3393,3267],{"class":936},[919,3395,3270],{"class":3238},[919,3397,3273],{"class":936},[919,3399,3270],{"class":3238},[919,3401,3242],{"class":936},[919,3403,3404,3406,3408,3411,3413],{"class":921,"line":1273},[919,3405,3267],{"class":936},[919,3407,3284],{"class":3238},[919,3409,3410],{"class":936},">spring-aspects\u003C\u002F",[919,3412,3284],{"class":3238},[919,3414,3242],{"class":936},[919,3416,3417,3419,3421,3424,3426],{"class":921,"line":1278},[919,3418,3267],{"class":936},[919,3420,3298],{"class":3238},[919,3422,3423],{"class":936},">6.0.11\u003C\u002F",[919,3425,3298],{"class":3238},[919,3427,3242],{"class":936},[919,3429,3430,3432,3434],{"class":921,"line":1285},[919,3431,3310],{"class":936},[919,3433,3260],{"class":3238},[919,3435,3242],{"class":936},[919,3437,3438],{"class":921,"line":1290},[919,3439,2388],{"emptyLinePlaceholder":2387},[919,3441,3442],{"class":921,"line":1295},[919,3443,3444],{"class":2174},"    \u003C!--junit5测试-->\n",[919,3446,3447,3449,3451],{"class":921,"line":1302},[919,3448,3257],{"class":936},[919,3450,3260],{"class":3238},[919,3452,3242],{"class":936},[919,3454,3455,3457,3459,3462,3464],{"class":921,"line":1325},[919,3456,3267],{"class":936},[919,3458,3270],{"class":3238},[919,3460,3461],{"class":936},">org.junit.jupiter\u003C\u002F",[919,3463,3270],{"class":3238},[919,3465,3242],{"class":936},[919,3467,3468,3470,3472,3475,3477],{"class":921,"line":1330},[919,3469,3267],{"class":936},[919,3471,3284],{"class":3238},[919,3473,3474],{"class":936},">junit-jupiter-api\u003C\u002F",[919,3476,3284],{"class":3238},[919,3478,3242],{"class":936},[919,3480,3481,3483,3485,3488,3490],{"class":921,"line":1346},[919,3482,3267],{"class":936},[919,3484,3298],{"class":3238},[919,3486,3487],{"class":936},">5.3.1\u003C\u002F",[919,3489,3298],{"class":3238},[919,3491,3242],{"class":936},[919,3493,3494,3496,3498],{"class":921,"line":1351},[919,3495,3310],{"class":936},[919,3497,3260],{"class":3238},[919,3499,3242],{"class":936},[919,3501,3502],{"class":921,"line":1366},[919,3503,2388],{"emptyLinePlaceholder":2387},[919,3505,3506],{"class":921,"line":1371},[919,3507,3508],{"class":2174},"    \u003C!--log4j2的依赖-->\n",[919,3510,3511,3513,3515],{"class":921,"line":1378},[919,3512,3257],{"class":936},[919,3514,3260],{"class":3238},[919,3516,3242],{"class":936},[919,3518,3519,3521,3523,3526,3528],{"class":921,"line":1383},[919,3520,3267],{"class":936},[919,3522,3270],{"class":3238},[919,3524,3525],{"class":936},">org.apache.logging.log4j\u003C\u002F",[919,3527,3270],{"class":3238},[919,3529,3242],{"class":936},[919,3531,3532,3534,3536,3539,3541],{"class":921,"line":1388},[919,3533,3267],{"class":936},[919,3535,3284],{"class":3238},[919,3537,3538],{"class":936},">log4j-core\u003C\u002F",[919,3540,3284],{"class":3238},[919,3542,3242],{"class":936},[919,3544,3545,3547,3549,3552,3554],{"class":921,"line":1395},[919,3546,3267],{"class":936},[919,3548,3298],{"class":3238},[919,3550,3551],{"class":936},">2.19.0\u003C\u002F",[919,3553,3298],{"class":3238},[919,3555,3242],{"class":936},[919,3557,3558,3560,3562],{"class":921,"line":1418},[919,3559,3310],{"class":936},[919,3561,3260],{"class":3238},[919,3563,3242],{"class":936},[919,3565,3566,3568,3570],{"class":921,"line":1423},[919,3567,3257],{"class":936},[919,3569,3260],{"class":3238},[919,3571,3242],{"class":936},[919,3573,3574,3576,3578,3580,3582],{"class":921,"line":1439},[919,3575,3267],{"class":936},[919,3577,3270],{"class":3238},[919,3579,3525],{"class":936},[919,3581,3270],{"class":3238},[919,3583,3242],{"class":936},[919,3585,3586,3588,3590,3593,3595],{"class":921,"line":1444},[919,3587,3267],{"class":936},[919,3589,3284],{"class":3238},[919,3591,3592],{"class":936},">log4j-slf4j2-impl\u003C\u002F",[919,3594,3284],{"class":3238},[919,3596,3242],{"class":936},[919,3598,3599,3601,3603,3605,3607],{"class":921,"line":1459},[919,3600,3267],{"class":936},[919,3602,3298],{"class":3238},[919,3604,3551],{"class":936},[919,3606,3298],{"class":3238},[919,3608,3242],{"class":936},[919,3610,3611,3613,3615],{"class":921,"line":1464},[919,3612,3310],{"class":936},[919,3614,3260],{"class":3238},[919,3616,3242],{"class":936},[919,3618,3619,3622,3624],{"class":921,"line":1471},[919,3620,3621],{"class":936},"\u003C\u002F",[919,3623,3239],{"class":3238},[919,3625,3242],{"class":936},[904,3627,3628],{},[907,3629,3630],{},"准备被代理的目标资源",[896,3632,3633],{},[2060,3634,3635],{},"接口",[911,3637,3638],{"className":913,"code":914,"language":915,"meta":11,"style":11},[900,3639,3640,3650,3654,3674,3678,3698,3702,3722,3726,3746,3750],{"__ignoreMap":11},[919,3641,3642,3644,3646,3648],{"class":921,"line":922},[919,3643,926],{"class":925},[919,3645,929],{"class":925},[919,3647,933],{"class":932},[919,3649,937],{"class":936},[919,3651,3652],{"class":921,"line":940},[919,3653,943],{"class":936},[919,3655,3656,3658,3660,3662,3664,3666,3668,3670,3672],{"class":921,"line":946},[919,3657,949],{"class":925},[919,3659,952],{"class":932},[919,3661,955],{"class":936},[919,3663,958],{"class":925},[919,3665,962],{"class":961},[919,3667,965],{"class":936},[919,3669,958],{"class":925},[919,3671,970],{"class":961},[919,3673,973],{"class":936},[919,3675,3676],{"class":921,"line":976},[919,3677,943],{"class":936},[919,3679,3680,3682,3684,3686,3688,3690,3692,3694,3696],{"class":921,"line":981},[919,3681,949],{"class":925},[919,3683,986],{"class":932},[919,3685,955],{"class":936},[919,3687,958],{"class":925},[919,3689,962],{"class":961},[919,3691,965],{"class":936},[919,3693,958],{"class":925},[919,3695,970],{"class":961},[919,3697,973],{"class":936},[919,3699,3700],{"class":921,"line":1003},[919,3701,943],{"class":936},[919,3703,3704,3706,3708,3710,3712,3714,3716,3718,3720],{"class":921,"line":1008},[919,3705,949],{"class":925},[919,3707,1013],{"class":932},[919,3709,955],{"class":936},[919,3711,958],{"class":925},[919,3713,962],{"class":961},[919,3715,965],{"class":936},[919,3717,958],{"class":925},[919,3719,970],{"class":961},[919,3721,973],{"class":936},[919,3723,3724],{"class":921,"line":1030},[919,3725,943],{"class":936},[919,3727,3728,3730,3732,3734,3736,3738,3740,3742,3744],{"class":921,"line":1035},[919,3729,949],{"class":925},[919,3731,1040],{"class":932},[919,3733,955],{"class":936},[919,3735,958],{"class":925},[919,3737,962],{"class":961},[919,3739,965],{"class":936},[919,3741,958],{"class":925},[919,3743,970],{"class":961},[919,3745,973],{"class":936},[919,3747,3748],{"class":921,"line":1057},[919,3749,943],{"class":936},[919,3751,3752],{"class":921,"line":1062},[919,3753,1065],{"class":936},[896,3755,3756],{},[2060,3757,3758],{},"实现类",[911,3760,3762],{"className":913,"code":3761,"language":915,"meta":11,"style":11},"@Component\npublic class CalculatorImpl implements Calculator {\n    \n    @Override\n    public int add(int i, int j) {\n    \n        int result = i + j;\n    \n        System.out.println(\"方法内部 result = \" + result);\n    \n        return result;\n    }\n    \n    @Override\n    public int sub(int i, int j) {\n    \n        int result = i - j;\n    \n        System.out.println(\"方法内部 result = \" + result);\n    \n        return result;\n    }\n    \n    @Override\n    public int mul(int i, int j) {\n    \n        int result = i * j;\n    \n        System.out.println(\"方法内部 result = \" + result);\n    \n        return result;\n    }\n    \n    @Override\n    public int div(int i, int j) {\n    \n        int result = i \u002F j;\n    \n        System.out.println(\"方法内部 result = \" + result);\n    \n        return result;\n    }\n}\n",[900,3763,3764,3771,3785,3789,3795,3817,3821,3835,3839,3853,3857,3863,3867,3871,3877,3899,3903,3917,3921,3935,3939,3945,3949,3953,3959,3981,3985,3999,4003,4017,4021,4027,4031,4035,4041,4063,4067,4081,4085,4099,4103,4109,4113],{"__ignoreMap":11},[919,3765,3766,3768],{"class":921,"line":922},[919,3767,2873],{"class":936},[919,3769,3770],{"class":925},"Component\n",[919,3772,3773,3775,3777,3779,3781,3783],{"class":921,"line":940},[919,3774,926],{"class":925},[919,3776,1082],{"class":925},[919,3778,1085],{"class":932},[919,3780,1088],{"class":925},[919,3782,933],{"class":932},[919,3784,937],{"class":936},[919,3786,3787],{"class":921,"line":946},[919,3788,943],{"class":936},[919,3790,3791,3793],{"class":921,"line":976},[919,3792,1101],{"class":936},[919,3794,1104],{"class":925},[919,3796,3797,3799,3801,3803,3805,3807,3809,3811,3813,3815],{"class":921,"line":981},[919,3798,1109],{"class":925},[919,3800,1112],{"class":925},[919,3802,952],{"class":932},[919,3804,955],{"class":936},[919,3806,958],{"class":925},[919,3808,962],{"class":961},[919,3810,965],{"class":936},[919,3812,958],{"class":925},[919,3814,970],{"class":961},[919,3816,1129],{"class":936},[919,3818,3819],{"class":921,"line":1003},[919,3820,943],{"class":936},[919,3822,3823,3825,3827,3829,3831,3833],{"class":921,"line":1008},[919,3824,1138],{"class":925},[919,3826,1141],{"class":936},[919,3828,1144],{"class":925},[919,3830,1147],{"class":936},[919,3832,1150],{"class":925},[919,3834,1153],{"class":936},[919,3836,3837],{"class":921,"line":1030},[919,3838,943],{"class":936},[919,3840,3841,3843,3845,3847,3849,3851],{"class":921,"line":1035},[919,3842,1162],{"class":936},[919,3844,1165],{"class":932},[919,3846,955],{"class":936},[919,3848,1171],{"class":1170},[919,3850,1174],{"class":925},[919,3852,1177],{"class":936},[919,3854,3855],{"class":921,"line":1057},[919,3856,943],{"class":936},[919,3858,3859,3861],{"class":921,"line":1062},[919,3860,1186],{"class":925},[919,3862,1189],{"class":936},[919,3864,3865],{"class":921,"line":1197},[919,3866,1194],{"class":936},[919,3868,3869],{"class":921,"line":1202},[919,3870,943],{"class":936},[919,3872,3873,3875],{"class":921,"line":1209},[919,3874,1101],{"class":936},[919,3876,1104],{"class":925},[919,3878,3879,3881,3883,3885,3887,3889,3891,3893,3895,3897],{"class":921,"line":1232},[919,3880,1109],{"class":925},[919,3882,1112],{"class":925},[919,3884,986],{"class":932},[919,3886,955],{"class":936},[919,3888,958],{"class":925},[919,3890,962],{"class":961},[919,3892,965],{"class":936},[919,3894,958],{"class":925},[919,3896,970],{"class":961},[919,3898,1129],{"class":936},[919,3900,3901],{"class":921,"line":1237},[919,3902,943],{"class":936},[919,3904,3905,3907,3909,3911,3913,3915],{"class":921,"line":1253},[919,3906,1138],{"class":925},[919,3908,1141],{"class":936},[919,3910,1144],{"class":925},[919,3912,1147],{"class":936},[919,3914,1248],{"class":925},[919,3916,1153],{"class":936},[919,3918,3919],{"class":921,"line":1258},[919,3920,943],{"class":936},[919,3922,3923,3925,3927,3929,3931,3933],{"class":921,"line":1273},[919,3924,1162],{"class":936},[919,3926,1165],{"class":932},[919,3928,955],{"class":936},[919,3930,1171],{"class":1170},[919,3932,1174],{"class":925},[919,3934,1177],{"class":936},[919,3936,3937],{"class":921,"line":1278},[919,3938,943],{"class":936},[919,3940,3941,3943],{"class":921,"line":1285},[919,3942,1186],{"class":925},[919,3944,1189],{"class":936},[919,3946,3947],{"class":921,"line":1290},[919,3948,1194],{"class":936},[919,3950,3951],{"class":921,"line":1295},[919,3952,943],{"class":936},[919,3954,3955,3957],{"class":921,"line":1302},[919,3956,1101],{"class":936},[919,3958,1104],{"class":925},[919,3960,3961,3963,3965,3967,3969,3971,3973,3975,3977,3979],{"class":921,"line":1325},[919,3962,1109],{"class":925},[919,3964,1112],{"class":925},[919,3966,1013],{"class":932},[919,3968,955],{"class":936},[919,3970,958],{"class":925},[919,3972,962],{"class":961},[919,3974,965],{"class":936},[919,3976,958],{"class":925},[919,3978,970],{"class":961},[919,3980,1129],{"class":936},[919,3982,3983],{"class":921,"line":1330},[919,3984,943],{"class":936},[919,3986,3987,3989,3991,3993,3995,3997],{"class":921,"line":1346},[919,3988,1138],{"class":925},[919,3990,1141],{"class":936},[919,3992,1144],{"class":925},[919,3994,1147],{"class":936},[919,3996,1341],{"class":925},[919,3998,1153],{"class":936},[919,4000,4001],{"class":921,"line":1351},[919,4002,943],{"class":936},[919,4004,4005,4007,4009,4011,4013,4015],{"class":921,"line":1366},[919,4006,1162],{"class":936},[919,4008,1165],{"class":932},[919,4010,955],{"class":936},[919,4012,1171],{"class":1170},[919,4014,1174],{"class":925},[919,4016,1177],{"class":936},[919,4018,4019],{"class":921,"line":1371},[919,4020,943],{"class":936},[919,4022,4023,4025],{"class":921,"line":1378},[919,4024,1186],{"class":925},[919,4026,1189],{"class":936},[919,4028,4029],{"class":921,"line":1383},[919,4030,1194],{"class":936},[919,4032,4033],{"class":921,"line":1388},[919,4034,943],{"class":936},[919,4036,4037,4039],{"class":921,"line":1395},[919,4038,1101],{"class":936},[919,4040,1104],{"class":925},[919,4042,4043,4045,4047,4049,4051,4053,4055,4057,4059,4061],{"class":921,"line":1418},[919,4044,1109],{"class":925},[919,4046,1112],{"class":925},[919,4048,1040],{"class":932},[919,4050,955],{"class":936},[919,4052,958],{"class":925},[919,4054,962],{"class":961},[919,4056,965],{"class":936},[919,4058,958],{"class":925},[919,4060,970],{"class":961},[919,4062,1129],{"class":936},[919,4064,4065],{"class":921,"line":1423},[919,4066,943],{"class":936},[919,4068,4069,4071,4073,4075,4077,4079],{"class":921,"line":1439},[919,4070,1138],{"class":925},[919,4072,1141],{"class":936},[919,4074,1144],{"class":925},[919,4076,1147],{"class":936},[919,4078,1434],{"class":925},[919,4080,1153],{"class":936},[919,4082,4083],{"class":921,"line":1444},[919,4084,943],{"class":936},[919,4086,4087,4089,4091,4093,4095,4097],{"class":921,"line":1459},[919,4088,1162],{"class":936},[919,4090,1165],{"class":932},[919,4092,955],{"class":936},[919,4094,1171],{"class":1170},[919,4096,1174],{"class":925},[919,4098,1177],{"class":936},[919,4100,4101],{"class":921,"line":1464},[919,4102,943],{"class":936},[919,4104,4105,4107],{"class":921,"line":1471},[919,4106,1186],{"class":925},[919,4108,1189],{"class":936},[919,4110,4111],{"class":921,"line":1476},[919,4112,1194],{"class":936},[919,4114,4115],{"class":921,"line":1888},[919,4116,1065],{"class":936},[2138,4118,4119],{"id":4119},"创建切面类并配置",[911,4121,4123],{"className":913,"code":4122,"language":915,"meta":11,"style":11},"\u002F\u002F @Aspect表示这个类是一个切面类\n@Aspect\n\u002F\u002F @Component注解保证这个切面类能够放入IOC容器\n@Component\npublic class LogAspect {\n\n    @Before(\"execution(public int com.codermast.spring.CalculatorImpl.*(..))\")\n    public void beforeMethod(JoinPoint joinPoint){\n        String methodName = joinPoint.getSignature().getName();\n        String args = Arrays.toString(joinPoint.getArgs());\n        System.out.println(\"Logger-->前置通知，方法名：\"+methodName+\"，参数：\"+args);\n    }\n\n    @After(\"execution(* com.codermast.spring.CalculatorImpl.*(..))\")\n    public void afterMethod(JoinPoint joinPoint){\n        String methodName = joinPoint.getSignature().getName();\n        System.out.println(\"Logger-->后置通知，方法名：\"+methodName);\n    }\n\n    @AfterReturning(value = \"execution(* com.codermast.spring.CalculatorImpl.*(..))\", returning = \"result\")\n    public void afterReturningMethod(JoinPoint joinPoint, Object result){\n        String methodName = joinPoint.getSignature().getName();\n        System.out.println(\"Logger-->返回通知，方法名：\"+methodName+\"，结果：\"+result);\n    }\n\n    @AfterThrowing(value = \"execution(* com.codermast.spring.CalculatorImpl.*(..))\", throwing = \"ex\")\n    public void afterThrowingMethod(JoinPoint joinPoint, Throwable ex){\n        String methodName = joinPoint.getSignature().getName();\n        System.out.println(\"Logger-->异常通知，方法名：\"+methodName+\"，异常：\"+ex);\n    }\n\n    @Around(\"execution(* com.codermast.spring.CalculatorImpl.*(..))\")\n    public Object aroundMethod(ProceedingJoinPoint joinPoint){\n        String methodName = joinPoint.getSignature().getName();\n        String args = Arrays.toString(joinPoint.getArgs());\n        Object result = null;\n        try {\n            System.out.println(\"环绕通知-->目标对象方法执行之前\");\n            \u002F\u002F目标对象（连接点）方法的执行\n            result = joinPoint.proceed();\n            System.out.println(\"环绕通知-->目标对象方法返回值之后\");\n        } catch (Throwable throwable) {\n            throwable.printStackTrace();\n            System.out.println(\"环绕通知-->目标对象方法出现异常时\");\n        } finally {\n            System.out.println(\"环绕通知-->目标对象方法执行完毕\");\n        }\n        return result;\n    }\n}\n",[900,4124,4125,4130,4137,4142,4148,4159,4163,4178,4196,4215,4234,4259,4263,4267,4281,4296,4312,4328,4332,4336,4366,4387,4403,4427,4431,4435,4462,4483,4499,4523,4527,4531,4544,4560,4576,4592,4603,4610,4624,4629,4643,4656,4671,4680,4693,4701,4714,4719,4725,4729],{"__ignoreMap":11},[919,4126,4127],{"class":921,"line":922},[919,4128,4129],{"class":2174},"\u002F\u002F @Aspect表示这个类是一个切面类\n",[919,4131,4132,4134],{"class":921,"line":940},[919,4133,2873],{"class":936},[919,4135,4136],{"class":925},"Aspect\n",[919,4138,4139],{"class":921,"line":946},[919,4140,4141],{"class":2174},"\u002F\u002F @Component注解保证这个切面类能够放入IOC容器\n",[919,4143,4144,4146],{"class":921,"line":976},[919,4145,2873],{"class":936},[919,4147,3770],{"class":925},[919,4149,4150,4152,4154,4157],{"class":921,"line":981},[919,4151,926],{"class":925},[919,4153,1082],{"class":925},[919,4155,4156],{"class":932}," LogAspect",[919,4158,937],{"class":936},[919,4160,4161],{"class":921,"line":1003},[919,4162,2388],{"emptyLinePlaceholder":2387},[919,4164,4165,4167,4170,4172,4175],{"class":921,"line":1008},[919,4166,1101],{"class":936},[919,4168,4169],{"class":925},"Before",[919,4171,955],{"class":936},[919,4173,4174],{"class":1170},"\"execution(public int com.codermast.spring.CalculatorImpl.*(..))\"",[919,4176,4177],{"class":936},")\n",[919,4179,4180,4182,4184,4187,4190,4193],{"class":921,"line":1030},[919,4181,1109],{"class":925},[919,4183,2883],{"class":925},[919,4185,4186],{"class":932}," beforeMethod",[919,4188,4189],{"class":936},"(JoinPoint ",[919,4191,4192],{"class":961},"joinPoint",[919,4194,4195],{"class":936},"){\n",[919,4197,4198,4201,4203,4206,4209,4211,4213],{"class":921,"line":1035},[919,4199,4200],{"class":936},"        String methodName ",[919,4202,1144],{"class":925},[919,4204,4205],{"class":936}," joinPoint.",[919,4207,4208],{"class":932},"getSignature",[919,4210,2497],{"class":936},[919,4212,2656],{"class":932},[919,4214,2503],{"class":936},[919,4216,4217,4220,4222,4224,4226,4229,4232],{"class":921,"line":1057},[919,4218,4219],{"class":936},"        String args ",[919,4221,1144],{"class":925},[919,4223,2669],{"class":936},[919,4225,2672],{"class":932},[919,4227,4228],{"class":936},"(joinPoint.",[919,4230,4231],{"class":932},"getArgs",[919,4233,2777],{"class":936},[919,4235,4236,4238,4240,4242,4245,4247,4250,4252,4254,4256],{"class":921,"line":1062},[919,4237,1162],{"class":936},[919,4239,1165],{"class":932},[919,4241,955],{"class":936},[919,4243,4244],{"class":1170},"\"Logger-->前置通知，方法名：\"",[919,4246,1150],{"class":925},[919,4248,4249],{"class":936},"methodName",[919,4251,1150],{"class":925},[919,4253,2664],{"class":1170},[919,4255,1150],{"class":925},[919,4257,4258],{"class":936},"args);\n",[919,4260,4261],{"class":921,"line":1197},[919,4262,1194],{"class":936},[919,4264,4265],{"class":921,"line":1202},[919,4266,2388],{"emptyLinePlaceholder":2387},[919,4268,4269,4271,4274,4276,4279],{"class":921,"line":1209},[919,4270,1101],{"class":936},[919,4272,4273],{"class":925},"After",[919,4275,955],{"class":936},[919,4277,4278],{"class":1170},"\"execution(* com.codermast.spring.CalculatorImpl.*(..))\"",[919,4280,4177],{"class":936},[919,4282,4283,4285,4287,4290,4292,4294],{"class":921,"line":1232},[919,4284,1109],{"class":925},[919,4286,2883],{"class":925},[919,4288,4289],{"class":932}," afterMethod",[919,4291,4189],{"class":936},[919,4293,4192],{"class":961},[919,4295,4195],{"class":936},[919,4297,4298,4300,4302,4304,4306,4308,4310],{"class":921,"line":1237},[919,4299,4200],{"class":936},[919,4301,1144],{"class":925},[919,4303,4205],{"class":936},[919,4305,4208],{"class":932},[919,4307,2497],{"class":936},[919,4309,2656],{"class":932},[919,4311,2503],{"class":936},[919,4313,4314,4316,4318,4320,4323,4325],{"class":921,"line":1253},[919,4315,1162],{"class":936},[919,4317,1165],{"class":932},[919,4319,955],{"class":936},[919,4321,4322],{"class":1170},"\"Logger-->后置通知，方法名：\"",[919,4324,1150],{"class":925},[919,4326,4327],{"class":936},"methodName);\n",[919,4329,4330],{"class":921,"line":1258},[919,4331,1194],{"class":936},[919,4333,4334],{"class":921,"line":1273},[919,4335,2388],{"emptyLinePlaceholder":2387},[919,4337,4338,4340,4343,4345,4348,4351,4354,4356,4359,4361,4364],{"class":921,"line":1278},[919,4339,1101],{"class":936},[919,4341,4342],{"class":925},"AfterReturning",[919,4344,955],{"class":936},[919,4346,4347],{"class":2206},"value",[919,4349,4350],{"class":925}," =",[919,4352,4353],{"class":1170}," \"execution(* com.codermast.spring.CalculatorImpl.*(..))\"",[919,4355,965],{"class":936},[919,4357,4358],{"class":2206},"returning",[919,4360,4350],{"class":925},[919,4362,4363],{"class":1170}," \"result\"",[919,4365,4177],{"class":936},[919,4367,4368,4370,4372,4375,4377,4379,4382,4385],{"class":921,"line":1285},[919,4369,1109],{"class":925},[919,4371,2883],{"class":925},[919,4373,4374],{"class":932}," afterReturningMethod",[919,4376,4189],{"class":936},[919,4378,4192],{"class":961},[919,4380,4381],{"class":936},", Object ",[919,4383,4384],{"class":961},"result",[919,4386,4195],{"class":936},[919,4388,4389,4391,4393,4395,4397,4399,4401],{"class":921,"line":1290},[919,4390,4200],{"class":936},[919,4392,1144],{"class":925},[919,4394,4205],{"class":936},[919,4396,4208],{"class":932},[919,4398,2497],{"class":936},[919,4400,2656],{"class":932},[919,4402,2503],{"class":936},[919,4404,4405,4407,4409,4411,4414,4416,4418,4420,4422,4424],{"class":921,"line":1295},[919,4406,1162],{"class":936},[919,4408,1165],{"class":932},[919,4410,955],{"class":936},[919,4412,4413],{"class":1170},"\"Logger-->返回通知，方法名：\"",[919,4415,1150],{"class":925},[919,4417,4249],{"class":936},[919,4419,1150],{"class":925},[919,4421,2713],{"class":1170},[919,4423,1150],{"class":925},[919,4425,4426],{"class":936},"result);\n",[919,4428,4429],{"class":921,"line":1302},[919,4430,1194],{"class":936},[919,4432,4433],{"class":921,"line":1325},[919,4434,2388],{"emptyLinePlaceholder":2387},[919,4436,4437,4439,4442,4444,4446,4448,4450,4452,4455,4457,4460],{"class":921,"line":1330},[919,4438,1101],{"class":936},[919,4440,4441],{"class":925},"AfterThrowing",[919,4443,955],{"class":936},[919,4445,4347],{"class":2206},[919,4447,4350],{"class":925},[919,4449,4353],{"class":1170},[919,4451,965],{"class":936},[919,4453,4454],{"class":2206},"throwing",[919,4456,4350],{"class":925},[919,4458,4459],{"class":1170}," \"ex\"",[919,4461,4177],{"class":936},[919,4463,4464,4466,4468,4471,4473,4475,4478,4481],{"class":921,"line":1346},[919,4465,1109],{"class":925},[919,4467,2883],{"class":925},[919,4469,4470],{"class":932}," afterThrowingMethod",[919,4472,4189],{"class":936},[919,4474,4192],{"class":961},[919,4476,4477],{"class":936},", Throwable ",[919,4479,4480],{"class":961},"ex",[919,4482,4195],{"class":936},[919,4484,4485,4487,4489,4491,4493,4495,4497],{"class":921,"line":1351},[919,4486,4200],{"class":936},[919,4488,1144],{"class":925},[919,4490,4205],{"class":936},[919,4492,4208],{"class":932},[919,4494,2497],{"class":936},[919,4496,2656],{"class":932},[919,4498,2503],{"class":936},[919,4500,4501,4503,4505,4507,4510,4512,4514,4516,4518,4520],{"class":921,"line":1366},[919,4502,1162],{"class":936},[919,4504,1165],{"class":932},[919,4506,955],{"class":936},[919,4508,4509],{"class":1170},"\"Logger-->异常通知，方法名：\"",[919,4511,1150],{"class":925},[919,4513,4249],{"class":936},[919,4515,1150],{"class":925},[919,4517,2766],{"class":1170},[919,4519,1150],{"class":925},[919,4521,4522],{"class":936},"ex);\n",[919,4524,4525],{"class":921,"line":1371},[919,4526,1194],{"class":936},[919,4528,4529],{"class":921,"line":1378},[919,4530,2388],{"emptyLinePlaceholder":2387},[919,4532,4533,4535,4538,4540,4542],{"class":921,"line":1383},[919,4534,1101],{"class":936},[919,4536,4537],{"class":925},"Around",[919,4539,955],{"class":936},[919,4541,4278],{"class":1170},[919,4543,4177],{"class":936},[919,4545,4546,4548,4550,4553,4556,4558],{"class":921,"line":1388},[919,4547,1109],{"class":925},[919,4549,2437],{"class":936},[919,4551,4552],{"class":932},"aroundMethod",[919,4554,4555],{"class":936},"(ProceedingJoinPoint ",[919,4557,4192],{"class":961},[919,4559,4195],{"class":936},[919,4561,4562,4564,4566,4568,4570,4572,4574],{"class":921,"line":1395},[919,4563,4200],{"class":936},[919,4565,1144],{"class":925},[919,4567,4205],{"class":936},[919,4569,4208],{"class":932},[919,4571,2497],{"class":936},[919,4573,2656],{"class":932},[919,4575,2503],{"class":936},[919,4577,4578,4580,4582,4584,4586,4588,4590],{"class":921,"line":1418},[919,4579,4219],{"class":936},[919,4581,1144],{"class":925},[919,4583,2669],{"class":936},[919,4585,2672],{"class":932},[919,4587,4228],{"class":936},[919,4589,4231],{"class":932},[919,4591,2777],{"class":936},[919,4593,4594,4597,4599,4601],{"class":921,"line":1423},[919,4595,4596],{"class":936},"        Object result ",[919,4598,1144],{"class":925},[919,4600,2626],{"class":2206},[919,4602,2629],{"class":936},[919,4604,4605,4608],{"class":921,"line":1439},[919,4606,4607],{"class":925},"        try",[919,4609,937],{"class":936},[919,4611,4612,4615,4617,4619,4622],{"class":921,"line":1444},[919,4613,4614],{"class":936},"            System.out.",[919,4616,1165],{"class":932},[919,4618,955],{"class":936},[919,4620,4621],{"class":1170},"\"环绕通知-->目标对象方法执行之前\"",[919,4623,973],{"class":936},[919,4625,4626],{"class":921,"line":1459},[919,4627,4628],{"class":2174},"            \u002F\u002F目标对象（连接点）方法的执行\n",[919,4630,4631,4634,4636,4638,4641],{"class":921,"line":1464},[919,4632,4633],{"class":936},"            result ",[919,4635,1144],{"class":925},[919,4637,4205],{"class":936},[919,4639,4640],{"class":932},"proceed",[919,4642,2503],{"class":936},[919,4644,4645,4647,4649,4651,4654],{"class":921,"line":1471},[919,4646,4614],{"class":936},[919,4648,1165],{"class":932},[919,4650,955],{"class":936},[919,4652,4653],{"class":1170},"\"环绕通知-->目标对象方法返回值之后\"",[919,4655,973],{"class":936},[919,4657,4658,4661,4663,4666,4669],{"class":921,"line":1476},[919,4659,4660],{"class":936},"        } ",[919,4662,2725],{"class":925},[919,4664,4665],{"class":936}," (Throwable ",[919,4667,4668],{"class":961},"throwable",[919,4670,1129],{"class":936},[919,4672,4673,4676,4678],{"class":921,"line":1888},[919,4674,4675],{"class":936},"            throwable.",[919,4677,2741],{"class":932},[919,4679,2503],{"class":936},[919,4681,4682,4684,4686,4688,4691],{"class":921,"line":1893},[919,4683,4614],{"class":936},[919,4685,1165],{"class":932},[919,4687,955],{"class":936},[919,4689,4690],{"class":1170},"\"环绕通知-->目标对象方法出现异常时\"",[919,4692,973],{"class":936},[919,4694,4695,4697,4699],{"class":921,"line":1898},[919,4696,4660],{"class":936},[919,4698,2784],{"class":925},[919,4700,937],{"class":936},[919,4702,4703,4705,4707,4709,4712],{"class":921,"line":1905},[919,4704,4614],{"class":936},[919,4706,1165],{"class":932},[919,4708,955],{"class":936},[919,4710,4711],{"class":1170},"\"环绕通知-->目标对象方法执行完毕\"",[919,4713,973],{"class":936},[919,4715,4716],{"class":921,"line":1928},[919,4717,4718],{"class":936},"        }\n",[919,4720,4721,4723],{"class":921,"line":1933},[919,4722,1186],{"class":925},[919,4724,1189],{"class":936},[919,4726,4727],{"class":921,"line":1957},[919,4728,1194],{"class":936},[919,4730,4731],{"class":921,"line":1962},[919,4732,1065],{"class":936},[904,4734,4735],{},[907,4736,4737],{},"在Spring的配置文件中配置",[911,4739,4741],{"className":3226,"code":4740,"language":3228,"meta":11,"style":11},"\u003C?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\u003Cbeans xmlns=\"http:\u002F\u002Fwww.springframework.org\u002Fschema\u002Fbeans\"\n       xmlns:xsi=\"http:\u002F\u002Fwww.w3.org\u002F2001\u002FXMLSchema-instance\"\n       xmlns:context=\"http:\u002F\u002Fwww.springframework.org\u002Fschema\u002Fcontext\"\n       xmlns:aop=\"http:\u002F\u002Fwww.springframework.org\u002Fschema\u002Faop\"\n       xsi:schemaLocation=\"http:\u002F\u002Fwww.springframework.org\u002Fschema\u002Fbeans\n       http:\u002F\u002Fwww.springframework.org\u002Fschema\u002Fbeans\u002Fspring-beans.xsd\n       http:\u002F\u002Fwww.springframework.org\u002Fschema\u002Fcontext\n       http:\u002F\u002Fwww.springframework.org\u002Fschema\u002Fcontext\u002Fspring-context.xsd\n       http:\u002F\u002Fwww.springframework.org\u002Fschema\u002Faop\n       http:\u002F\u002Fwww.springframework.org\u002Fschema\u002Faop\u002Fspring-aop.xsd\">\n    \u003C!--\n        基于注解的AOP的实现：\n        1、将目标对象和切面交给IOC容器管理（注解+扫描）\n        2、开启AspectJ的自动代理，为目标对象自动生成代理\n        3、将切面类通过注解@Aspect标识\n    -->\n    \u003Ccontext:component-scan base-package=\"com.codermast.spring\"\u002F>\n\n    \u003Caop:aspectj-autoproxy \u002F>\n\u003C\u002Fbeans>\n",[900,4742,4743,4769,4784,4794,4804,4814,4824,4829,4834,4839,4844,4851,4856,4861,4866,4871,4876,4881,4899,4903,4913],{"__ignoreMap":11},[919,4744,4745,4748,4750,4753,4755,4758,4761,4763,4766],{"class":921,"line":922},[919,4746,4747],{"class":936},"\u003C?",[919,4749,3228],{"class":3238},[919,4751,4752],{"class":932}," version",[919,4754,1144],{"class":936},[919,4756,4757],{"class":1170},"\"1.0\"",[919,4759,4760],{"class":932}," encoding",[919,4762,1144],{"class":936},[919,4764,4765],{"class":1170},"\"UTF-8\"",[919,4767,4768],{"class":936},"?>\n",[919,4770,4771,4773,4776,4779,4781],{"class":921,"line":940},[919,4772,3235],{"class":936},[919,4774,4775],{"class":3238},"beans",[919,4777,4778],{"class":932}," xmlns",[919,4780,1144],{"class":936},[919,4782,4783],{"class":1170},"\"http:\u002F\u002Fwww.springframework.org\u002Fschema\u002Fbeans\"\n",[919,4785,4786,4789,4791],{"class":921,"line":946},[919,4787,4788],{"class":932},"       xmlns:xsi",[919,4790,1144],{"class":936},[919,4792,4793],{"class":1170},"\"http:\u002F\u002Fwww.w3.org\u002F2001\u002FXMLSchema-instance\"\n",[919,4795,4796,4799,4801],{"class":921,"line":976},[919,4797,4798],{"class":932},"       xmlns:context",[919,4800,1144],{"class":936},[919,4802,4803],{"class":1170},"\"http:\u002F\u002Fwww.springframework.org\u002Fschema\u002Fcontext\"\n",[919,4805,4806,4809,4811],{"class":921,"line":981},[919,4807,4808],{"class":932},"       xmlns:aop",[919,4810,1144],{"class":936},[919,4812,4813],{"class":1170},"\"http:\u002F\u002Fwww.springframework.org\u002Fschema\u002Faop\"\n",[919,4815,4816,4819,4821],{"class":921,"line":1003},[919,4817,4818],{"class":932},"       xsi:schemaLocation",[919,4820,1144],{"class":936},[919,4822,4823],{"class":1170},"\"http:\u002F\u002Fwww.springframework.org\u002Fschema\u002Fbeans\n",[919,4825,4826],{"class":921,"line":1008},[919,4827,4828],{"class":1170},"       http:\u002F\u002Fwww.springframework.org\u002Fschema\u002Fbeans\u002Fspring-beans.xsd\n",[919,4830,4831],{"class":921,"line":1030},[919,4832,4833],{"class":1170},"       http:\u002F\u002Fwww.springframework.org\u002Fschema\u002Fcontext\n",[919,4835,4836],{"class":921,"line":1035},[919,4837,4838],{"class":1170},"       http:\u002F\u002Fwww.springframework.org\u002Fschema\u002Fcontext\u002Fspring-context.xsd\n",[919,4840,4841],{"class":921,"line":1057},[919,4842,4843],{"class":1170},"       http:\u002F\u002Fwww.springframework.org\u002Fschema\u002Faop\n",[919,4845,4846,4849],{"class":921,"line":1062},[919,4847,4848],{"class":1170},"       http:\u002F\u002Fwww.springframework.org\u002Fschema\u002Faop\u002Fspring-aop.xsd\"",[919,4850,3242],{"class":936},[919,4852,4853],{"class":921,"line":1197},[919,4854,4855],{"class":2174},"    \u003C!--\n",[919,4857,4858],{"class":921,"line":1202},[919,4859,4860],{"class":2174},"        基于注解的AOP的实现：\n",[919,4862,4863],{"class":921,"line":1209},[919,4864,4865],{"class":2174},"        1、将目标对象和切面交给IOC容器管理（注解+扫描）\n",[919,4867,4868],{"class":921,"line":1232},[919,4869,4870],{"class":2174},"        2、开启AspectJ的自动代理，为目标对象自动生成代理\n",[919,4872,4873],{"class":921,"line":1237},[919,4874,4875],{"class":2174},"        3、将切面类通过注解@Aspect标识\n",[919,4877,4878],{"class":921,"line":1253},[919,4879,4880],{"class":2174},"    -->\n",[919,4882,4883,4885,4888,4891,4893,4896],{"class":921,"line":1258},[919,4884,3257],{"class":936},[919,4886,4887],{"class":3238},"context:component-scan",[919,4889,4890],{"class":932}," base-package",[919,4892,1144],{"class":936},[919,4894,4895],{"class":1170},"\"com.codermast.spring\"",[919,4897,4898],{"class":936},"\u002F>\n",[919,4900,4901],{"class":921,"line":1273},[919,4902,2388],{"emptyLinePlaceholder":2387},[919,4904,4905,4907,4910],{"class":921,"line":1278},[919,4906,3257],{"class":936},[919,4908,4909],{"class":3238},"aop:aspectj-autoproxy",[919,4911,4912],{"class":936}," \u002F>\n",[919,4914,4915,4917,4919],{"class":921,"line":1285},[919,4916,3621],{"class":936},[919,4918,4775],{"class":3238},[919,4920,3242],{"class":936},[904,4922,4923],{},[907,4924,4925],{},"执行测试",[911,4927,4929],{"className":913,"code":4928,"language":915,"meta":11,"style":11},"import com.codermast.spring.Calculator;\nimport org.junit.jupiter.api.Test;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.support.ClassPathXmlApplicationContext;\n\npublic class CalculatorTest {\n    private Logger logger = LoggerFactory.getLogger(CalculatorTest.class);\n\n    @Test\n    public void testAdd(){\n        ApplicationContext ac = new ClassPathXmlApplicationContext(\"beans.xml\");\n        Calculator calculator = ac.getBean( Calculator.class);\n        int add = calculator.add(1, 1);\n        logger.info(\"执行成功:\"+add);\n    }\n}\n",[900,4930,4931,4939,4946,4953,4960,4967,4974,4978,4989,5007,5011,5017,5028,5047,5063,5087,5105,5109],{"__ignoreMap":11},[919,4932,4933,4936],{"class":921,"line":922},[919,4934,4935],{"class":925},"import",[919,4937,4938],{"class":936}," com.codermast.spring.Calculator;\n",[919,4940,4941,4943],{"class":921,"line":940},[919,4942,4935],{"class":925},[919,4944,4945],{"class":936}," org.junit.jupiter.api.Test;\n",[919,4947,4948,4950],{"class":921,"line":946},[919,4949,4935],{"class":925},[919,4951,4952],{"class":936}," org.slf4j.Logger;\n",[919,4954,4955,4957],{"class":921,"line":976},[919,4956,4935],{"class":925},[919,4958,4959],{"class":936}," org.slf4j.LoggerFactory;\n",[919,4961,4962,4964],{"class":921,"line":981},[919,4963,4935],{"class":925},[919,4965,4966],{"class":936}," org.springframework.context.ApplicationContext;\n",[919,4968,4969,4971],{"class":921,"line":1003},[919,4970,4935],{"class":925},[919,4972,4973],{"class":936}," org.springframework.context.support.ClassPathXmlApplicationContext;\n",[919,4975,4976],{"class":921,"line":1008},[919,4977,2388],{"emptyLinePlaceholder":2387},[919,4979,4980,4982,4984,4987],{"class":921,"line":1030},[919,4981,926],{"class":925},[919,4983,1082],{"class":925},[919,4985,4986],{"class":932}," CalculatorTest",[919,4988,937],{"class":936},[919,4990,4991,4993,4996,4998,5001,5004],{"class":921,"line":1035},[919,4992,2180],{"class":925},[919,4994,4995],{"class":936}," Logger logger ",[919,4997,1144],{"class":925},[919,4999,5000],{"class":936}," LoggerFactory.",[919,5002,5003],{"class":932},"getLogger",[919,5005,5006],{"class":936},"(CalculatorTest.class);\n",[919,5008,5009],{"class":921,"line":1057},[919,5010,2388],{"emptyLinePlaceholder":2387},[919,5012,5013,5015],{"class":921,"line":1062},[919,5014,1101],{"class":936},[919,5016,2876],{"class":925},[919,5018,5019,5021,5023,5026],{"class":921,"line":1197},[919,5020,1109],{"class":925},[919,5022,2883],{"class":925},[919,5024,5025],{"class":932}," testAdd",[919,5027,2443],{"class":936},[919,5029,5030,5033,5035,5037,5040,5042,5045],{"class":921,"line":1202},[919,5031,5032],{"class":936},"        ApplicationContext ac ",[919,5034,1144],{"class":925},[919,5036,2537],{"class":925},[919,5038,5039],{"class":932}," ClassPathXmlApplicationContext",[919,5041,955],{"class":936},[919,5043,5044],{"class":1170},"\"beans.xml\"",[919,5046,973],{"class":936},[919,5048,5049,5052,5054,5057,5060],{"class":921,"line":1209},[919,5050,5051],{"class":936},"        Calculator calculator ",[919,5053,1144],{"class":925},[919,5055,5056],{"class":936}," ac.",[919,5058,5059],{"class":932},"getBean",[919,5061,5062],{"class":936},"( Calculator.class);\n",[919,5064,5065,5067,5070,5072,5075,5077,5079,5081,5083,5085],{"class":921,"line":1232},[919,5066,1138],{"class":925},[919,5068,5069],{"class":936}," add ",[919,5071,1144],{"class":925},[919,5073,5074],{"class":936}," calculator.",[919,5076,2306],{"class":932},[919,5078,955],{"class":936},[919,5080,2935],{"class":2206},[919,5082,965],{"class":936},[919,5084,2935],{"class":2206},[919,5086,973],{"class":936},[919,5088,5089,5092,5095,5097,5100,5102],{"class":921,"line":1237},[919,5090,5091],{"class":936},"        logger.",[919,5093,5094],{"class":932},"info",[919,5096,955],{"class":936},[919,5098,5099],{"class":1170},"\"执行成功:\"",[919,5101,1150],{"class":925},[919,5103,5104],{"class":936},"add);\n",[919,5106,5107],{"class":921,"line":1253},[919,5108,1194],{"class":936},[919,5110,5111],{"class":921,"line":1258},[919,5112,1065],{"class":936},[2039,5114,5115],{},"\n注意这里要导入的类路径，有几个类名是相同的，不要导入错了，会造成异常。\n",[896,5117,5118],{},[2097,5119],{"alt":5120,"src":5121},"测试结果","\u002Fassets\u002Fjava\u002Fspring\u002Fspring-aop\u002F2024-01-01-21-11-05.png",[2138,5123,5124],{"id":5124},"各种通知",[904,5126,5127,5132,5139,5146,5153],{},[907,5128,5129,5130,3028],{},"前置通知：使用@Before注解标识，在被代理的目标方法",[2060,5131,3027],{},[907,5133,5134,5135,3035,5137,3039],{},"返回通知：使用@AfterReturning注解标识，在被代理的目标方法",[2060,5136,3034],{},[2060,5138,3038],{},[907,5140,5141,5142,3035,5144,3039],{},"异常通知：使用@AfterThrowing注解标识，在被代理的目标方法",[2060,5143,3045],{},[2060,5145,3048],{},[907,5147,5148,5149,3035,5151,3039],{},"后置通知：使用@After注解标识，在被代理的目标方法",[2060,5150,3054],{},[2060,5152,3057],{},[907,5154,5155,5156,3064],{},"环绕通知：使用@Around注解标识，使用try...catch...finally结构围绕",[2060,5157,3063],{},[896,5159,5160],{},"> 各种通知的执行顺序：\n>\n> - Spring版本5.3.x以前：\n>   - 前置通知\n>   - 目标操作\n>   - 后置通知\n>   - 返回通知或异常通知\n> - Spring版本5.3.x以后：\n>   - 前置通知\n>   - 目标操作\n>   - 返回通知或异常通知\n>   - 后置通知",[2138,5162,5163],{"id":5163},"切入点表达式语法",[896,5165,5166,5169],{},[2060,5167,5168],{},"①作用",[2097,5170],{"alt":11,"src":5171},"\u002Fassets\u002Fjava\u002Fspring\u002Fspring-aop\u002F2024-01-01-21-13-06.png",[896,5173,5174],{},[2060,5175,5176],{},"②语法细节",[904,5178,5179,5182,5190,5193,5196,5204,5207,5215,5218,5221,5229],{},[907,5180,5181],{},"用*号代替“权限修饰符”和“返回值”部分表示“权限修饰符”和“返回值”不限",[907,5183,5184,5185],{},"在包名的部分，一个“*”号只能代表包的层次结构中的一层，表示这一层是任意的。",[904,5186,5187],{},[907,5188,5189],{},"例如：*.Hello匹配com.Hello，不匹配com.atguigu.Hello",[907,5191,5192],{},"在包名的部分，使用“*..”表示包名任意、包的层次深度任意",[907,5194,5195],{},"在类名的部分，类名部分整体用*号代替，表示类名任意",[907,5197,5198,5199],{},"在类名的部分，可以使用*号代替类名的一部分",[904,5200,5201],{},[907,5202,5203],{},"例如：*Service匹配所有名称以Service结尾的类或接口",[907,5205,5206],{},"在方法名部分，可以使用*号表示方法名任意",[907,5208,5209,5210],{},"在方法名部分，可以使用*号代替方法名的一部分",[904,5211,5212],{},[907,5213,5214],{},"例如：*Operation匹配所有方法名以Operation结尾的方法",[907,5216,5217],{},"在方法参数列表部分，使用(..)表示参数列表任意",[907,5219,5220],{},"在方法参数列表部分，使用(int,..)表示参数列表以一个int类型的参数开头",[907,5222,5223,5224],{},"在方法参数列表部分，基本数据类型和对应的包装类型是不一样的",[904,5225,5226],{},[907,5227,5228],{},"切入点表达式中使用 int 和实际方法中 Integer 是不匹配的",[907,5230,5231,5232],{},"在方法返回值部分，如果想要明确指定一个返回值类型，那么必须同时写明权限修饰符",[904,5233,5234],{},[907,5235,5236,5237,5245,5246,5248],{},"例如：execution(public int ",[5238,5239,5240,5241,5244],"em",{},"..",[5238,5242,5243],{},"Service.","(.., int))\t正确\n例如：execution("," int *..",[5238,5247,5243],{},"(.., int))\t错误",[896,5250,5251],{},[2097,5252],{"alt":11,"src":5253},"\u002Fassets\u002Fjava\u002Fspring\u002Fspring-aop\u002F2024-01-01-21-14-16.png",[2138,5255,5256],{"id":5256},"重用切入点表达式",[2055,5258,5259],{},[907,5260,5261],{},[2060,5262,5263],{},"声明",[911,5265,5267],{"className":913,"code":5266,"language":915,"meta":11,"style":11},"@Pointcut(\"execution(* com.atguigu.aop.annotation.*.*(..))\")\npublic void pointCut(){}\n",[900,5268,5269,5283],{"__ignoreMap":11},[919,5270,5271,5273,5276,5278,5281],{"class":921,"line":922},[919,5272,2873],{"class":936},[919,5274,5275],{"class":925},"Pointcut",[919,5277,955],{"class":936},[919,5279,5280],{"class":1170},"\"execution(* com.atguigu.aop.annotation.*.*(..))\"",[919,5282,4177],{"class":936},[919,5284,5285,5287,5289,5292],{"class":921,"line":940},[919,5286,926],{"class":925},[919,5288,2883],{"class":925},[919,5290,5291],{"class":932}," pointCut",[919,5293,5294],{"class":936},"(){}\n",[2055,5296,5297],{"start":940},[907,5298,5299],{},[2060,5300,5301],{},"在同一个切面中使用",[911,5303,5305],{"className":913,"code":5304,"language":915,"meta":11,"style":11},"@Before(\"pointCut()\")\npublic void beforeMethod(JoinPoint joinPoint){\n    String methodName = joinPoint.getSignature().getName();\n    String args = Arrays.toString(joinPoint.getArgs());\n    System.out.println(\"Logger-->前置通知，方法名：\"+methodName+\"，参数：\"+args);\n}\n",[900,5306,5307,5320,5331,5348,5365,5388],{"__ignoreMap":11},[919,5308,5309,5311,5313,5315,5318],{"class":921,"line":922},[919,5310,2873],{"class":936},[919,5312,4169],{"class":925},[919,5314,955],{"class":936},[919,5316,5317],{"class":1170},"\"pointCut()\"",[919,5319,4177],{"class":936},[919,5321,5322,5324,5326,5328],{"class":921,"line":940},[919,5323,926],{"class":925},[919,5325,2883],{"class":925},[919,5327,4186],{"class":932},[919,5329,5330],{"class":936},"(JoinPoint joinPoint){\n",[919,5332,5333,5336,5338,5340,5342,5344,5346],{"class":921,"line":946},[919,5334,5335],{"class":936},"    String methodName ",[919,5337,1144],{"class":925},[919,5339,4205],{"class":936},[919,5341,4208],{"class":932},[919,5343,2497],{"class":936},[919,5345,2656],{"class":932},[919,5347,2503],{"class":936},[919,5349,5350,5353,5355,5357,5359,5361,5363],{"class":921,"line":976},[919,5351,5352],{"class":936},"    String args ",[919,5354,1144],{"class":925},[919,5356,2669],{"class":936},[919,5358,2672],{"class":932},[919,5360,4228],{"class":936},[919,5362,4231],{"class":932},[919,5364,2777],{"class":936},[919,5366,5367,5370,5372,5374,5376,5378,5380,5382,5384,5386],{"class":921,"line":981},[919,5368,5369],{"class":936},"    System.out.",[919,5371,1165],{"class":932},[919,5373,955],{"class":936},[919,5375,4244],{"class":1170},[919,5377,1150],{"class":925},[919,5379,4249],{"class":936},[919,5381,1150],{"class":925},[919,5383,2664],{"class":1170},[919,5385,1150],{"class":925},[919,5387,4258],{"class":936},[919,5389,5390],{"class":921,"line":1003},[919,5391,1065],{"class":936},[2055,5393,5394],{"start":946},[907,5395,5396],{},[2060,5397,5398],{},"在不同切面中使用",[911,5400,5402],{"className":913,"code":5401,"language":915,"meta":11,"style":11},"@Before(\"com.atguigu.aop.CommonPointCut.pointCut()\")\npublic void beforeMethod(JoinPoint joinPoint){\n    String methodName = joinPoint.getSignature().getName();\n    String args = Arrays.toString(joinPoint.getArgs());\n    System.out.println(\"Logger-->前置通知，方法名：\"+methodName+\"，参数：\"+args);\n}\n",[900,5403,5404,5417,5427,5443,5459,5481],{"__ignoreMap":11},[919,5405,5406,5408,5410,5412,5415],{"class":921,"line":922},[919,5407,2873],{"class":936},[919,5409,4169],{"class":925},[919,5411,955],{"class":936},[919,5413,5414],{"class":1170},"\"com.atguigu.aop.CommonPointCut.pointCut()\"",[919,5416,4177],{"class":936},[919,5418,5419,5421,5423,5425],{"class":921,"line":940},[919,5420,926],{"class":925},[919,5422,2883],{"class":925},[919,5424,4186],{"class":932},[919,5426,5330],{"class":936},[919,5428,5429,5431,5433,5435,5437,5439,5441],{"class":921,"line":946},[919,5430,5335],{"class":936},[919,5432,1144],{"class":925},[919,5434,4205],{"class":936},[919,5436,4208],{"class":932},[919,5438,2497],{"class":936},[919,5440,2656],{"class":932},[919,5442,2503],{"class":936},[919,5444,5445,5447,5449,5451,5453,5455,5457],{"class":921,"line":976},[919,5446,5352],{"class":936},[919,5448,1144],{"class":925},[919,5450,2669],{"class":936},[919,5452,2672],{"class":932},[919,5454,4228],{"class":936},[919,5456,4231],{"class":932},[919,5458,2777],{"class":936},[919,5460,5461,5463,5465,5467,5469,5471,5473,5475,5477,5479],{"class":921,"line":981},[919,5462,5369],{"class":936},[919,5464,1165],{"class":932},[919,5466,955],{"class":936},[919,5468,4244],{"class":1170},[919,5470,1150],{"class":925},[919,5472,4249],{"class":936},[919,5474,1150],{"class":925},[919,5476,2664],{"class":1170},[919,5478,1150],{"class":925},[919,5480,4258],{"class":936},[919,5482,5483],{"class":921,"line":1003},[919,5484,1065],{"class":936},[2138,5486,5487],{"id":5487},"获取通知的相关信息",[896,5489,5490],{},[2060,5491,5492],{},"①获取连接点信息",[896,5494,5495],{},"获取连接点信息可以在通知方法的参数位置设置JoinPoint类型的形参",[911,5497,5499],{"className":913,"code":5498,"language":915,"meta":11,"style":11},"@Before(\"execution(public int com.codermast.spring.CalculatorImpl.*(..))\")\npublic void beforeMethod(JoinPoint joinPoint){\n    \u002F\u002F获取连接点的签名信息\n    String methodName = joinPoint.getSignature().getName();\n    \u002F\u002F获取目标方法到的实参信息\n    String args = Arrays.toString(joinPoint.getArgs());\n    System.out.println(\"Logger-->前置通知，方法名：\"+methodName+\"，参数：\"+args);\n}\n",[900,5500,5501,5513,5523,5528,5544,5549,5565,5587],{"__ignoreMap":11},[919,5502,5503,5505,5507,5509,5511],{"class":921,"line":922},[919,5504,2873],{"class":936},[919,5506,4169],{"class":925},[919,5508,955],{"class":936},[919,5510,4174],{"class":1170},[919,5512,4177],{"class":936},[919,5514,5515,5517,5519,5521],{"class":921,"line":940},[919,5516,926],{"class":925},[919,5518,2883],{"class":925},[919,5520,4186],{"class":932},[919,5522,5330],{"class":936},[919,5524,5525],{"class":921,"line":946},[919,5526,5527],{"class":2174},"    \u002F\u002F获取连接点的签名信息\n",[919,5529,5530,5532,5534,5536,5538,5540,5542],{"class":921,"line":976},[919,5531,5335],{"class":936},[919,5533,1144],{"class":925},[919,5535,4205],{"class":936},[919,5537,4208],{"class":932},[919,5539,2497],{"class":936},[919,5541,2656],{"class":932},[919,5543,2503],{"class":936},[919,5545,5546],{"class":921,"line":981},[919,5547,5548],{"class":2174},"    \u002F\u002F获取目标方法到的实参信息\n",[919,5550,5551,5553,5555,5557,5559,5561,5563],{"class":921,"line":1003},[919,5552,5352],{"class":936},[919,5554,1144],{"class":925},[919,5556,2669],{"class":936},[919,5558,2672],{"class":932},[919,5560,4228],{"class":936},[919,5562,4231],{"class":932},[919,5564,2777],{"class":936},[919,5566,5567,5569,5571,5573,5575,5577,5579,5581,5583,5585],{"class":921,"line":1008},[919,5568,5369],{"class":936},[919,5570,1165],{"class":932},[919,5572,955],{"class":936},[919,5574,4244],{"class":1170},[919,5576,1150],{"class":925},[919,5578,4249],{"class":936},[919,5580,1150],{"class":925},[919,5582,2664],{"class":1170},[919,5584,1150],{"class":925},[919,5586,4258],{"class":936},[919,5588,5589],{"class":921,"line":1030},[919,5590,1065],{"class":936},[896,5592,5593],{},[2060,5594,5595],{},"②获取目标方法的返回值",[896,5597,5598],{},"@AfterReturning中的属性returning，用来将通知方法的某个形参，接收目标方法的返回值",[911,5600,5602],{"className":913,"code":5601,"language":915,"meta":11,"style":11},"@AfterReturning(value = \"execution(* com.codermast.spring.CalculatorImpl.*(..))\", returning = \"result\")\npublic void afterReturningMethod(JoinPoint joinPoint, Object result){\n    String methodName = joinPoint.getSignature().getName();\n    System.out.println(\"Logger-->返回通知，方法名：\"+methodName+\"，结果：\"+result);\n}\n",[900,5603,5604,5628,5639,5655,5677],{"__ignoreMap":11},[919,5605,5606,5608,5610,5612,5614,5616,5618,5620,5622,5624,5626],{"class":921,"line":922},[919,5607,2873],{"class":936},[919,5609,4342],{"class":925},[919,5611,955],{"class":936},[919,5613,4347],{"class":2206},[919,5615,4350],{"class":925},[919,5617,4353],{"class":1170},[919,5619,965],{"class":936},[919,5621,4358],{"class":2206},[919,5623,4350],{"class":925},[919,5625,4363],{"class":1170},[919,5627,4177],{"class":936},[919,5629,5630,5632,5634,5636],{"class":921,"line":940},[919,5631,926],{"class":925},[919,5633,2883],{"class":925},[919,5635,4374],{"class":932},[919,5637,5638],{"class":936},"(JoinPoint joinPoint, Object result){\n",[919,5640,5641,5643,5645,5647,5649,5651,5653],{"class":921,"line":946},[919,5642,5335],{"class":936},[919,5644,1144],{"class":925},[919,5646,4205],{"class":936},[919,5648,4208],{"class":932},[919,5650,2497],{"class":936},[919,5652,2656],{"class":932},[919,5654,2503],{"class":936},[919,5656,5657,5659,5661,5663,5665,5667,5669,5671,5673,5675],{"class":921,"line":976},[919,5658,5369],{"class":936},[919,5660,1165],{"class":932},[919,5662,955],{"class":936},[919,5664,4413],{"class":1170},[919,5666,1150],{"class":925},[919,5668,4249],{"class":936},[919,5670,1150],{"class":925},[919,5672,2713],{"class":1170},[919,5674,1150],{"class":925},[919,5676,4426],{"class":936},[919,5678,5679],{"class":921,"line":981},[919,5680,1065],{"class":936},[896,5682,5683],{},[2060,5684,5685],{},"③获取目标方法的异常",[896,5687,5688],{},"@AfterThrowing中的属性throwing，用来将通知方法的某个形参，接收目标方法的异常",[911,5690,5692],{"className":913,"code":5691,"language":915,"meta":11,"style":11},"@AfterThrowing(value = \"execution(* com.codermast.spring.CalculatorImpl.*(..))\", throwing = \"ex\")\npublic void afterThrowingMethod(JoinPoint joinPoint, Throwable ex){\n    String methodName = joinPoint.getSignature().getName();\n    System.out.println(\"Logger-->异常通知，方法名：\"+methodName+\"，异常：\"+ex);\n}\n",[900,5693,5694,5718,5729,5745,5767],{"__ignoreMap":11},[919,5695,5696,5698,5700,5702,5704,5706,5708,5710,5712,5714,5716],{"class":921,"line":922},[919,5697,2873],{"class":936},[919,5699,4441],{"class":925},[919,5701,955],{"class":936},[919,5703,4347],{"class":2206},[919,5705,4350],{"class":925},[919,5707,4353],{"class":1170},[919,5709,965],{"class":936},[919,5711,4454],{"class":2206},[919,5713,4350],{"class":925},[919,5715,4459],{"class":1170},[919,5717,4177],{"class":936},[919,5719,5720,5722,5724,5726],{"class":921,"line":940},[919,5721,926],{"class":925},[919,5723,2883],{"class":925},[919,5725,4470],{"class":932},[919,5727,5728],{"class":936},"(JoinPoint joinPoint, Throwable ex){\n",[919,5730,5731,5733,5735,5737,5739,5741,5743],{"class":921,"line":946},[919,5732,5335],{"class":936},[919,5734,1144],{"class":925},[919,5736,4205],{"class":936},[919,5738,4208],{"class":932},[919,5740,2497],{"class":936},[919,5742,2656],{"class":932},[919,5744,2503],{"class":936},[919,5746,5747,5749,5751,5753,5755,5757,5759,5761,5763,5765],{"class":921,"line":976},[919,5748,5369],{"class":936},[919,5750,1165],{"class":932},[919,5752,955],{"class":936},[919,5754,4509],{"class":1170},[919,5756,1150],{"class":925},[919,5758,4249],{"class":936},[919,5760,1150],{"class":925},[919,5762,2766],{"class":1170},[919,5764,1150],{"class":925},[919,5766,4522],{"class":936},[919,5768,5769],{"class":921,"line":981},[919,5770,1065],{"class":936},[2138,5772,5773],{"id":5773},"环绕通知",[911,5775,5777],{"className":913,"code":5776,"language":915,"meta":11,"style":11},"@Around(\"execution(* com.codermast.spring.CalculatorImpl.*(..))\")\npublic Object aroundMethod(ProceedingJoinPoint joinPoint){\n    String methodName = joinPoint.getSignature().getName();\n    String args = Arrays.toString(joinPoint.getArgs());\n    Object result = null;\n    try {\n        System.out.println(\"环绕通知-->目标对象方法执行之前\");\n        \u002F\u002F目标方法的执行，目标方法的返回值一定要返回给外界调用者\n        result = joinPoint.proceed();\n        System.out.println(\"环绕通知-->目标对象方法返回值之后\");\n    } catch (Throwable throwable) {\n        throwable.printStackTrace();\n        System.out.println(\"环绕通知-->目标对象方法出现异常时\");\n    } finally {\n        System.out.println(\"环绕通知-->目标对象方法执行完毕\");\n    }\n    return result;\n}\n",[900,5778,5779,5791,5802,5818,5834,5845,5852,5864,5869,5882,5894,5907,5916,5928,5936,5948,5952,5959],{"__ignoreMap":11},[919,5780,5781,5783,5785,5787,5789],{"class":921,"line":922},[919,5782,2873],{"class":936},[919,5784,4537],{"class":925},[919,5786,955],{"class":936},[919,5788,4278],{"class":1170},[919,5790,4177],{"class":936},[919,5792,5793,5795,5797,5799],{"class":921,"line":940},[919,5794,926],{"class":925},[919,5796,2437],{"class":936},[919,5798,4552],{"class":932},[919,5800,5801],{"class":936},"(ProceedingJoinPoint joinPoint){\n",[919,5803,5804,5806,5808,5810,5812,5814,5816],{"class":921,"line":946},[919,5805,5335],{"class":936},[919,5807,1144],{"class":925},[919,5809,4205],{"class":936},[919,5811,4208],{"class":932},[919,5813,2497],{"class":936},[919,5815,2656],{"class":932},[919,5817,2503],{"class":936},[919,5819,5820,5822,5824,5826,5828,5830,5832],{"class":921,"line":976},[919,5821,5352],{"class":936},[919,5823,1144],{"class":925},[919,5825,2669],{"class":936},[919,5827,2672],{"class":932},[919,5829,4228],{"class":936},[919,5831,4231],{"class":932},[919,5833,2777],{"class":936},[919,5835,5836,5839,5841,5843],{"class":921,"line":981},[919,5837,5838],{"class":936},"    Object result ",[919,5840,1144],{"class":925},[919,5842,2626],{"class":2206},[919,5844,2629],{"class":936},[919,5846,5847,5850],{"class":921,"line":1003},[919,5848,5849],{"class":925},"    try",[919,5851,937],{"class":936},[919,5853,5854,5856,5858,5860,5862],{"class":921,"line":1008},[919,5855,1162],{"class":936},[919,5857,1165],{"class":932},[919,5859,955],{"class":936},[919,5861,4621],{"class":1170},[919,5863,973],{"class":936},[919,5865,5866],{"class":921,"line":1030},[919,5867,5868],{"class":2174},"        \u002F\u002F目标方法的执行，目标方法的返回值一定要返回给外界调用者\n",[919,5870,5871,5874,5876,5878,5880],{"class":921,"line":1035},[919,5872,5873],{"class":936},"        result ",[919,5875,1144],{"class":925},[919,5877,4205],{"class":936},[919,5879,4640],{"class":932},[919,5881,2503],{"class":936},[919,5883,5884,5886,5888,5890,5892],{"class":921,"line":1057},[919,5885,1162],{"class":936},[919,5887,1165],{"class":932},[919,5889,955],{"class":936},[919,5891,4653],{"class":1170},[919,5893,973],{"class":936},[919,5895,5896,5899,5901,5903,5905],{"class":921,"line":1062},[919,5897,5898],{"class":936},"    } ",[919,5900,2725],{"class":925},[919,5902,4665],{"class":936},[919,5904,4668],{"class":961},[919,5906,1129],{"class":936},[919,5908,5909,5912,5914],{"class":921,"line":1197},[919,5910,5911],{"class":936},"        throwable.",[919,5913,2741],{"class":932},[919,5915,2503],{"class":936},[919,5917,5918,5920,5922,5924,5926],{"class":921,"line":1202},[919,5919,1162],{"class":936},[919,5921,1165],{"class":932},[919,5923,955],{"class":936},[919,5925,4690],{"class":1170},[919,5927,973],{"class":936},[919,5929,5930,5932,5934],{"class":921,"line":1209},[919,5931,5898],{"class":936},[919,5933,2784],{"class":925},[919,5935,937],{"class":936},[919,5937,5938,5940,5942,5944,5946],{"class":921,"line":1232},[919,5939,1162],{"class":936},[919,5941,1165],{"class":932},[919,5943,955],{"class":936},[919,5945,4711],{"class":1170},[919,5947,973],{"class":936},[919,5949,5950],{"class":921,"line":1237},[919,5951,1194],{"class":936},[919,5953,5954,5957],{"class":921,"line":1253},[919,5955,5956],{"class":925},"    return",[919,5958,1189],{"class":936},[919,5960,5961],{"class":921,"line":1258},[919,5962,1065],{"class":936},[2138,5964,5965],{"id":5965},"切面的优先级",[896,5967,5968,5969,5972],{},"相同目标方法上同时存在多个切面时，切面的优先级控制切面的",[2060,5970,5971],{},"内外嵌套","顺序。",[904,5974,5975,5978],{},[907,5976,5977],{},"优先级高的切面：外面",[907,5979,5980],{},"优先级低的切面：里面",[896,5982,5983],{},"使用@Order注解可以控制切面的优先级：",[904,5985,5986,5989],{},[907,5987,5988],{},"@Order(较小的数)：优先级高",[907,5990,5991],{},"@Order(较大的数)：优先级低",[896,5993,5994],{},[2097,5995],{"alt":11,"src":5996},"\u002Fassets\u002Fjava\u002Fspring\u002Fspring-aop\u002F2024-01-01-22-03-32.png",[892,5998,6000],{"id":5999},"基于xml的aop","基于XML的AOP",[2138,6002,3215],{"id":6003},"准备工作-1",[896,6005,6006],{},"参考基于注解的AOP环境",[2138,6008,6009],{"id":6009},"实现",[911,6011,6013],{"className":3226,"code":6012,"language":3228,"meta":11,"style":11},"\u003Ccontext:component-scan base-package=\"com.codermast.spring.CalculatorImpl\">\u003C\u002Fcontext:component-scan>\n\n\u003Caop:config>\n    \u003C!--配置切面类-->\n    \u003Caop:aspect ref=\"loggerAspect\">\n        \u003Caop:pointcut id=\"pointCut\" \n                   expression=\"execution(* com.codermast.spring.CalculatorImpl.*(..))\"\u002F>\n        \u003Caop:before method=\"beforeMethod\" pointcut-ref=\"pointCut\">\u003C\u002Faop:before>\n        \u003Caop:after method=\"afterMethod\" pointcut-ref=\"pointCut\">\u003C\u002Faop:after>\n        \u003Caop:after-returning method=\"afterReturningMethod\" returning=\"result\" pointcut-ref=\"pointCut\">\u003C\u002Faop:after-returning>\n        \u003Caop:after-throwing method=\"afterThrowingMethod\" throwing=\"ex\" pointcut-ref=\"pointCut\">\u003C\u002Faop:after-throwing>\n        \u003Caop:around method=\"aroundMethod\" pointcut-ref=\"pointCut\">\u003C\u002Faop:around>\n    \u003C\u002Faop:aspect>\n\u003C\u002Faop:config>\n",[900,6014,6015,6035,6039,6048,6053,6070,6088,6099,6127,6153,6187,6221,6247,6255],{"__ignoreMap":11},[919,6016,6017,6019,6021,6023,6025,6028,6031,6033],{"class":921,"line":922},[919,6018,3235],{"class":936},[919,6020,4887],{"class":3238},[919,6022,4890],{"class":932},[919,6024,1144],{"class":936},[919,6026,6027],{"class":1170},"\"com.codermast.spring.CalculatorImpl\"",[919,6029,6030],{"class":936},">\u003C\u002F",[919,6032,4887],{"class":3238},[919,6034,3242],{"class":936},[919,6036,6037],{"class":921,"line":940},[919,6038,2388],{"emptyLinePlaceholder":2387},[919,6040,6041,6043,6046],{"class":921,"line":946},[919,6042,3235],{"class":936},[919,6044,6045],{"class":3238},"aop:config",[919,6047,3242],{"class":936},[919,6049,6050],{"class":921,"line":976},[919,6051,6052],{"class":2174},"    \u003C!--配置切面类-->\n",[919,6054,6055,6057,6060,6063,6065,6068],{"class":921,"line":981},[919,6056,3257],{"class":936},[919,6058,6059],{"class":3238},"aop:aspect",[919,6061,6062],{"class":932}," ref",[919,6064,1144],{"class":936},[919,6066,6067],{"class":1170},"\"loggerAspect\"",[919,6069,3242],{"class":936},[919,6071,6072,6074,6077,6080,6082,6085],{"class":921,"line":1003},[919,6073,3267],{"class":936},[919,6075,6076],{"class":3238},"aop:pointcut",[919,6078,6079],{"class":932}," id",[919,6081,1144],{"class":936},[919,6083,6084],{"class":1170},"\"pointCut\"",[919,6086,6087],{"class":936}," \n",[919,6089,6090,6093,6095,6097],{"class":921,"line":1008},[919,6091,6092],{"class":932},"                   expression",[919,6094,1144],{"class":936},[919,6096,4278],{"class":1170},[919,6098,4898],{"class":936},[919,6100,6101,6103,6106,6109,6111,6114,6117,6119,6121,6123,6125],{"class":921,"line":1030},[919,6102,3267],{"class":936},[919,6104,6105],{"class":3238},"aop:before",[919,6107,6108],{"class":932}," method",[919,6110,1144],{"class":936},[919,6112,6113],{"class":1170},"\"beforeMethod\"",[919,6115,6116],{"class":932}," pointcut-ref",[919,6118,1144],{"class":936},[919,6120,6084],{"class":1170},[919,6122,6030],{"class":936},[919,6124,6105],{"class":3238},[919,6126,3242],{"class":936},[919,6128,6129,6131,6134,6136,6138,6141,6143,6145,6147,6149,6151],{"class":921,"line":1035},[919,6130,3267],{"class":936},[919,6132,6133],{"class":3238},"aop:after",[919,6135,6108],{"class":932},[919,6137,1144],{"class":936},[919,6139,6140],{"class":1170},"\"afterMethod\"",[919,6142,6116],{"class":932},[919,6144,1144],{"class":936},[919,6146,6084],{"class":1170},[919,6148,6030],{"class":936},[919,6150,6133],{"class":3238},[919,6152,3242],{"class":936},[919,6154,6155,6157,6160,6162,6164,6167,6170,6172,6175,6177,6179,6181,6183,6185],{"class":921,"line":1057},[919,6156,3267],{"class":936},[919,6158,6159],{"class":3238},"aop:after-returning",[919,6161,6108],{"class":932},[919,6163,1144],{"class":936},[919,6165,6166],{"class":1170},"\"afterReturningMethod\"",[919,6168,6169],{"class":932}," returning",[919,6171,1144],{"class":936},[919,6173,6174],{"class":1170},"\"result\"",[919,6176,6116],{"class":932},[919,6178,1144],{"class":936},[919,6180,6084],{"class":1170},[919,6182,6030],{"class":936},[919,6184,6159],{"class":3238},[919,6186,3242],{"class":936},[919,6188,6189,6191,6194,6196,6198,6201,6204,6206,6209,6211,6213,6215,6217,6219],{"class":921,"line":1062},[919,6190,3267],{"class":936},[919,6192,6193],{"class":3238},"aop:after-throwing",[919,6195,6108],{"class":932},[919,6197,1144],{"class":936},[919,6199,6200],{"class":1170},"\"afterThrowingMethod\"",[919,6202,6203],{"class":932}," throwing",[919,6205,1144],{"class":936},[919,6207,6208],{"class":1170},"\"ex\"",[919,6210,6116],{"class":932},[919,6212,1144],{"class":936},[919,6214,6084],{"class":1170},[919,6216,6030],{"class":936},[919,6218,6193],{"class":3238},[919,6220,3242],{"class":936},[919,6222,6223,6225,6228,6230,6232,6235,6237,6239,6241,6243,6245],{"class":921,"line":1197},[919,6224,3267],{"class":936},[919,6226,6227],{"class":3238},"aop:around",[919,6229,6108],{"class":932},[919,6231,1144],{"class":936},[919,6233,6234],{"class":1170},"\"aroundMethod\"",[919,6236,6116],{"class":932},[919,6238,1144],{"class":936},[919,6240,6084],{"class":1170},[919,6242,6030],{"class":936},[919,6244,6227],{"class":3238},[919,6246,3242],{"class":936},[919,6248,6249,6251,6253],{"class":921,"line":1202},[919,6250,3310],{"class":936},[919,6252,6059],{"class":3238},[919,6254,3242],{"class":936},[919,6256,6257,6259,6261],{"class":921,"line":1209},[919,6258,3621],{"class":936},[919,6260,6045],{"class":3238},[919,6262,3242],{"class":936},[6264,6265,6266],"style",{},"html pre.shiki code .s8jYJ, html code.shiki .s8jYJ{--shiki-light:#D73A49;--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .snPdu, html code.shiki .snPdu{--shiki-light:#6F42C1;--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .sxrX7, html code.shiki .sxrX7{--shiki-light:#24292E;--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .sP4rz, html code.shiki .sP4rz{--shiki-light:#E36209;--shiki-default:#E36209;--shiki-dark:#FFAB70}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sIIMD, html code.shiki .sIIMD{--shiki-light:#032F62;--shiki-default:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .sCsY4, html code.shiki .sCsY4{--shiki-light:#6A737D;--shiki-default:#6A737D;--shiki-dark:#6A737D}html pre.shiki code .sBjJW, html code.shiki .sBjJW{--shiki-light:#005CC5;--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .sovSZ, html code.shiki .sovSZ{--shiki-light:#22863A;--shiki-default:#22863A;--shiki-dark:#85E89D}",{"title":11,"searchDepth":940,"depth":940,"links":6268},[6269,6270,6274],{"id":894,"depth":940,"text":894},{"id":2078,"depth":940,"text":2078,"children":6271},[6272,6273],{"id":2140,"depth":946,"text":2140},{"id":2356,"depth":946,"text":2356},{"id":2973,"depth":940,"text":2974,"children":6275},[6276,6277],{"id":2977,"depth":946,"text":2977},{"id":2983,"depth":946,"text":2983},"md",{},{"title":496,"description":11},"other\u002Fspring-series\u002Fspring\u002Fspring-aop","TYKOeBLY9HQ94dIHV9ZD7uoQzAFLXzuQJGuE-euIMpw",1775496430380]