Google Guice 5:AOP
1. AOP
1.1 实际开发中面临的问题
-
在实际开发中,经常需要打印一个方法的执行时间,以确定是否存在慢操作
-
最简单的方法,直接修改已有的方法,在
finnally
语句中打印耗时@Override public Optional<Table> getTable(String databaseName, String tableName) {long startTime = System.currentTimeMillis();try {... // 省略关键代码return result;}... // 省略catch语句finally {long consumedTime = System.currentTimeMillis() - startTime;logger.info("getTable() -- databaseName: %s, tableName: %s, consumed time: %dms", databaseName, tableName, consumedTime);} }
-
随着打印耗时的需求增多,你会发现整个应用程序中存在很多打印耗时的代码
-
这些代码如果按照OOP(
Object Oriented Programming
)编程的思想,是无法抽象出来复用的,因为它与方法的执行是紧耦合的 -
而且随着需求的增多,安全检查、权限校验、审计日志等附加功能的代码,会使得整个方法越来越臃肿,以致难以阅读
-
同时,如果附加功能的逻辑发生变化,将牵一发而动全身
1.2 AOP编程
-
这时,我们希望有一种编程范例,能将这些公共的代码从方法中剥离出来,并切入到有需要的方法中
-
这种范例叫做AOP(
Aspect-Oriented Programming
,面向切面编程) -
它将问题划分成了不同的面(
Aspect
),在程序编译或运行阶段可以将这些面插入到需要的地方,以实现辅助功能与核心逻辑的解耦以及代码的复用 -
维基百科对AOP的描述如下:
- In computing, aspect-oriented programming (AOP) is a programming paradigm that aims to increase modularity by allowing the separation of cross-cutting concerns.
在计算机领域,AOP是一种允许横切关注以增加代码模块化的编程范例 - It does so by adding behavior to existing code (an advice) without modifying the code itself, instead separately specifying which code is modified via a “pointcut” specification, such as “log all function calls when the function’s name begins with ‘set’”.
它可以在不修改代码本身的情况下,向已有的代码添加行为(an advice),通过 "pointcut"规范来单独指定修改哪些代码,例如:记录所有以set开头的函数的调用 - This allows behaviors that are not central to the business logic (such as logging) to be added to a program without cluttering the code core to the functionality.
这样可以允许将不属于业务核心逻辑的行为(如日志打印)添加到程序中,并不会导致功能的代码核心紊乱
- In computing, aspect-oriented programming (AOP) is a programming paradigm that aims to increase modularity by allowing the separation of cross-cutting concerns.
-
上述的第二点,笔者觉得维基百科的描述可能存在一定问题:
- advice,通知,是对被拦截到的方法需要执行的代码(又叫增强),可以是前置、后置、最终、异常、环绕通知五类。以环绕通知为例,就是在方法执行前后需要执行的代码
- pointcut: joint point是连接点的意思,即可能需要注入切面的地方;而pointcut用于定义需要特殊处理的连接点
1.3 Srping AOP的常见术语
-
使用过Spring进行AOP编程的小伙伴,可能会注意到Aspect、Pointcut、Advice(Before、After、AfterReturning、AfterThrowing、Around)这些类似的关键字
-
在Spring AOP中,有很多术语,但最常使用的还是上面三种术语
-
下面是一段打印controller请求参数的AOP代码
@Component @Aspect // 表示这是一个切面 public class ControllerParamsLogAspect {private static final Logger logger = LoggerFactory.getLogger(ControllerParamsLogAspect.class);// 定义切点,匹配com.sunrise.controller包下所有的public方法,方法的参数任意@Pointcut("execution(public * com.sunrise.controller..*.*(..))")public void logAspect() {}// 前置通知,在执行controller方法前,打印方法入参@Before("logAspect()")public void doBefore(JoinPoint point) {// 构建打印内容JSONObject content = new JSONObject();try {... // 省略核心代码logger.error("API请求信息:{}", CommonUtils.jsonObjectToString(content));} catch (Exception exception) {... // 省略异常处理代码}} }
-
以上与AOP有关的注解,需要的maven依赖如下:
<dependency><groupId>org.aspectj</groupId><artifactId>aspectjrt</artifactId><version>1.8.14</version> </dependency>
-
其余术语概念可以参考:
- Spring AOP详解
- Spring 学习笔记(四):Spring AOP
-
PS: 阅读理论知识如果让你觉得迷糊,可以尝试直接看一段代码或者写一个小demo
2. AOP的实现方法
2.1 笔者的理解
-
通过对AOP基础知识的学习,在笔者心中AOP的实现方法,就应该像动态代理一样:以某种方式调用方法(如反射),并在方法的执行前后添加一些代码,从而可以在不修改已有业务逻辑的情况下增强方法
-
这是使用JDK动态代理实现的,打印方法耗时的核心代码:
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {long startTime = System.currentTimeMillis();try {return method.invoke(animal, args);} finally {long diff = System.currentTimeMillis() - startTime;System.out.printf("%s() called, consumed %dms\n", method.getName(), diff);} }
-
然而,动态代理是有针对性的,AOP应该是有普适性的
- cglib动态代理虽然能代理一个类,但是后续对该类的访问,都需要转为对proxy的访问
- AOP则可以在满足特定规则的所有方法上使用,例如,只要对方法添加指定注解,Aspect则可以应用到这些方法上;又或者,所以以
set
开头的方法,都可以打印审计日志以记录数据的变化
-
让笔者不认同的是,有些博客宣称可以使用动态代理实现AOP,这明显是忽略了AOP的普适性
-
当然,这也可能是笔者对动态代理的理解不够深入 🤣 🤣 🤣
-
Guice使用拦截器机制实现AOP,笔者也比较赞同这种思想
2.2. Guice对AOP的支持
-
使用AOP实现一个打印方法耗时的功能,在目标方法执行结束后,系统会自动打印该方法的耗时
-
定义一个注解,使用该注解的方法,都将获得耗时打印的附加能力
@Target({METHOD}) @Retention(RUNTIME) public @interface PrintExecutionTime { }
-
定义一个打印方法耗时的拦截器,它实现了
org.aopalliance.intercept.MethodInterceptor
接口public class ExecutionTimePrinter implements MethodInterceptor {@Overridepublic Object invoke(MethodInvocation invocation) throws Throwable {long startTime = System.currentTimeMillis();try {return invocation.proceed();} finally {long consumedTime = System.currentTimeMillis() - startTime;System.out.printf("call %s() and consumed %dms\n", invocation.getMethod().getName(), consumedTime);}} }
-
将拦截器应用到计算器的某些方法上
public class Calculator {private static final Random random = new Random();@PrintExecutionTimepublic int add(int a, int b) throws Throwable {// 随机休眠一段时间Thread.sleep(random.nextInt(2000));return a + b;}public int sub(int a, int b) {return a - b;}@PrintExecutionTimepublic int div(int a, int b) throws Throwable {// 随机休眠一段时间Thread.sleep(random.nextInt(2000));return a / b;}public long mul(int a, int b) {return a * b;} }
-
在Module中定义pointcut,即拦截器将作用到满足什么规则的方法上
public class AopModule extends AbstractModule {@Overrideprotected void configure() {// ExecutionTimePrinter将作用到任意类的、使用了@PrintExecutionTime的方法上bindInterceptor(Matchers.any(), Matchers.annotatedWith(PrintExecutionTime.class),new ExecutionTimePrinter());} }
-
从Guice中获取一个计算器实例,执行其方法以验证拦截器是否生效
public static void main(String[] args) throws Throwable {Injector injector = Guice.createInjector(new AopModule());Calculator calculator = injector.getInstance(Calculator.class);int a = 12, b = 24;System.out.printf("%d + %d = %d\n", a, b, calculator.add(a, b));System.out.printf("%d - %d = %d\n", a, b, calculator.sub(a, b));System.out.printf("%d / %d = %d\n", b, a, calculator.div(b, a));System.out.printf("%d * %d = %d\n", a, b, calculator.mul(a, b)); }
-
最终,添加了@PrintExecutionTime的
add()
和div()
方法执行结束后将打印耗时
相关文章:

Google Guice 5:AOP
1. AOP 1.1 实际开发中面临的问题 在实际开发中,经常需要打印一个方法的执行时间,以确定是否存在慢操作 最简单的方法,直接修改已有的方法,在finnally语句中打印耗时 Override public Optional<Table> getTable(String da…...

【同步、共享和内容协作软件】上海道宁与ownCloud让您的团队随时随地在任何设备上轻松处理数据
ownCloud是 一款开源文件同步、共享和 内容协作软件 可让团队随时随地 在任何设备上轻松处理数据 ownCloud开发并提供 用于内容协作的开源软件 使团队能够轻松地无缝 共享和处理文件 而无需考虑设备或位置 开发商介绍 ownCloud成立于2010年,是一个托管和同…...
Linux 文件、目录与磁盘格式
用户与用户组 用户:即某个文件的拥有者,可以管理自己账号下的文件,另有一个超级账号 root,可以统一管理全局,利用 su root 命令登录该账号。用户组:相当于群组,多个用户之间可以组成用户组&…...
锁屏面试题百日百刷-Hive篇(五)
锁屏面试题百日百刷,每个工作日坚持更新面试题。锁屏面试题app、小程序现已上线,官网地址:https://www.demosoftware.cn。已收录了每日更新的面试题的所有内容,还包含特色的解锁屏幕复习面试题、每日编程题目邮件推送等功能。让你…...

java多线程(七)线程等待与唤醒
一、wait()、notify()、notifyAll()等方法介绍 在Object.java中,定义了wait(), notify()和notifyAll()等接口。wait()的作用是让当前线程进入等待状态,同时,wait()也会让当前线程释放它所持有的锁。而notify()和notifyAll()的作用࿰…...

第13天-仓储服务(仓库管理,采购管理 ,SPU规格维护)
1.仓储服务开发配置 1.1.加入到Nacos注册中心 spring:application:name: gmall-warecloud:nacos:discovery:server-addr: 192.168.139.10:8848namespace: 36854647-e68c-409b-9233-708a2d41702c1.2.配置网关路由 spring:cloud:gateway:routes:- id: ware_routeuri: lb://gmal…...
Maven 命令行及例子
基本 mvn -v - show-version -version 显示版本信息mvn -h - help 显示帮助信息mvn -e -errors控制 maven 的日志级别,产生执行错误相关消息mvn -q - quiet 控制 maven 的日志级别,仅仅显示错误mvn -o - offline 运行 offline 模式,不联网更…...

JavaScript手写题
一、防抖 function debounce(fn, delay200) {let timeout null; // 定时器控制return function(...args) {if (timeout) { // 定时器存在,表示某个动作之前触发过了clearTimeout(timeout); // 清除定时器timeout null;} else {// 对第一次输入立即执行fn.apply…...

为什么图标的宽度总是8的倍数?
对于 Windows 上的所有图标而言,它的宽度总是8的倍数,这可不是因为人们喜欢2的幂,虽然在计算机世界,你会看到很多这样的数字,例如,1024,4096等。 在 Windows 的早期阶段,大多数显卡…...

常用的xpath
一、xpath 语法 简单看一下菜鸟教程即可 1、基本语法 XPath 使用路径表达式在 XML 文档中选取节点。节点是通过沿着路径或者 step 来选取的。 下面列出了最有用的路径表达式: 表达式描述nodename选取此节点的所有子节点。/从根节点选取(取子节点&#…...

【035】基于java的进销库存管理系统(Vue+Springboot+Mysql)前后端分离项目,附万字课设论文
1.3 系统实现的功能 本次设计任务是要设计一个超市进销存系统,通过这个系统能够满足超市进销存系统的管理及员工的超市进销存管理功能。系统的主要功能包括:首页、个人中心、员工管理、客户管理、供应商管理、承运商管理、仓库信息管理、商品类别管理、 …...

【Spark分布式内存计算框架——Spark Streaming】7. Kafka集成方式
集成方式 Spark Streaming与Kafka集成,有两套API,原因在于Kafka Consumer API有两套, 文档:http://spark.apache.org/docs/2.4.5/streaming-kafka-integration.html。 方式一:Kafka 0.8.x版本 老的Old Kafka Consum…...
如何引入elementUI
elementUI的引入完整引入按需引入完整引入 在 main.js 中写入以下内容: import Vue from ‘vue’; import ElementUI from ‘element-ui’; import ‘element-ui/lib/theme-chalk/index.css’; import App from ‘./App.vue’; Vue.use(ElementUI); new Vue({ el: ‘…...

vue3+rust个人博客建站日记4-Vditor搞定MarkDown
即然是个人博客,那么绝对不能丢给自己一个大大的输入框敷衍了事。如果真是这样,现在就可以宣布项目到此结束了。如今没人享受用输入框写博客。作为一个有追求的程序员,作品就要紧跟潮流。 后来,Markdown 的崛起逐步改变了大家的排…...

KDZD-JC软化击穿试验仪
一、概 述 KDZD-JC智能软化击穿试验仪是根据GB/T4074.6-2008和idtIEC60851-6:2004标准而设计的一种新型漆包圆线检测仪器。主要适用于固体绝缘材料(如:塑料、橡胶、层压材料、薄膜、树脂、云母、陶瓷、玻璃、绝缘漆等绝缘材料及绝缘件)在工…...

【数据结构】单链表的C语言实现--万字详解介绍
📝个人主页:Sherry的成长之路 🏠学习社区:Sherry的成长之路(个人社区) 📖专栏链接:数据结构 🎯长路漫漫浩浩,万事皆有期待 文章目录1.链表1.1 链表的概念…...

电子科技大学软件工程期末复习笔记(七):测试策略
目录 前言 重点一览 V模型 回归测试 单元测试 集成测试 重要概念 自顶向下的集成方法 自底向上的集成方法 SMOKE方法 系统测试 验收测试 α测试 β测试 本章小结 前言 本复习笔记基于王玉林老师的课堂PPT与复习大纲,供自己期末复习与学弟学妹参考用…...

逆向-还原代码之除法 (Interl 64)
除法和32位差不多,毕竟背后的数学公式是一样的。区别只是32位的乘法需要两个寄存器来存放大数相乘的结果,而64位的不需要,一个寄存器就能存下。所以在64位的环境下,多了右移32位这条指令,其他指令一样。 //code #incl…...

Python WebDriver自动化测试
Webdriver Selenium 是 ThroughtWorks 一个强大的基于浏览器的开源自动化测试工具,它通常用来编写 Web 应用的自动化测试。 Selenium 2,又名 WebDriver,它的主要新功能是集成了 Selenium 1.0 以及 WebDriver(WebDriver 曾经是…...

2023年微信小程序获取手机号授权登录注册详细教程,包含服务端教程
前言 小程序中有很多地方都会用到用户的手机号,比如登陆注册,填写收货地址等等。有了这个组件可以快速获取微信绑定手机号码,无须用户填写。网上大多数教程还是往年的,而微信官方的api已做了修改。本篇文章将使用最新的方法获取手…...
<6>-MySQL表的增删查改
目录 一,create(创建表) 二,retrieve(查询表) 1,select列 2,where条件 三,update(更新表) 四,delete(删除表…...

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 执行具体的机器人操作或任务,直接与硬件、传感器或外部系统…...
大数据学习(132)-HIve数据分析
🍋🍋大数据学习🍋🍋 🔥系列专栏: 👑哲学语录: 用力所能及,改变世界。 💖如果觉得博主的文章还不错的话,请点赞👍收藏⭐️留言Ǵ…...

SAP学习笔记 - 开发26 - 前端Fiori开发 OData V2 和 V4 的差异 (Deepseek整理)
上一章用到了V2 的概念,其实 Fiori当中还有 V4,咱们这一章来总结一下 V2 和 V4。 SAP学习笔记 - 开发25 - 前端Fiori开发 Remote OData Service(使用远端Odata服务),代理中间件(ui5-middleware-simpleproxy)-CSDN博客…...

人工智能(大型语言模型 LLMs)对不同学科的影响以及由此产生的新学习方式
今天是关于AI如何在教学中增强学生的学习体验,我把重要信息标红了。人文学科的价值被低估了 ⬇️ 转型与必要性 人工智能正在深刻地改变教育,这并非炒作,而是已经发生的巨大变革。教育机构和教育者不能忽视它,试图简单地禁止学生使…...
C++.OpenGL (20/64)混合(Blending)
混合(Blending) 透明效果核心原理 #mermaid-svg-SWG0UzVfJms7Sm3e {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-SWG0UzVfJms7Sm3e .error-icon{fill:#552222;}#mermaid-svg-SWG0UzVfJms7Sm3e .error-text{fill…...

倒装芯片凸点成型工艺
UBM(Under Bump Metallization)与Bump(焊球)形成工艺流程。我们可以将整张流程图分为三大阶段来理解: 🔧 一、UBM(Under Bump Metallization)工艺流程(黄色区域ÿ…...

基于单片机的宠物屋智能系统设计与实现(论文+源码)
本设计基于单片机的宠物屋智能系统核心是实现对宠物生活环境及状态的智能管理。系统以单片机为中枢,连接红外测温传感器,可实时精准捕捉宠物体温变化,以便及时发现健康异常;水位检测传感器时刻监测饮用水余量,防止宠物…...
文件上传漏洞防御全攻略
要全面防范文件上传漏洞,需构建多层防御体系,结合技术验证、存储隔离与权限控制: 🔒 一、基础防护层 前端校验(仅辅助) 通过JavaScript限制文件后缀名(白名单)和大小,提…...