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

相关文章

Java中流式并行操作parallelStream的原理和使用方法

《Java中流式并行操作parallelStream的原理和使用方法》本文详细介绍了Java中的并行流(parallelStream)的原理、正确使用方法以及在实际业务中的应用案例,并指出在使用并行流... 目录Java中流式并行操作parallelStream0. 问题的产生1. 什么是parallelS

MySQL数据库双机热备的配置方法详解

《MySQL数据库双机热备的配置方法详解》在企业级应用中,数据库的高可用性和数据的安全性是至关重要的,MySQL作为最流行的开源关系型数据库管理系统之一,提供了多种方式来实现高可用性,其中双机热备(M... 目录1. 环境准备1.1 安装mysql1.2 配置MySQL1.2.1 主服务器配置1.2.2 从

C++中unordered_set哈希集合的实现

《C++中unordered_set哈希集合的实现》std::unordered_set是C++标准库中的无序关联容器,基于哈希表实现,具有元素唯一性和无序性特点,本文就来详细的介绍一下unorder... 目录一、概述二、头文件与命名空间三、常用方法与示例1. 构造与析构2. 迭代器与遍历3. 容量相关4

Java中Redisson 的原理深度解析

《Java中Redisson的原理深度解析》Redisson是一个高性能的Redis客户端,它通过将Redis数据结构映射为Java对象和分布式对象,实现了在Java应用中方便地使用Redis,本文... 目录前言一、核心设计理念二、核心架构与通信层1. 基于 Netty 的异步非阻塞通信2. 编解码器三、

C++中悬垂引用(Dangling Reference) 的实现

《C++中悬垂引用(DanglingReference)的实现》C++中的悬垂引用指引用绑定的对象被销毁后引用仍存在的情况,会导致访问无效内存,下面就来详细的介绍一下产生的原因以及如何避免,感兴趣... 目录悬垂引用的产生原因1. 引用绑定到局部变量,变量超出作用域后销毁2. 引用绑定到动态分配的对象,对象

Linux kill正在执行的后台任务 kill进程组使用详解

《Linuxkill正在执行的后台任务kill进程组使用详解》文章介绍了两个脚本的功能和区别,以及执行这些脚本时遇到的进程管理问题,通过查看进程树、使用`kill`命令和`lsof`命令,分析了子... 目录零. 用到的命令一. 待执行的脚本二. 执行含子进程的脚本,并kill2.1 进程查看2.2 遇到的

MyBatis常用XML语法详解

《MyBatis常用XML语法详解》文章介绍了MyBatis常用XML语法,包括结果映射、查询语句、插入语句、更新语句、删除语句、动态SQL标签以及ehcache.xml文件的使用,感兴趣的朋友跟随小... 目录1、定义结果映射2、查询语句3、插入语句4、更新语句5、删除语句6、动态 SQL 标签7、ehc

SpringBoot基于注解实现数据库字段回填的完整方案

《SpringBoot基于注解实现数据库字段回填的完整方案》这篇文章主要为大家详细介绍了SpringBoot如何基于注解实现数据库字段回填的相关方法,文中的示例代码讲解详细,感兴趣的小伙伴可以了解... 目录数据库表pom.XMLRelationFieldRelationFieldMapping基础的一些代

一篇文章彻底搞懂macOS如何决定java环境

《一篇文章彻底搞懂macOS如何决定java环境》MacOS作为一个功能强大的操作系统,为开发者提供了丰富的开发工具和框架,下面:本文主要介绍macOS如何决定java环境的相关资料,文中通过代码... 目录方法一:使用 which命令方法二:使用 Java_home工具(Apple 官方推荐)那问题来了,

Java HashMap的底层实现原理深度解析

《JavaHashMap的底层实现原理深度解析》HashMap基于数组+链表+红黑树结构,通过哈希算法和扩容机制优化性能,负载因子与树化阈值平衡效率,是Java开发必备的高效数据结构,本文给大家介绍... 目录一、概述:HashMap的宏观结构二、核心数据结构解析1. 数组(桶数组)2. 链表节点(Node