12AOP面向切面编程/GoF之代理模式
先看一个例子:
声明一个接口:
// + - * / 运算的标准接口!
public interface Calculator {int add(int i, int j);int sub(int i, int j);int mul(int i, int j);int div(int i, int j);
}
实现该接口:
package com.sunsplanter.proxy;/*** 在每个方法中,输出传入的参数和计算后的返回结果!*/
public class CalculatorLogImpl implements Calculator {@Overridepublic int add(int i, int j) {System.out.println("参数是:" + i + "," + j);int result = i + j;System.out.println("方法内部 result = " + result);return result;}@Overridepublic int sub(int i, int j) {System.out.println("参数是:" + i + "," + j);int result = i - j;System.out.println("方法内部 result = " + result);return result;}@Overridepublic int mul(int i, int j) {System.out.println("参数是:" + i + "," + j);int result = i * j;System.out.println("方法内部 result = " + result);return result;}@Overridepublic int div(int i, int j) {System.out.println("参数是:" + i + "," + j);int result = i / j;System.out.println("方法内部 result = " + result);return result;}
}
存在的问题:
- 核心功能与边缘功能掺杂(即计算的过程和sout掺杂)
- 边缘功能尽管重复,但却大量分散,不利于管理
目标: 将重复的代码统一提取,并且[[动态插入]]到每个业务方法!
用代理模式解决:

相关术语:
- 代理:将非核心逻辑剥离出来以后,封装这些非核心逻辑的类、对象、方法。(中介)
- 动词:指做代理这个动作,或这项工作
- 名词:扮演代理这个角色的类、对象、方法
- 目标:被代理“套用”了核心逻辑代码的类、对象、方法。(房东)
解决问题的思维:AOP
解决问题技术:代理技术
代理技术太麻烦,因此使用框架
Spring AOP框架(底层是代理技术:jdk动态daili,cglib)
代理在开发中实现的方式具体有两种:静态代理,[动态代理技术]
1. 静态代理解决了功能掺杂
缺点:静态代理确实实现了解耦,但是由于代码都写死了,完全不具备任何的灵活性。就拿sout来说,将来其他地方也需要sout,那还得再声明更多个静态代理类,那就产生了大量重复的代码,sout还是分散的,没有统一管理。
项目结构:
原有代码不变,
使用静态代理即主动创建一个代理类CalculatorStaticProxy实现接口,:
public class CalculatorStaticProxy implements Calculator {// 将被代理的目标对象声明为成员变量(令代理类与被代理对象建立关系)private Calculator target;//将代理对象传入构造方法,“注入”public CalculatorStaticProxy(Calculator target) {this.target = target;}@Overridepublic int add(int i, int j) {// 附加功能由代理类中的代理方法来实现System.out.println("参数是:" + i + "," + j);// 通过目标对象来实现核心业务逻辑int addResult = target.add(i, j);System.out.println("方法内部 result = " + result);return addResult;}@Overridepublic int sub(int i, int j) {// 附加功能由代理类中的代理方法来实现System.out.println("参数是:" + i + "," + j);// 通过目标对象来实现核心业务逻辑int subResult = target.sub(i, j);System.out.println("方法内部 result = " + result);return subResult;}……
提出进一步的需求:将sout集中到一个代理类中,将来有任何日志需求,都通过这一个代理类来实现。这就需要使用动态代理技术了。
2. 动态代理进一步解决了集中管理边缘功能
动态代理技术分类
- JDK动态代理:JDK原生的实现方式,需要被代理的目标类必须实现接口(也即 必须有接口)!他会根据目标类的接口动态生成一个代理对象!代理对象和目标对象有相同的接口!(接口作为父亲,代理对象和目标对象拜把子)
- cglib:通过继承被代理的目标类实现代理,可以代理没有实现接口的类!(也即不需要有接口,代理对象认目标对象为干爹)
JDK动态代理技术实现(了解)

代理工程:基于jdk代理技术,生成代理对象
在这里我们不给出代理的具体实现代码,后续会学习Spring AOP框架,该框架封装动态代理技术,们只需写少量的配置,指定生效范围即可,即可完成面向切面思维编程的实现!
3. AOP思维
-
OOP引入封装、继承、多态等概念来建立一种对象层次结构,用于模拟公共行为的一个集合。OOP允许开发者定义纵向的关系。但在OOP设计中,它导致了大量公共代码的重复,而不利于各个模块的重用。
-
AOP技术恰恰相反,它利用一种称为"横切"的技术,剖解开封装的对象内部,并将那些影响了多个类的公共行为封装到一个可重用模块,并将其命名为"Aspect",即切面。所谓"切面",简单说就是那些与业务无关,却为业务模块所共同调用的逻辑或责任封装起来,便于减少系统的重复代码,降低模块之间的耦合度,并有利于未来的可操作性和可维护性。
-
使用AOP,可以在不修改原来代码的基础上添加新功能。
-
AOP思想主要的应用场景
- 日志记录:在系统中记录日志是非常重要的,可以使用AOP来实现日志记录的功能,可以在方法执行前、执行后或异常抛出时记录日志。
- 事务处理:在数据库操作中使用事务可以保证数据的一致性,可以使用AOP来实现事务处理的功能,可以在方法开始前开启事务,在方法执行完毕后提交或回滚事务。
- 安全控制:在系统中包含某些需要安全控制的操作,如登录、修改密码、授权等,可以使用AOP来实现安全控制的功能。可以在方法执行前进行权限判断,如果用户没有权限,则抛出异常或转向到错误页面,以防止未经授权的访问。
- 性能监控:在系统运行过程中,有时需要对某些方法的性能进行监控,以找到系统的瓶颈并进行优化。可以使用AOP来实现性能监控的功能,可以在方法执行前记录时间戳,在方法执行完毕后计算方法执行时间并输出到日志中。
- 异常处理:系统中可能出现各种异常情况,如空指针异常、数据库连接异常等,可以使用AOP来实现异常处理的功能,在方法执行过程中,如果出现异常,则进行异常处理(如记录日志、发送邮件等)。
- 缓存控制:在系统中有些数据可以缓存起来以提高访问速度,可以使用AOP来实现缓存控制的功能,可以在方法执行前查询缓存中是否有数据,如果有则返回,否则执行方法并将方法返回值存入缓存中。
- 动态代理:AOP的实现方式之一是通过动态代理,可以代理某个类的所有方法,用于实现各种功能。
-
AOP术语名词介绍
1-横切关注点
从每个方法中抽取出来的同一类非核心业务。在同一个项目中,我们可以使用多个横切关注点对相关方法进行多个不同方面的增强。
有十个附加功能,就有十个横切关注点。

AOP把软件系统分为两个部分:核心关注点和横切关注点。业务处理的主要流程是核心关注点,与之关系不大的部分是横切关注点。横切关注点的一个特点是,他们经常发生在核心关注点的多处,而各处基本相似,比如权限认证、日志、事务、异常等。AOP的作用在于分离系统中的各种关注点,将核心关注点和横切关注点分离开来。
2-通知(增强)
每一个横切关注点上要做的事情都需要写一个方法来实现,这样的方法就叫通知方法。就是具体你要织入的代码。
- 前置通知:在被代理的目标方法前执行
- 返回通知:在被代理的目标方法成功结束后执行(寿终正寝)
- 异常通知:在被代理的目标方法异常结束后执行(死于非命)
- 后置通知:在被代理的目标方法最终结束后执行(盖棺定论)
- 环绕通知(最常用):使用try…catch…finally结构围绕整个被代理的目标方法,包括上面四种通知对应的所有位置。

3-切入点 pointcut
定位连接点的方式,或者可以理解成被选中的连接点!
是一个表达式,比如execution(* com.spring.service.impl..(…))。符合条件的每个方法都是一个具体的连接点。
4-切面 aspect
切入点和通知的结合。是一个类。

3-连接点 joinpoint
这也是一个纯逻辑概念,不是语法定义的。
指那些被拦截到的点。在 Spring 中,可以被动态代理拦截目标类的方法

6-目标 target
被代理的目标对象。
7-代理 proxy
向目标对象应用通知之后创建的代理对象。
8-织入 weave
指把通知应用到目标上,生成代理对象的过程。可以在编译期织入,也可以在运行期织入,Spring采用后者。
3.1 AOP封装层次
3.2 注解实现AOP
3.2.1 切点表达式:定义通知(Advice)往哪些方法上切入。
切入点表达式语法格式:
execution([访问控制权限修饰符] 返回值类型 [全限定类名]方法名(形式参数列表) [异常])

访问控制权限修饰符:
- 可选项。没写,就是4个权限都包括。
- 写public就表示只包括公开的方法。
返回值类型:
- 必填项。
- *表示返回值类型任意。
全限定类名:
- 可选项。
- 两个点“…”代表当前包以及子包下的所有类。
- 省略时表示所有的类。
方法名:
-
必填项。
-
*表示所有方法。
-
set*表示所有的set方法。
r
形式参数列表: -
必填项
-
() 表示没有参数的方法
-
(…) 参数类型和个数随意的方法
-
(*) 只有一个参数的方法
-
(*, String) 第一个参数类型随意,第二个参数是String的。
异常:
- 可选项。
- 省略时表示任意异常类型。
3.2.2 简单演示AOP的实现
- 首先是导入依赖,实现AOP需要导入Spring-aspect,但Spring-aop包括了Spring-aspect,Spring-context又包括了Spring-aop,因此之前导入的Spring-context就够了。
- 在spring配置文件中增加命名空间; 启用自动代理
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:context="http://www.springframework.org/schema/context"xmlns:aop="http://www.springframework.org/schema/aop"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsdhttp://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd"><!--开启组件扫描--><context:component-scan base-package="com.powernode.spring6.service"/><!--开启自动代理后,凡是带有@Aspect注解的bean都会生成代理对象。proxy-target-class是可选属性,默认为false时采用JDK动态代理,但即便是最坏的情况,即采用JDK动态代理,而类又没有实现接口,Spring仍会自动转向cglib动态代理--><aop:aspectj-autoproxy proxy-target-class="true"/>
</beans>
</beans>
- 定义目标类以及目标方法, 纳入Spring管理
package com.sunsplanter.spring6.service;// 目标类
@Component
public class OrderService {// 目标方法public void generate(){System.out.println("订单已生成!");}
}
第二步:定义切面类, 纳入Spring管理
package com.sunsplanter.spring6.service;import org.aspectj.lang.annotation.Aspect;// 切面类的注解
@Aspect
@Component
public class MyAspect {
}
第三步:在Spring配置文件中添加组建扫描
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:context="http://www.springframework.org/schema/context"xmlns:aop="http://www.springframework.org/schema/aop"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsdhttp://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd"><!--开启组件扫描--><context:component-scan base-package="com.powernode.spring6.service"/>
</beans>
第四步: 在切面类中定义一个切面
package com.sunsplanter.spring6.service;import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;
import org.aspectj.lang.annotation.Aspect;// 切面类
@Aspect
@Component
public class MyAspect {//通知+切点=切面// 切点表达式,@Before即前置通知@Before("execution(* com.powernode.spring6.service.OrderService.*(..))")// 这就是需要增强的代码(通知)public void advice(){System.out.println("我是一个通知");}
}
第五步:测试程序:
package com.sunsplanter.spring6.test;import com.sunsplanter.spring6.service.OrderService;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;public class AOPTest {@Testpublic void testAOP(){ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring-aspectj-aop-annotation.xml");OrderService orderService = applicationContext.getBean("orderService", OrderService.class);orderService.generate();}
}

目标:横向插入增强代码(日志输出/)
相关文章:
12AOP面向切面编程/GoF之代理模式
先看一个例子: 声明一个接口: // - * / 运算的标准接口! public interface Calculator {int add(int i, int j);int sub(int i, int j);int mul(int i, int j);int div(int i, int j); }实现该接口: package com.sunsplanter.prox…...
【MySQL】数据处理之增删改
文章目录 一、增加(插入)INSERT INTO...VALUES(...,...)VALUES的方式添加情况一:为表的所有字段按默认顺序插入数据情况二:为表的指定字段插入数据情况三:同时插入多条记录 将查询结果插入到表中 二、修改(…...
利用docker的LNMP
目录 服务器环境 任务需求 服务搭建 Nginx Mysql Php 启动 wordpress 服务 服务器环境 容器 操作系统 IP地址 主要软件 nginx CentOS 7 172.20.0.10 Docker-Nginx mysql CentOS 7 172.20.0.20 Docker-Mysql php CentOS 7 172.2…...
Grafana(二)Grafana 两种数据源图表展示(json-api与数据库)
一. 背景介绍 在先前的博客文章中,我们搭建了Grafana ,它是一个开源的度量分析和可视化工具,可以通过将采集的数据分析、查询,然后进行可视化的展示,接下来我们重点介绍如何使用它来进行数据渲染图表展示 Docker安装G…...
Shape-IoU——综合考量边框形状与尺度的度量
今天看到一篇文章主要是提出了一种更有效的IOU度量方法,论文地址在这里,如下所示: 摘要 边界盒回归损失作为检测器定位分支的重要组成部分,在目标检测任务中起着重要作用。现有的边界框回归方法通常考虑GT框和预测框之间的几何关…...
Stack详解(Java)
Stack Java 中的 Stack 是一种基于后进先出(LIFO)原则的数据结构。Stack 类实现了一个标准的堆栈,它继承自 Vector 类,并提供了一些额外的方法来支持堆栈的操作。 下面是一些 Java Stack 类的详细解释: 构造方法&…...
Qt框架学习 --- CTK编译(Qt5.15.2+vs2019+cmake)
系列文章目录 第二章 CTK的测试demo https://blog.csdn.net/yonug1107716573/article/details/135527289 文章目录 系列文章目录前言一、准备工作二、编译步骤1.修改文件2.编译CTK2.1 准备2.2 cmake界面配置2.3 配置编译器2.4 编译的配置设置2.5 选择需要编译的模块2.6 生成2.…...
Flink(十三)【Flink SQL(上)】
前言 最近在假期实训,但是实在水的不行,三天要学完SSM,实在一言难尽,浪费那时间干什么呢。SSM 之前学了一半,等后面忙完了,再去好好重学一遍,毕竟这玩意真是面试必会的东西。 今天开始学习 Flin…...
linux nginx配置链接访问图片
nginx 安装 sudo apt update sudo apt install nginxnginx 启动命令 sudo systemctl restart nginx # 重启 sudo systemctl start nginx #开启 sudo systemctl stop nginx # 关闭 sudo systemctl status nginx # 状态 sudo systemctl restart nginx.service #重启nginx安装成…...
深度学习笔记(二)——Tensorflow环境的安装
本篇文章只做基本的流程概述,不阐述具体每个软件的详细安装流程,具体的流程网上教程已经非常丰富。主要是给出完整的安装流程,以供参考 环境很重要 一个好的算法环境往往能够帮助开发者事半功倍,入门学习的时候往往搭建好环境就已…...
Java实现在线编辑预览office文档
文章目录 1 在线编辑1.1 PageOffice简介1.2 前端项目1.2.1 配置1.2.2 页面部分 1.3 后端项目1.3.1 pom.xml1.3.2 添加配置1.3.3 controller 2 在线预览2.1 引言2.2 市面上现有的文件预览服务2.2.1 微软2.2.2 Google Drive查看器2.2.3 阿里云 IMM2.2.4 XDOC 文档预览2.2.5 Offic…...
阿里云OSS上传视频,可分片上传
uniappH5实现 阿里云OSS上传视频 示例图: 上传视频完整示例代码: 使用npm安装SDK开发包,安装命令为 npm install ali-oss --save accessKeyId 和 accessKeySecret 还有 bucket 替换成你的就行。 multipartUpload 的第一个入参是&#x…...
Linux第三次课后作业
1.使用while和until语句编写脚本程序,计算1到100的和。 i1 s0 while(i<100) {sii} echo(s)sum0 i0 until test $num -eq 101 do #下面两个均为反斜杠 sumexpr $sum $i iexpr $num 1 done echo "the result is $sum"2.编写脚本程序备份用户指定的文件…...
WordPress后台仪表盘自定义添加删除概览项目插件Glance That
成功搭建WordPress站点,登录后台后可以在“仪表盘 – 概览”中看到包括多少篇文章、多少个页面、多少条评论和当前WordPress版本号及所使用的主题。具体如下图所示: 但是如果我们的WordPress站点还有自定义文章类型,也想在概览中显示出来应该…...
.Net6使用SignalR实现前后端实时通信
代码部分 后端代码 (Asp.net core web api,用的.net6)Program.cs 代码运行逻辑: 1. 通过 WebApplication.CreateBuilder(args) 创建一个 ASP.NET Core 应用程序建造器。 2. 使用 builder.Services.AddControllers() 添加 MVC 控…...
基于SpringBoot+Vue的时装服饰商城购物系统
博主介绍:✌程序员徐师兄、7年大厂程序员经历。全网粉丝30W、csdn博客专家、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ 🍅文末获取源码联系🍅 👇🏻 精彩专栏推荐订阅👇…...
近4w字吐血整理!只要你认真看完【C++编程核心知识】分分钟吊打面试官(包含:内存、函数、引用、类与对象、文件操作)
🌈个人主页:godspeed_lucip 🔥 系列专栏:C从基础到进阶 🏆🏆关注博主,随时获取更多关于C的优质内容!🏆🏆 C核心编程🌏1 内存分区模型🎄…...
pytest学习和使用-pytest如何进行分布式测试?(pytest-xdist)
1 什么是分布式测试? 在进行本文之前,先了解些基础知识,什么是分布式测试?分布式测试:是指通过局域网和Internet,把分布于不同地点、独立完成特定功能的测试计算机连接起来,以达到测试资源共享…...
虚拟ip可以解决所有的安全问题吗
虚拟IP(Virtual IP)是一种网络技术,可以把多台物理服务器或设备组合成一个逻辑集群,并且使用同一个IP地址对外提供服务。虚拟IP具有负载均衡、故障切换和高可用性等优势,同时还可以作为一种安全措施来增加系统的抗攻击…...
【数据库原理】(27)数据库恢复
在数据库系统中,恢复是指在发生某种故障导致数据库数据不再正确时,将数据库恢复到已知正确的某一状态的过程。数据库故障可能由多种原因引起,包括硬件故障、软件错误、操作员失误以及恶意破坏。为了确保数据库的安全性和完整性,数…...
进程地址空间(比特课总结)
一、进程地址空间 1. 环境变量 1 )⽤户级环境变量与系统级环境变量 全局属性:环境变量具有全局属性,会被⼦进程继承。例如当bash启动⼦进程时,环 境变量会⾃动传递给⼦进程。 本地变量限制:本地变量只在当前进程(ba…...
【OSG学习笔记】Day 18: 碰撞检测与物理交互
物理引擎(Physics Engine) 物理引擎 是一种通过计算机模拟物理规律(如力学、碰撞、重力、流体动力学等)的软件工具或库。 它的核心目标是在虚拟环境中逼真地模拟物体的运动和交互,广泛应用于 游戏开发、动画制作、虚…...
R语言AI模型部署方案:精准离线运行详解
R语言AI模型部署方案:精准离线运行详解 一、项目概述 本文将构建一个完整的R语言AI部署解决方案,实现鸢尾花分类模型的训练、保存、离线部署和预测功能。核心特点: 100%离线运行能力自包含环境依赖生产级错误处理跨平台兼容性模型版本管理# 文件结构说明 Iris_AI_Deployme…...
Day131 | 灵神 | 回溯算法 | 子集型 子集
Day131 | 灵神 | 回溯算法 | 子集型 子集 78.子集 78. 子集 - 力扣(LeetCode) 思路: 笔者写过很多次这道题了,不想写题解了,大家看灵神讲解吧 回溯算法套路①子集型回溯【基础算法精讲 14】_哔哩哔哩_bilibili 完…...
Linux相关概念和易错知识点(42)(TCP的连接管理、可靠性、面临复杂网络的处理)
目录 1.TCP的连接管理机制(1)三次握手①握手过程②对握手过程的理解 (2)四次挥手(3)握手和挥手的触发(4)状态切换①挥手过程中状态的切换②握手过程中状态的切换 2.TCP的可靠性&…...
1.3 VSCode安装与环境配置
进入网址Visual Studio Code - Code Editing. Redefined下载.deb文件,然后打开终端,进入下载文件夹,键入命令 sudo dpkg -i code_1.100.3-1748872405_amd64.deb 在终端键入命令code即启动vscode 需要安装插件列表 1.Chinese简化 2.ros …...
【ROS】Nav2源码之nav2_behavior_tree-行为树节点列表
1、行为树节点分类 在 Nav2(Navigation2)的行为树框架中,行为树节点插件按照功能分为 Action(动作节点)、Condition(条件节点)、Control(控制节点) 和 Decorator(装饰节点) 四类。 1.1 动作节点 Action 执行具体的机器人操作或任务,直接与硬件、传感器或外部系统…...
Cloudflare 从 Nginx 到 Pingora:性能、效率与安全的全面升级
在互联网的快速发展中,高性能、高效率和高安全性的网络服务成为了各大互联网基础设施提供商的核心追求。Cloudflare 作为全球领先的互联网安全和基础设施公司,近期做出了一个重大技术决策:弃用长期使用的 Nginx,转而采用其内部开发…...
04-初识css
一、css样式引入 1.1.内部样式 <div style"width: 100px;"></div>1.2.外部样式 1.2.1.外部样式1 <style>.aa {width: 100px;} </style> <div class"aa"></div>1.2.2.外部样式2 <!-- rel内表面引入的是style样…...
Java + Spring Boot + Mybatis 实现批量插入
在 Java 中使用 Spring Boot 和 MyBatis 实现批量插入可以通过以下步骤完成。这里提供两种常用方法:使用 MyBatis 的 <foreach> 标签和批处理模式(ExecutorType.BATCH)。 方法一:使用 XML 的 <foreach> 标签ÿ…...
