当前位置: 首页 > news >正文

Java Spring AOP代码3分钟快速入手

AOP

Spring入门(十):Spring AOP使用讲解 - 掘金

maven的依赖:

<dependency><groupId>org.springframework</groupId><artifactId>spring-aop</artifactId>
</dependency>
<!--aspectj支持-->
<dependency><groupId>org.aspectj</groupId><artifactId>aspectjrt</artifactId>
</dependency>
<dependency><groupId>org.aspectj</groupId><artifactId>aspectjweaver</artifactId>
</dependency>

demo1

基于注解实现

AopAnnotation:

package com.example.learn.aop;import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;@Target({ ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
public @interface AopAnnotation {
}

TestAspect:

package com.example.learn.aop;import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;@Aspect
@Component
@Slf4j
public class TestAspect {@Pointcut("@annotation(com.example.learn.aop.AopAnnotation)")private void cut() {}@Around("cut()")public Object around(ProceedingJoinPoint joinPoint) throws Throwable {log.info("====环绕通知start");// 注解所切的方法所在类的全类名String typeName = joinPoint.getTarget().getClass().getName();log.info("目标对象:[{}]", typeName);// 注解所切的方法名String methodName = joinPoint.getSignature().getName();log.info("所切方法名:[{}]", methodName);StringBuilder sb = new StringBuilder();// 获取参数Object[] arguments = joinPoint.getArgs();for (Object argument : arguments) {sb.append(argument.toString());}log.info("所切方法入参:[{}]", sb.toString());// 统计方法执行时间long start = System.currentTimeMillis();//执行目标方法,并获得对应方法的返回值Object result = joinPoint.proceed();log.info("返回结果:[{}]", result);long end = System.currentTimeMillis();log.info("====执行方法共用时:[{}]", (end - start));log.info("====环绕通知之结束");return result;}}

实现一个被织入的类,注意这个类得是Bean,一般aop都是针对容器的,针对普通类的很少且不常用:

AopClass:

package com.example.learn.aop;import org.springframework.stereotype.Component;@Component
public class AopClass {@AopAnnotationpublic void testAop() {System.out.println("func invoked!");}
}

测试:

正是因为AOP是针对Bean的,因此测试的时候不要像下面这样去测试,因为new出来的这个对象没有被Spring管理:

@SpringBootTest
class LearnApplicationTests {@Testvoid contextLoads() {AopClass aopClass = new AopClass();aopClass.testAop();}}

憨憨行为。应该注入容器来测试:

@SpringBootTest
class LearnApplicationTests {@Autowiredprivate AopClass aopClass;@Testvoid contextLoads() {aopClass.testAop();}}

打印结果:

.   ____          _            __ _ _/\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \\\/  ___)| |_)| | | | | || (_| |  ) ) ) )'  |____| .__|_| |_|_| |_\__, | / / / /=========|_|==============|___/=/_/_/_/:: Spring Boot ::                (v2.5.5)2023-10-27 10:56:13.600  INFO 16048 --- [           main] com.example.learn.LearnApplicationTests  : Starting LearnApplicationTests using Java 1.8.0_381 on DESKTOP-NFN5QCN with PID 16048 (started by DELL in F:\OneDrive\Java学习\yunfei\learn)
2023-10-27 10:56:13.604  INFO 16048 --- [           main] com.example.learn.LearnApplicationTests  : No active profile set, falling back to default profiles: default
2023-10-27 10:56:15.202  INFO 16048 --- [           main] com.example.learn.LearnApplicationTests  : Started LearnApplicationTests in 1.916 seconds (JVM running for 2.886)
2023-10-27 10:56:15.408  INFO 16048 --- [           main] com.example.learn.aop.TestAspect         : ====环绕通知start
2023-10-27 10:56:15.408  INFO 16048 --- [           main] com.example.learn.aop.TestAspect         : 目标对象:[com.example.learn.aop.AopClass]
2023-10-27 10:56:15.410  INFO 16048 --- [           main] com.example.learn.aop.TestAspect         : 所切方法名:[testAop]
2023-10-27 10:56:15.410  INFO 16048 --- [           main] com.example.learn.aop.TestAspect         : 所切方法入参:[]
func invoked!
2023-10-27 10:56:15.420  INFO 16048 --- [           main] com.example.learn.aop.TestAspect         : 返回结果:[null]
2023-10-27 10:56:15.420  INFO 16048 --- [           main] com.example.learn.aop.TestAspect         : ====执行方法共用时:[10]
2023-10-27 10:56:15.420  INFO 16048 --- [           main] com.example.learn.aop.TestAspect         : ====环绕通知之结束

demo2

写一个切面类:

package com.example.base.aop;import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;@Aspect
public class Detector {@Pointcut("execution(* com.example.base.AopController.hello(..))")public void helloAspect() {}@Before("helloAspect()")public void beforeAction() {System.out.println("before hello~");}@After("helloAspect()")public void afterAction() {System.out.println("after hello~");}@AfterReturning("helloAspect()")public void afterReturningAction() {System.out.println("after return~");}@Around("helloAspect()")public Object aroundAction(ProceedingJoinPoint pjp) throws Throwable {System.out.println("around~");pjp.proceed();System.out.println("around~");return null;}
}

切点为Controller的一个方法:

package com.example.base;import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;@RestController
public class AopController {@GetMapping("/hello")public String hello(@RequestParam("id") int userId) {return null;}
}

写切面的配置类,自动加载切面:

package com.example.base.aop;import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;@Configuration
@EnableAspectJAutoProxy
@ComponentScan
public class Config {@Beanpublic Detector detector() {return new Detector();}
}

启动项目,浏览器http://localhost:8080/hello?id=1 触发打印:

2023-09-06 15:49:32.974  INFO 198380 --- [nio-8080-exec-1] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring DispatcherServlet 'dispatcherServlet'
2023-09-06 15:49:32.974  INFO 198380 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet        : Initializing Servlet 'dispatcherServlet'
2023-09-06 15:49:32.975  INFO 198380 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet        : Completed initialization in 1 ms
around~
before hello~
after return~
after hello~
around~
Disconnected from the target VM, address: '127.0.0.1:61026', transport: 'socket'

相关文章:

Java Spring AOP代码3分钟快速入手

AOP Spring入门(十)&#xff1a;Spring AOP使用讲解 - 掘金 maven的依赖&#xff1a; <dependency><groupId>org.springframework</groupId><artifactId>spring-aop</artifactId> </dependency> <!--aspectj支持--> <dependen…...

.NET开源快速、强大、免费的电子表格组件

今天大姚给大家分享一个.NET开源&#xff08;MIT License&#xff09;、快速、强大、免费的电子表格组件&#xff0c;支持数据格式、冻结、大纲、公式计算、图表、脚本执行等。兼容 Excel 2007 (.xlsx) 格式&#xff0c;支持WinForm、WPF和Android平台&#xff1a;ReoGrid。 项…...

docker一键部署若依前后端分离版本

比如这里把文件放到/xin/docker/jiaoZ/的目录下&#xff0c;jar包和下面的配置文件都放在这个文件夹下。 注意要把jar端口改为你实际启动的&#xff0c;映射端口也可以改为你想要的。 这里的映射端口为&#xff1a;nginx监听80端口&#xff0c;jar在8620端口&#xff0c;mysq…...

Java项目开发之fastjson详解

Fastjson 是由阿里巴巴公司开发的一个 Java 语言编写的高性能 JSON 处理库。它主要用于 Java 对象与 JSON 数据格式之间的转换&#xff0c;提供了简单易用的 API 来实现序列化&#xff08;Java 对象转 JSON 字符串&#xff09;和反序列化&#xff08;JSON 字符串转 Java 对象&a…...

面试算法-62-盛最多水的容器

题目 给定一个长度为 n 的整数数组 height 。有 n 条垂线&#xff0c;第 i 条线的两个端点是 (i, 0) 和 (i, height[i]) 。 找出其中的两条线&#xff0c;使得它们与 x 轴共同构成的容器可以容纳最多的水。 返回容器可以储存的最大水量。 说明&#xff1a;你不能倾斜容器。…...

【智能算法】海洋捕食者算法(MPA)原理及实现

目录 1.背景2.算法原理2.1算法思想2.2算法过程 3.结果展示4.参考文献 1.背景 2020年&#xff0c;Afshin Faramarzi 等人受到海洋生物适者生存启发&#xff0c;提出了海洋捕食者算法(Marine Predators Algorithm&#xff0c;MPA)。 2.算法原理 2.1算法思想 MPA根据模拟自然界…...

刷题DAY24 | LeetCode 77-组合

1 回溯法理论基础 回溯法也可以叫做回溯搜索法&#xff0c;它是一种搜索的方式。回溯是递归的副产品&#xff0c;只要有递归就会有回溯。 所以以下讲解中&#xff0c;回溯函数也就是递归函数&#xff0c;指的都是一个函数。 1.1 回溯法的效率 回溯法的性能如何呢&#xff0…...

Spring Boot为什么默认使用CGLIB动态代理

兼容性&#xff1a; 1. CGLIB 动态代理可以代理任何类型的目标类&#xff0c;无论它是否实现了接口&#xff1b;&#xff3b;注意的是&#xff0c;类被 final 修饰&#xff0c;那么该不可被继承&#xff0c;即不可被代理&#xff1b;同样&#xff0c;类中 final 修饰的方法&am…...

算法详解——Dijkstra算法

Dijkstra算法的目的是寻找单起点最短路径&#xff0c;其策略是贪心加非负加权队列 一、单起点最短路径问题 单起点最短路径问题&#xff1a;给定一个加权连通图中的特定起点&#xff0c;目标是找出从该起点到图中所有其他顶点的最短路径集合。需要明确的是&#xff0c;这里关心…...

利用GANs进行图像生成

生成对抗网络&#xff08;GANs&#xff09;是一种深度学习模型&#xff0c;由两部分组成&#xff1a;生成器&#xff08;Generator&#xff09;和判别器&#xff08;Discriminator&#xff09;。它们通过相互竞争来提高生成器生成高质量图像的能力。以下是如何利用GANs进行图像…...

Flutter-底部弹出框(Widget层级)

需求 支持底部弹出对话框。支持手势滑动关闭。支持在widget中嵌入引用。支持底部弹出框弹出后不影响其他操作。支持弹出框中内容固定头部和下面列表时&#xff0c;支持触摸头部并在列表不在头部的时候支持滑动关闭 简述 通过上面的需求可知&#xff0c;就是在界面中可以支持…...

聚焦两会:数字化再加速,VR全景助力制造业转型

近年来&#xff0c;随着信息技术、人工智能、VR虚拟现实等新兴技术的不断涌现&#xff0c;数字化正日益成为推动当今经济发展的新驱动力。在不久前的两会上&#xff0c;数字化经济和创新技术再度成为热门话题&#xff1a; 国务院总理李强作政府工作报告&#xff1a; 要深入推…...

数据挖掘之关联规则

“啤酒和尿布的荣誉” 概念 项 item&#xff1a;单个的事物个体 &#xff0c;I{i1,i2…im}是所有项的集合&#xff0c;|I|m是项的总数项集&#xff08;item set)/模式&#xff08;pattern)&#xff1a;项的集合&#xff0c;包含k个项的项集称为k-项集数据集(data set)/数据库…...

java:java.util.BitSet对象的Jackson序列化和反序列化实现

java.util.BitSet是个非常方便的比特位数据存储和操作类&#xff0c;一个 bit 具有2个值&#xff1a;0和1&#xff0c;正好可以用来表示 false 和 true&#xff0c;适用于判断“数据是否存在”的场景。 但是&#xff0c;这个从JDK1.0版本就存在的类&#xff0c;Jackson,Fastjso…...

Go语言学习01-基本程序结构

文章目录 Go语言学习01-基本程序结构基本程序结构应用程序入口退出返回值编写测试程序快速设置连续值基本数据类型类型的预定义值指针类型运算符算数运算符比较运算符用 比较数组 逻辑运算符位运算符&^ 按位 置零 Go语言学习01-基本程序结构 基本程序结构 package main …...

rundeck k8s部署踩坑

1、镜像启动后原来的定时任务无法运行 参考&#xff1a; https://github.com/rundeck/rundeck/issues/4275 https://stackoverflow.com/questions/60942785/env-variable-for-rundeck-feature-joblifecycleplugin-enabled/60959605#60959605 结论&#xff1a; &#xff08;1&…...

每天学习几道面试题|Kafka(二)架构设计类

文章目录 1. Kafka 是如何保证高可用性和容错性的&#xff1f;2. Kafka 的存储机制是怎样的&#xff1f;它是如何处理大量数据的&#xff1f;3. Kafka 如何处理消费者的消费速率低于生产者的生产速率&#xff1f;4. Kafka 集群中的 Controller 是什么&#xff1f;它的作用是什么…...

Spring 实现 OAuth2 授权之解决方案

Spring Security OAuth2 - 已经废弃的项目 早期的Spring 使用 Spring Security OAuth2 实现 OAuth 2.0 的认证服务器和资源服务器。OAuth2是一个授权框架,它允许第三方应用获取有限的访问权限,而无需获取用户的账号和密码等敏感信息。通过这种方式,OAuth2协议实现了安全的用…...

el-select使用filterable下拉无法关闭得问题

这里推荐一个前端框架 sakuya / SCUI&#xff0c;他里面有个formTable&#xff0c;可以解决很多订单明细保存得问题。基本沿用element-plus的前端使用模式&#xff0c;让表单表格变的非常容易。 这个的供应商插件&#xff0c;当使用filterable后&#xff0c;点击表格重的选项&…...

基于javaweb(springboot)城市地名地址信息管理系统设计和实现

基于javaweb(springboot)城市地名地址信息管理系统设计和实现 博主介绍&#xff1a;多年java开发经验&#xff0c;专注Java开发、定制、远程、文档编写指导等,csdn特邀作者、专注于Java技术领域 作者主页 央顺技术团队 Java毕设项目精品实战案例《1000套》 欢迎点赞 收藏 ⭐留言…...

基于Arduino与应变片传感器的高精度厨房电子秤DIY全攻略

1. 项目概述&#xff1a;用Arduino打造一台高精度厨房电子秤作为一个喜欢在厨房里折腾的硬件爱好者&#xff0c;我经常遇到需要精确称量食材的场合。市面上的电子秤要么精度不够&#xff0c;要么价格不菲&#xff0c;要么功能单一。于是&#xff0c;我萌生了自己动手做一台的想…...

【DeepSeek开源协议识别权威指南】:20年合规专家亲授3大协议陷阱与5步精准识别法

更多请点击&#xff1a; https://intelliparadigm.com 第一章&#xff1a;DeepSeek开源协议识别的底层逻辑与合规价值 DeepSeek系列模型&#xff08;如DeepSeek-V2、DeepSeek-Coder&#xff09;虽以“开源”名义发布&#xff0c;但其实际许可状态需通过结构化协议解析才能准确…...

碧蓝航线自动化脚本终极指南:3小时学会全自动游戏管理

碧蓝航线自动化脚本终极指南&#xff1a;3小时学会全自动游戏管理 【免费下载链接】AzurLaneAutoScript Azur Lane bot (CN/EN/JP/TW) 碧蓝航线脚本 | 无缝委托科研&#xff0c;全自动大世界 项目地址: https://gitcode.com/gh_mirrors/az/AzurLaneAutoScript 还在为碧蓝…...

举一个具体例子说明为什么索引不是越多越好,举具体字段

文章目录1. 核心舞台&#xff1a;笔记表 (t_note) 结构设计&#x1f6a8; 错误的操作&#xff1a;2. 结合具体字段&#xff0c;拆解三大翻车现场现场一&#xff1a;给 view_count&#xff08;浏览量&#xff09;加索引 —— 导致写放大&#xff0c;拖垮数据库现场二&#xff1a…...

YOLOv8晶圆体缺识别检测系统(项目源码+YOLO数据集+模型权重+UI界面+python+深度学习+环境配置)

摘要 晶圆制造过程中的缺陷检测是保证芯片良率的关键环节。本文基于YOLOv8目标检测算法&#xff0c;构建了一套针对晶圆表面9类典型缺陷的自动检测系统。所识别的缺陷类型包括&#xff1a;Center、Donut、Edge-Loc、Edge-Ring、Loc、Near-full、None、Random、Scratch。模型在…...

终极Node.js Mock工具:Mockery入门到精通实战教程

终极Node.js Mock工具&#xff1a;Mockery入门到精通实战教程 【免费下载链接】mockery Simplifying the use of mocks with Node.js 项目地址: https://gitcode.com/gh_mirrors/mock/mockery Mockery是Node.js生态中简化Mock使用的终极工具&#xff0c;它为开发者提供了…...

告别杂乱!用FileMenu Tools 8.4.2一键清理Windows 11右键菜单(附隐藏技巧)

Windows 11右键菜单精简指南&#xff1a;用FileMenu Tools打造高效工作流每次在文件上点击右键时&#xff0c;那个缓慢弹出的冗长菜单是否让你感到烦躁&#xff1f;随着安装的软件越来越多&#xff0c;Windows的右键菜单往往会变得臃肿不堪&#xff0c;严重影响工作效率。今天&…...

AI算法工程师如何进行模型部署?这2个工具+3个技巧,快速上线

对于软件测试从业者来说&#xff0c;模型部署并不是一个陌生的概念——随着AI功能逐渐渗透到各类应用软件中&#xff0c;测试工程师不仅需要验证模型输出的准确性&#xff0c;更需要理解部署流程对模型稳定性、响应速度和结果一致性的影响。很多测试同学会有这样的困惑&#xf…...

在数据预处理与分析流水线中集成大模型API进行智能标注与摘要

&#x1f680; 告别海外账号与网络限制&#xff01;稳定直连全球优质大模型&#xff0c;限时半价接入中。 &#x1f449; 点击领取海量免费额度 在数据预处理与分析流水线中集成大模型API进行智能标注与摘要 对于数据工程师而言&#xff0c;处理海量非结构化文本数据是一项常见…...

为什么你的Midjourney雾效总像“水汽”而非“山岚”?——资深CG总监拆解大气散射物理模型在--v 6.1中的3层映射偏差

更多请点击&#xff1a; https://kaifayun.com 第一章&#xff1a;为什么你的Midjourney雾效总像“水汽”而非“山岚”&#xff1f; Midjourney 生成的雾气常呈现为均匀、半透明、边界模糊的“水汽感”——厚重、潮湿、缺乏层次与呼吸感。这并非模型能力不足&#xff0c;而是提…...