Spring--AOP案例以及使用介绍

2024-09-01 15:28

本文主要是介绍Spring--AOP案例以及使用介绍,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

AOP案例

1 案例-测量业务层接口万次执行效率

问题导入

能不能描述一下环绕通知里面的实现步骤?

1.1 需求和分析

需求:任意业务层接口执行均可显示其执行效率(执行时长)

分析:

​ ①:业务功能:业务层接口执行前后分别记录时间,求差值得到执行效率
​ ②:通知类型选择前后均可以增强的类型——环绕通知

1.2 代码实现
【前置工作】环境准备
  1. Spring整合mybatis对spring_db数据库中的Account进行CRUD操作
  2. Spring整合Junit测试CRUD是否OK。
  3. 在pom.xml中添加aspectjweaver切入点表达式依赖
  4. … …
【第一步】编写通知类
@Component
@Aspect
public class ProjectAdvice {//匹配业务层的所有方法@Pointcut("execution(* com.itheima.service.*Service.*(..))")private void servicePt(){}//设置环绕通知,在原始操作的运行前后记录执行时间@Around("ProjectAdvice.servicePt()") //本类类名可以省略不写public void runSpeed(ProceedingJoinPoint pjp) throws Throwable {//获取执行的签名对象Signature signature = pjp.getSignature();//获取接口/类全限定名String className = signature.getDeclaringTypeName();//获取方法名String methodName = signature.getName();//记录开始时间long start = System.currentTimeMillis();//执行万次操作for (int i = 0; i < 10000; i++) {pjp.proceed();}//记录结束时间long end = System.currentTimeMillis();//打印执行结果System.out.println("万次执行:"+ className+"."+methodName+"---->" +(end-start) + "ms");}
}
【第二步】在SpringConfig配置类上开启AOP注解功能
@Configuration
@ComponentScan("com.itheima")
@PropertySource("classpath:jdbc.properties")
@Import({JdbcConfig.class,MybatisConfig.class})
@EnableAspectJAutoProxy //开启AOP注解功能
public class SpringConfig {
}
【第三步】运行测试类,查看结果
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = SpringConfig.class)
public class AccountServiceTestCase {@Autowiredprivate AccountService accountService;@Testpublic void testFindById(){Account account = accountService.findById(2);}@Testpublic void testFindAll(){List<Account> list = accountService.findAll();}
}

2 AOP切入点数据获取

问题导入

在环绕通知中可以获取到哪些数据?

2.1 获取参数

说明:在前置通知和环绕通知中都可以获取到连接点方法的参数们

  • JoinPoint对象描述了连接点方法的运行状态,可以获取到原始方法的调用参数
@Before("pt()")
public void before(JoinPoint jp) {Object[] args = jp.getArgs(); //获取连接点方法的参数们System.out.println(Arrays.toString(args));
}
  • ProccedJointPoint是JoinPoint的子类
@Around("pt()")
public Object around(ProceedingJoinPoint pjp) throws Throwable {Object[] args = pjp.getArgs(); //获取连接点方法的参数们System.out.println(Arrays.toString(args));Object ret = pjp.proceed();return ret;
}
2.2 获取返回值

说明:在返回后通知和环绕通知中都可以获取到连接点方法的返回值

  • 返回后通知可以获取切入点方法返回值信息,使用形参可以接收对应的返回值
@AfterReturning(value = "pt()",returning = "ret")
public void afterReturning(String ret) { //变量名要和returning="ret"的属性值一致System.out.println("afterReturning advice ..."+ret);
}
  • 环绕通知中可以手工书写对原始方法的调用,得到的结果即为原始方法的返回值
@Around("pt()")
public Object around(ProceedingJoinPoint pjp) throws Throwable {// 手动调用连接点方法,返回值就是连接点方法的返回值Object ret = pjp.proceed();return ret;
}
2.3 获取异常

说明:在抛出异常后通知和环绕通知中都可以获取到连接点方法中出现的异常

  • 抛出异常后通知可以获取切入点方法中出现的异常信息,使用形参可以接收对应的异常对象
@AfterThrowing(value = "pt()",throwing = "t")
public void afterThrowing(Throwable t) {//变量名要和throwing = "t"的属性值一致System.out.println("afterThrowing advice ..."+ t);
}
  • 抛出异常后通知可以获取切入点方法运行的异常信息,使用形参可以接收运行时抛出的异常对象
@Around("pt()")
public Object around(ProceedingJoinPoint pjp)  {Object ret = null;//此处需要try...catch处理,catch中捕获到的异常就是连接点方法中抛出的异常try {ret = pjp.proceed();} catch (Throwable t) {t.printStackTrace();}return ret;
}

3 案例-百度网盘密码数据兼容处理

问题导入

请说出我们该使用什么类型的通知来完成这个需求?

3.1 需求和分析

需求:对百度网盘分享链接输入密码时尾部多输入的空格做兼容处理

分析:
①:在业务方法执行之前对所有的输入参数进行格式处理——trim()
②:使用处理后的参数调用原始方法——环绕通知中存在对原始方法的调用

3.2 代码实现
【前置工作】环境准备
//-------------service层代码-----------------------
public interface ResourcesService {public boolean openURL(String url ,String password);
}
@Service
public class ResourcesServiceImpl implements ResourcesService {@Autowiredprivate ResourcesDao resourcesDao;public boolean openURL(String url, String password) {return resourcesDao.readResources(url,password);}
}
//-------------dao层代码-----------------------
public interface ResourcesDao {boolean readResources(String url, String password);
}
@Repository
public class ResourcesDaoImpl implements ResourcesDao {public boolean readResources(String url, String password) {System.out.println(password.length());//模拟校验return password.equals("root");}
}
【第一步】编写通知类
@Component
@Aspect
public class DataAdvice {@Pointcut("execution(boolean com.itheima.service.*Service.*(*,*))")private void servicePt(){}@Around("DataAdvice.servicePt()")public Object trimStr(ProceedingJoinPoint pjp) throws Throwable {Object[] args = pjp.getArgs();for (int i = 0; i < args.length; i++) {//判断参数是不是字符串if(args[i].getClass().equals(String.class)){args[i] = args[i].toString().trim();}}Object ret = pjp.proceed(args);return ret;}
}
【第二步】在SpringConfig配置类上开启AOP注解功能
@Configuration
@ComponentScan("com.itheima")
@EnableAspectJAutoProxy
public class SpringConfig {
}
【第三步】运行测试类,查看结果
public class App {public static void main(String[] args) {ApplicationContext ctx = new AnnotationConfigApplicationContext(SpringConfig.class);ResourcesService resourcesService = ctx.getBean(ResourcesService.class);boolean flag = resourcesService.openURL("http://pan.baidu.com/haha", "root ");System.out.println(flag);}
}

4 AOP开发总结

4.1 AOP的核心概念
  • 概念:AOP(Aspect Oriented Programming)面向切面编程,一种编程范式
  • 作用:在不惊动原始设计的基础上为方法进行功能增强
  • 核心概念
    • 代理(Proxy):SpringAOP的核心本质是采用代理模式实现的
    • 连接点(JoinPoint): 在SpringAOP中,理解为任意方法的执行
    • 切入点(Pointcut):匹配连接点的式子,也是具有共性功能的方法描述
    • 通知(Advice):若干个方法的共性功能,在切入点处执行,最终体现为一个方法
    • 切面(Aspect):描述通知与切入点的对应关系
    • 目标对象(Target):被代理的原始对象成为目标对象
4.2 切入点表达式语法
  • 切入点表达式标准格式:动作关键字(访问修饰符 返回值 包名.类/接口名.方法名(参数)异常名)

    • execution(* com.itheima.service.Service.(…))
  • 切入点表达式描述通配符:

    • 作用:用于快速描述,范围描述
    • *:匹配任意符号(常用)
    • … :匹配多个连续的任意符号(常用)
    • +:匹配子类类型
  • 切入点表达式书写技巧

    1.按标准规范开发
    2.查询操作的返回值建议使用*匹配
    3.减少使用…的形式描述包
    4.对接口进行描述,使用*表示模块名,例如UserService的匹配描述为*Service
    5.方法名书写保留动词,例如get,使用*表示名词,例如getById匹配描述为getBy*
    6.参数根据实际情况灵活调整

4.3 五种通知类型
  • 前置通知
  • 后置通知
    • 环绕通知(重点)
    • 环绕通知依赖形参ProceedingJoinPoint才能实现对原始方法的调用
    • 环绕通知可以隔离原始方法的调用执行
    • 环绕通知返回值设置为Object类型
    • 环绕通知中可以对原始方法调用过程中出现的异常进行处理
  • 返回后通知
  • 抛出异常后通知

这篇关于Spring--AOP案例以及使用介绍的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1127318

相关文章

Linux下如何使用C++获取硬件信息

《Linux下如何使用C++获取硬件信息》这篇文章主要为大家详细介绍了如何使用C++实现获取CPU,主板,磁盘,BIOS信息等硬件信息,文中的示例代码讲解详细,感兴趣的小伙伴可以了解下... 目录方法获取CPU信息:读取"/proc/cpuinfo"文件获取磁盘信息:读取"/proc/diskstats"文

Java数组初始化的五种方式

《Java数组初始化的五种方式》数组是Java中最基础且常用的数据结构之一,其初始化方式多样且各具特点,本文详细讲解Java数组初始化的五种方式,分析其适用场景、优劣势对比及注意事项,帮助避免常见陷阱... 目录1. 静态初始化:简洁但固定代码示例核心特点适用场景注意事项2. 动态初始化:灵活但需手动管理代

Java使用SLF4J记录不同级别日志的示例详解

《Java使用SLF4J记录不同级别日志的示例详解》SLF4J是一个简单的日志门面,它允许在运行时选择不同的日志实现,这篇文章主要为大家详细介绍了如何使用SLF4J记录不同级别日志,感兴趣的可以了解下... 目录一、SLF4J简介二、添加依赖三、配置Logback四、记录不同级别的日志五、总结一、SLF4J

将Java项目提交到云服务器的流程步骤

《将Java项目提交到云服务器的流程步骤》所谓将项目提交到云服务器即将你的项目打成一个jar包然后提交到云服务器即可,因此我们需要准备服务器环境为:Linux+JDK+MariDB(MySQL)+Gi... 目录1. 安装 jdk1.1 查看 jdk 版本1.2 下载 jdk2. 安装 mariadb(my

使用Python实现一个优雅的异步定时器

《使用Python实现一个优雅的异步定时器》在Python中实现定时器功能是一个常见需求,尤其是在需要周期性执行任务的场景下,本文给大家介绍了基于asyncio和threading模块,可扩展的异步定... 目录需求背景代码1. 单例事件循环的实现2. 事件循环的运行与关闭3. 定时器核心逻辑4. 启动与停

如何使用Nginx配置将80端口重定向到443端口

《如何使用Nginx配置将80端口重定向到443端口》这篇文章主要为大家详细介绍了如何将Nginx配置为将HTTP(80端口)请求重定向到HTTPS(443端口),文中的示例代码讲解详细,有需要的小伙... 目录1. 创建或编辑Nginx配置文件2. 配置HTTP重定向到HTTPS3. 配置HTTPS服务器

SpringBoot中配置Redis连接池的完整指南

《SpringBoot中配置Redis连接池的完整指南》这篇文章主要为大家详细介绍了SpringBoot中配置Redis连接池的完整指南,文中的示例代码讲解详细,具有一定的借鉴价值,感兴趣的小伙伴可以... 目录一、添加依赖二、配置 Redis 连接池三、测试 Redis 操作四、完整示例代码(一)pom.

Java 正则表达式URL 匹配与源码全解析

《Java正则表达式URL匹配与源码全解析》在Web应用开发中,我们经常需要对URL进行格式验证,今天我们结合Java的Pattern和Matcher类,深入理解正则表达式在实际应用中... 目录1.正则表达式分解:2. 添加域名匹配 (2)3. 添加路径和查询参数匹配 (3) 4. 最终优化版本5.设计思

Java使用ANTLR4对Lua脚本语法校验详解

《Java使用ANTLR4对Lua脚本语法校验详解》ANTLR是一个强大的解析器生成器,用于读取、处理、执行或翻译结构化文本或二进制文件,下面就跟随小编一起看看Java如何使用ANTLR4对Lua脚本... 目录什么是ANTLR?第一个例子ANTLR4 的工作流程Lua脚本语法校验准备一个Lua Gramm

Java字符串操作技巧之语法、示例与应用场景分析

《Java字符串操作技巧之语法、示例与应用场景分析》在Java算法题和日常开发中,字符串处理是必备的核心技能,本文全面梳理Java中字符串的常用操作语法,结合代码示例、应用场景和避坑指南,可快速掌握字... 目录引言1. 基础操作1.1 创建字符串1.2 获取长度1.3 访问字符2. 字符串处理2.1 子字