目录
一、Spring AOP简介
二、AOP相关术语
三、AOP入门案例
1. 引入依赖
2. 编写连接点
3. 编写通知类
4. 配置切面
5. 测试
四、通知类型
1. 编写通知方法
2. 配置切面
3. 测试
五、切点表达式
六、多切面配置
1. 编写发送邮件的通知
2. 配置切面
3. 测试
往期专栏&文章相关导读
1. Maven系列专栏文章
2. Mybatis系列专栏文章
3. Spring系列专栏文章
一、Spring AOP简介
AOP的全称是Aspect Oriented Programming,即面向切面编程。是实现功能统一维护的一种技术,它将业务逻辑的各个部分进行隔离,使开发人员在编写业务逻辑时可以专心于核心业务,从而提高了开发效率。
- 作用:在不修改源码的基础上,对已有方法进行增强。实现原理:动态代理技术。
- 优势:减少重复代码、提高开发效率、维护方便
- 应用场景:事务处理、日志管理、权限控制、异常处理等方面。
二、AOP相关术语
为了更好地理解AOP,就需要对AOP的相关术语有一些了解
名称 | 说明 |
Joinpoint(连接点) | 指能被拦截到的点,在Spring中只有方法能被拦截。 |
Pointcut(切点) | 指要对哪些连接点进行拦截,即被增强的方法。 |
Advice(通知) | 指拦截后要做的事情,即切点被拦截后执行的方法。 |
Aspect(切面) | 切点+通知称为切面 |
Target(目标) | 被代理的对象 |
Proxy(代理) | 代理对象 |
Weaving(织入) | 生成代理对象的过程 |
三、AOP入门案例
AspectJ是一个基于Java语言的AOP框架,在Spring框架中建议使用AspectJ实现AOP。
接下来我们写一个AOP入门案例:dao层的每个方法结束后都可以打印一条日志:
1. 引入依赖
<dependencies><dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>5.3.13</version></dependency><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.12</version><scope>test</scope></dependency><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>8.0.27</version></dependency></dependencies>
2. 编写连接点
package com.example.dao;import org.springframework.stereotype.Repository;@Repository
public class UserDao {public void add(){System.out.println("用户新增");}public void delete(){System.out.println("用户删除");}public void update(){System.out.println("用户修改");}
}
3. 编写通知类
package com.example.aspect;import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;public class MyAspectJAdvice {// 后置通知public void myAfterReturning(JoinPoint joinPoint){System.out.println("切点方法名:"+joinPoint.getSignature().getName());System.out.println("目标对象:"+joinPoint.getTarget());System.out.println("打印日志···"+joinPoint.getSignature().getName()+"方法被执行了!"); }
}
4. 配置切面
bean.xml文件
<?xml version="1.0" encoding="UTF-8"?>
<beansxmlns="http://www.springframework.org/schema/beans"xmlns:context="http://www.springframework.org/schema/context"xmlns:aop="http://www.springframework.org/schema/aop"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context.xsdhttp://www.springframework.org/schema/aophttp://www.springframework.org/schema/aop/spring-aop.xsd"><!-- 扫描包 --><context:component-scan base-package="com.example"/><!-- 通知对象 --><bean id="myAspectJAdvice" class="com.example.aspect.MyAspectJAdvice"/><!-- 配置AOP --><aop:config><!-- 配置切面 --><aop:aspect ref="myAspectJAdvice"><!-- 配置切点 --><aop:pointcut id="myPointcut" expression="execution(* com.example.dao.UserDao.* (..))"/><!-- 配置后置通知 --><aop:after-returning method="myAfterReturning" pointcut-ref="myPointcut"/></aop:aspect></aop:config></beans>
5. 测试
import com.example.SpringConfig;
import com.example.dao.UserDao;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;public class UserDaoTest {@Testpublic void testAdd(){ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");UserDao userDao = (UserDao) ac.getBean("userDao");userDao.add();}@Testpublic void testDelete(){ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");UserDao userDao = (UserDao) ac.getBean("userDao");userDao.delete();}
}
运行结果分别为
OK,确实是可以的,本次入门案例就学习到这里了。
四、通知类型
AOP有以下几种常用的通知类型:
通知类型 | 描述 |
---|---|
前置通知 | 在方法执行前添加功能 |
后置通知 | 在方法正常执行后添加功能 |
异常通知 | 在方法抛出异常后添加功能 |
最终通知 | 无论方法是否抛出异常,都会执行该通知 |
环绕通知 | 在方法执行前后添加功能 |
1. 编写通知方法
// 前置通知public void myBefore(){System.out.println("前置通知···");}// 异常通知public void myAfterThrowing(Exception e){System.out.println("异常通知···");System.out.println(e.getMessage());}// 最终通知public void myAfter(){System.out.println("最终通知···");}// 环绕通知public Object myAround(ProceedingJoinPoint point) throws Throwable {System.out.println("环绕前···");// 执行方法Object obj = point.proceed();System.out.println("环绕后···");return obj;}
2. 配置切面
<!-- 配置AOP --><aop:config><!-- 配置切面 --><aop:aspect ref="myAspectJAdvice"><!-- 配置切点 --><aop:pointcut id="myPointcut" expression="execution(* com.example.dao.UserDao.* (..))"/><!-- 配置后置通知 --><aop:after-returning method="myAfterReturning" pointcut-ref="myPointcut"/><!-- 前置通知 --><aop:before method="myBefore" pointcut-ref="myPointcut"/><!-- 异常通知 --><aop:after-throwing method="myAfterThrowing" pointcut-ref="myPointcut" throwing="e"/><!-- 最终通知 --><aop:after method="myAfter" pointcut-ref="myPointcut"/><!-- 环绕通知 --><aop:around method="myAround" pointcut-ref="myPointcut"/></aop:aspect></aop:config>
3. 测试
OK,这里我们测试用户新增方法 ,确实是得出来我们想要的结果了
五、切点表达式
切点表达式:访问修饰符 返回值 包名.类名.方法名(参数列表)
- 使用AspectJ需要使用切点表达式配置切点位置,写法如下:
- 标准写法:访问修饰符 返回值 包名.类名.方法名(参数列表)
- 访问修饰符可以省略。
- 返回值使用 * 代表任意类型。
- 包名使用 * 表示任意包,多级包结构要写多个 * ,使用 *.. 表示任意包结构
- 类名和方法名都可以用 * 实现通配。
参数列表
- 基本数据类型直接写类型
- 引用类型写 包名.类名
- * 表示匹配一个任意类型参数
- .. 表示匹配任意类型任意个数的参数
全通配: * *..*.*(..)
六、多切面配置
我们可以为切点配置多个通知,形成多切面,比如希望dao层的每个方法结束后都可以打印日志并发送邮件:
1. 编写发送邮件的通知
package com.example.aspect;import org.aspectj.lang.JoinPoint;public class MyAspectJAdvice2 {// 后置通知public void myAfterReturning(JoinPoint point){System.out.println("发送邮件···");}
}
2. 配置切面
在上面的基础上配置多一个切面即可
<aop:aspect ref="myAspectJAdvice2"><aop:pointcut id="myPointcut2" expression="execution(* com.example.dao.UserDao.*(..))"/><aop:after-returning method="myAfterReturning" pointcut-ref="myPointcut2"/></aop:aspect>
3. 测试
OK,确实是打印了发送邮件,因此该多切面配置成功,下面接着讲解用另外几种方法实现AOP ,让我们一起学习啪
往期专栏&文章相关导读
大家如果对于本期内容有什么不了解的话也可以去看看往期的内容,下面列出了博主往期精心制作的Maven,Mybatis等专栏系列文章,走过路过不要错过哎!如果对您有所帮助的话就点点赞,收藏一下啪。其中Spring专栏有些正在更,所以无法查看,但是当博主全部更完之后就可以看啦。
1. Maven系列专栏文章
Maven系列专栏 | Maven工程开发 |
Maven聚合开发【实例详解---5555字】 |
2. Mybatis系列专栏文章
Mybatis系列专栏 | MyBatis入门配置 |
Mybatis入门案例【超详细】 | |
MyBatis配置文件 —— 相关标签详解 | |
Mybatis模糊查询——三种定义参数方法和聚合查询、主键回填 | |
Mybatis动态SQL查询 --(附实战案例--8888个字--88质量分) | |
Mybatis分页查询——四种传参方式 | |
Mybatis一级缓存和二级缓存(带测试方法) | |
Mybatis分解式查询 | |
Mybatis关联查询【附实战案例】 | |
MyBatis注解开发---实现增删查改和动态SQL | |
MyBatis注解开发---实现自定义映射关系和关联查询 |
3. Spring系列专栏文章
Spring系列专栏 | Spring IOC 入门简介【自定义容器实例】 |
IOC使用Spring实现附实例详解 | |
Spring IOC之对象的创建方式、策略及销毁时机和生命周期且获取方式 | |
Spring DI简介及依赖注入方式和依赖注入类型 | |
Spring IOC相关注解运用——上篇 | |
Spring IOC相关注解运用——下篇 | |
Spring AOP简介及相关案例 | |
注解、原生Spring、SchemaBased三种方式实现AOP【附详细案例】 | |
Spring事务简介及相关案例 | |
Spring 事务管理方案和事务管理器及事务控制的API | |
Spring 事务的相关配置、传播行为、隔离级别及注解配置声明式事务 |