Spring详解(七)----AspectJ 实现AOP

2024-08-29 13:08

本文主要是介绍Spring详解(七)----AspectJ 实现AOP,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

原文网址:https://www.cnblogs.com/ysocean/p/7507993.html

AspectJ 实现AOP
目录
1、什么是 AspectJ?
2、切入点表达式
2、Aspect 通知类型
3、AOP具体实例
4、测试异常通知
5、测试环绕通知


上一篇博客我们引出了 AOP 的概念,以及 AOP 的具体实现方式。但是为什么要这样实现?以及提出的切入点表达式到底该怎么理解?
  这篇博客我们通过对 AspectJ 框架的介绍来详细了解。

1、什么是 AspectJ?
  AspectJ是一个面向切面的框架,它扩展了Java语言。AspectJ定义了AOP语法,也可以说 AspectJ 是一个基于 Java 语言的 AOP 框架。通常我们在使用 Spring AOP 的时候,都会导入 AspectJ 的相关 jar 包。
在这里插入图片描述

在 spring2.0以后,spring新增了对AspectJ 切点表达式的支持;Aspect1.5新增注解功能,通过 JDK5的注解技术,能直接在类中定义切面;新版本的 spring 框架,也都建议使用 AspectJ 来实现 AOP。所以说在 spring AOP 的核心包 Spring-aop-3.2.jar 里面也有对 AspectJ 的支持。

2、切入点表达式
  上一篇博客中,我们在spring配置文件中配置如下:

<aop:pointcut expression=“execution(* com.ys.aop..(…))” id=“myPointCut”/>
  那么它表达的意思是 返回值任意,包名为 com.ys.aop 下的任意类名中的任意方法名,参数任意。那么这到底是什么意思呢?
  首先 execution 是 AspectJ 框架定义的一个切入点函数,其语法形式如下:
execution(modifiers-pattern? ref-type-pattern declaring-type-pattern? name-pattern(param-pattern) throws-pattern?)类修饰符 返回值 方法所在的包 方法名 方法抛出的异常
  简单点来说就是:
1 语法:execution(修饰符 返回值 包.类.方法名(参数) throws异常)
  具体解释我们用下面一张思维导图来看:
在这里插入图片描述

注意:如果切入点表达式有多个不同目录呢? 可以通过 || 来表示或的关系。  
<aop:pointcut expression=“execution(* com.ys.Service1.(…)) || execution(* com.ys.Service2.(…))” id=“myPointCut”/>
  表示匹配 com.ys包下的,以 Service1结尾或者以Service2结尾的类的任意方法。
  
  AOP 切入点表达式支持多种形式的定义规则:
1、execution:匹配方法的执行(常用)
execution(public .(…))
2.within:匹配包或子包中的方法(了解)
within(com.ys.aop…*)
3.this:匹配实现接口的代理对象中的方法(了解)
this(com.ys.aop.user.UserDAO)
4.target:匹配实现接口的目标对象中的方法(了解)
target(com.ys.aop.user.UserDAO)
5.args:匹配参数格式符合标准的方法(了解)
args(int,int)6.bean(id)
6对指定的bean所有的方法(了解)
bean(‘userServiceId’)

2、Aspect 通知类型
Aspect 通知类型,定义了类型名称以及方法格式。类型如下:
before:前置通知(应用:各种校验)
在方法执行前执行,如果通知抛出异常,阻止方法运行afterReturning:
后置通知(应用:常规数据处理)
方法正常返回后执行,如果方法中抛出异常,通知无法执行 必须在方法执行后才执行,所以可以获得方法的返回值。
around:环绕通知(应用:十分强大,可以做任何事情) 方法执行前后分别执行,可以阻止方法的执行 必须手动执行目标方法
afterThrowing:抛出异常通知(应用:包装异常信息) 方法抛出异常后执行,如果方法没有抛出异常,无法执行
after:最终通知(应用:清理现场) 方法执行完毕后执行,无论方法中是否出现异常
  这里最重要的是around,环绕通知,它可以代替上面的任意通知。
  在程序中表示的意思如下:
123456789 try{ //前置:before //手动执行目标方法 //后置:afterRetruning} catch(){ //抛出异常 afterThrowing} finally{ //最终 after}
  对应的 jar 包如下:
  在这里插入图片描述

我们可以查看源码:
  
在这里插入图片描述
在这里插入图片描述
3、AOP具体实例
  ①、创建接口
package com.ys.aop; public interface UserService {
//添加 user
public void addUser();
//删除 user
public void deleteUser();}
  ②、创建实现类
package com.ys.aop; public class UserServiceImpl implements UserService{
@Override
public void addUser() {
System.out.println(“增加 User”);
}
@Override
public void deleteUser() {
System.out.println(“删除 User”);
}
}
  ③、创建切面类(包含各种通知)  
package com.ys.aop; import org.aspectj.lang.JoinPoint; public class MyAspect {
/** * JoinPoint 能获取目标方法的一些基本信息

  • @param joinPoint
  • */
  • public void myBefore(JoinPoint joinPoint){
  • 	System.out.println("前置通知 : " + joinPoint.getSignature().getName());    
    
  • }
  • public void myAfterReturning(JoinPoint joinPoint,Object ret){
  • 	System.out.println("后置通知 : " + joinPoint.getSignature().getName() + " , -->" + ret);    
    
  • }
  • public void myAfter(){ System.out.println(“最终通知”);
  • }
    }
      ④、创建spring配置文件applicationContext.xml
      我们首先测试前置通知、后置通知、最终通知

aop:config <aop:aspect ref=“myAspect”>

<aop:pointcut expression=“execution(* com.ys.aop..(…))” id=“myPointCut”/>

<aop:before method="myBefore" pointcut-ref="myPointCut"/>                          
<!-- 3.2后置通知  ,目标方法后执行,获得返回值                
<aop:after-returning method="" pointcut-ref="" returning=""/>                   returning 通知方法第二个参数的名称                通知方法格式:public void myAfterReturning(JoinPoint joinPoint,Object ret){                    参数1:连接点描述                    参数2:类型Object,参数名 returning="ret" 配置的        -->        <aop:after-returning method="myAfterReturning" pointcut-ref="myPointCut" returning="ret" />                     <!-- 3.3 最终通知 -->                <aop:after method="myAfter" pointcut-ref="myPointCut"/>                       </aop:aspect>    </aop:config>
  ⑤、测试 @Test public void testAop(){ ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); UserService useService = (UserService) context.getBean("userService"); useService.addUser(); }   控制台打印:   ![在这里插入图片描述](https://img-blog.csdnimg.cn/20190802082245821.?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3UwMTMxMzE3MTY=,size_16,color_FFFFFF,t_70)

注意,后置通知的返回值为 null,是因为我们的目标方法 addUser() 没有返回值。如果有返回值,这里就是addUser() 的返回值。

4、测试异常通知
  目标接口保持不变,目标类我们手动引入异常:
public void addUser() {
int i = 1/0;
//显然这里会抛出除数不能为 0
System.out.println(“增加 User”);
}
  接着配置切面:MyAspect.java
public void myAfterThrowing(JoinPoint joinPoint,Throwable e){
System.out.println("抛出异常通知 : " + e.getMessage());
}
  接着在 applicationContext.xml 中配置如下:

<aop:after-throwing method=“myAfterThrowing” pointcut-ref=“myPointCut” throwing=“e”/>
  测试:
@Test
public void testAop(){
String str = “com/ys/execption/applicationContext.xml”;
ApplicationContext context = new ClassPathXmlApplicationContext(str);
UserService useService = (UserService) context.getBean(“userService”); useService.addUser();
}
  控制台打印:
  在这里插入图片描述

5、测试环绕通知
  目标接口和目标类保持不变,切面MyAspect 修改如下:
public class MyAspect {
public Object myAround(ProceedingJoinPoint joinPoint) throws Throwable{ System.out.println(“前置通知”);
//手动执行目标方法
Object obj = joinPoint.proceed();
System.out.println(“后置通知”);
return obj;
}
}
  applicationContext.xml 配置如下:

<aop:around method=“myAround” pointcut-ref=“myPointCut”/>
  测试:
@Test
public void testAop(){
String str = “com/ys/around/applicationContext.xml”;
ApplicationContext context = new ClassPathXmlApplicationContext(str);
UserService useService = (UserService) context.getBean(“userService”); useService.addUser();
}
  打印结果:
  在这里插入图片描述

那么至此,通过 xml 配置的方式我们讲解了Spring AOP 的配置。下一章将通过注解的方式来实现。

这篇关于Spring详解(七)----AspectJ 实现AOP的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



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

相关文章

JSON字符串转成java的Map对象详细步骤

《JSON字符串转成java的Map对象详细步骤》:本文主要介绍如何将JSON字符串转换为Java对象的步骤,包括定义Element类、使用Jackson库解析JSON和添加依赖,文中通过代码介绍... 目录步骤 1: 定义 Element 类步骤 2: 使用 Jackson 库解析 jsON步骤 3: 添

Java中注解与元数据示例详解

《Java中注解与元数据示例详解》Java注解和元数据是编程中重要的概念,用于描述程序元素的属性和用途,:本文主要介绍Java中注解与元数据的相关资料,文中通过代码介绍的非常详细,需要的朋友可以参... 目录一、引言二、元数据的概念2.1 定义2.2 作用三、Java 注解的基础3.1 注解的定义3.2 内

Java中使用Java Mail实现邮件服务功能示例

《Java中使用JavaMail实现邮件服务功能示例》:本文主要介绍Java中使用JavaMail实现邮件服务功能的相关资料,文章还提供了一个发送邮件的示例代码,包括创建参数类、邮件类和执行结... 目录前言一、历史背景二编程、pom依赖三、API说明(一)Session (会话)(二)Message编程客

Java中List转Map的几种具体实现方式和特点

《Java中List转Map的几种具体实现方式和特点》:本文主要介绍几种常用的List转Map的方式,包括使用for循环遍历、Java8StreamAPI、ApacheCommonsCollect... 目录前言1、使用for循环遍历:2、Java8 Stream API:3、Apache Commons

JavaScript中的isTrusted属性及其应用场景详解

《JavaScript中的isTrusted属性及其应用场景详解》在现代Web开发中,JavaScript是构建交互式应用的核心语言,随着前端技术的不断发展,开发者需要处理越来越多的复杂场景,例如事件... 目录引言一、问题背景二、isTrusted 属性的来源与作用1. isTrusted 的定义2. 为

C#提取PDF表单数据的实现流程

《C#提取PDF表单数据的实现流程》PDF表单是一种常见的数据收集工具,广泛应用于调查问卷、业务合同等场景,凭借出色的跨平台兼容性和标准化特点,PDF表单在各行各业中得到了广泛应用,本文将探讨如何使用... 目录引言使用工具C# 提取多个PDF表单域的数据C# 提取特定PDF表单域的数据引言PDF表单是一

使用Python实现高效的端口扫描器

《使用Python实现高效的端口扫描器》在网络安全领域,端口扫描是一项基本而重要的技能,通过端口扫描,可以发现目标主机上开放的服务和端口,这对于安全评估、渗透测试等有着不可忽视的作用,本文将介绍如何使... 目录1. 端口扫描的基本原理2. 使用python实现端口扫描2.1 安装必要的库2.2 编写端口扫

Java循环创建对象内存溢出的解决方法

《Java循环创建对象内存溢出的解决方法》在Java中,如果在循环中不当地创建大量对象而不及时释放内存,很容易导致内存溢出(OutOfMemoryError),所以本文给大家介绍了Java循环创建对象... 目录问题1. 解决方案2. 示例代码2.1 原始版本(可能导致内存溢出)2.2 修改后的版本问题在

PyCharm接入DeepSeek实现AI编程的操作流程

《PyCharm接入DeepSeek实现AI编程的操作流程》DeepSeek是一家专注于人工智能技术研发的公司,致力于开发高性能、低成本的AI模型,接下来,我们把DeepSeek接入到PyCharm中... 目录引言效果演示创建API key在PyCharm中下载Continue插件配置Continue引言

MySQL分表自动化创建的实现方案

《MySQL分表自动化创建的实现方案》在数据库应用场景中,随着数据量的不断增长,单表存储数据可能会面临性能瓶颈,例如查询、插入、更新等操作的效率会逐渐降低,分表是一种有效的优化策略,它将数据分散存储在... 目录一、项目目的二、实现过程(一)mysql 事件调度器结合存储过程方式1. 开启事件调度器2. 创