1、AOP简介和作用
AOP(Aspect Oriented Programming)面向切面编程,一种编程范式。
作用:在不惊动原始设计的基础上为其进行功能增强。简单的说就是在不改变方法源代码的基础上对方法进行功能增强。
Spring理念:无入侵式/无侵入式
2、AOP核心概念
连接点:JoinPoint,可以被AOP控制的方法(暗含方法执行时的相关信息)
通知:Advice,指哪些重复的逻辑,也就是共性功能(最终体现为一个方法)
切入点:Pointcut,匹配连接点的条件,通知仅会在切入点方法执行时被应用
切面:Aspect,描述通知与切入点的对应关系(通知+切入点)
目标对象:Target,通知所应用的对象
可以认为切入点是连接点的子集
目标对象(Target):被代理的对象,也叫原始对象,该对象中的方法没有任何功能增强。
代理对象(Proxy):代理后生成的对象,由Spring帮我们创建代理对象。
3、Aop的具体实现
(1).在pom.xml文件引入相关依赖
<!-- AOP-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
(2).准备好测试类和通知类
连接点接口TestAop
public interface TestAop {
void test1();
void test2();
}
连接点接口的实现类TestAopImpl
@Service
public class TestAopImpl implements TestAop {
@Override
public void test1() {
for (int i = 0; i < 5; i++) {
System.out.println("Aop切入点");
}
}
@Override
public void test2() {
System.out.println("第二个连接点");
}
}
(3)切面类MyAspect1(定义通知)
//1声名是一个切面类
//2 交给ioc管理
//3.添加日志记录
@Aspect
@Component
@Slf4j
public class MyAspect1 {
//定义一个通知
@Around("execution(* edu.sias.service.impl.TestAopImpl.*(..))")
public Object testAop(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
log.info("方法放行前");
//环绕通知的方法放行
Object proceed = proceedingJoinPoint.proceed();
log.info("方法放行后");
return proceed;
}
}
在springboot的专门 测试类SpringbootJavawebMybatisApplicationTests中定义单元测试调用TestAopImpl里实现的方法
//注入依赖
@Autowired
private TestAop testAop;
@Test
void testAop() {
//调用该方法是,方法会去到Myspect1中进行通知的方法升级,再将结果返回到这里
testAop.test1();
}
}
(4) 结果分析
4、AOP执行流程
-
Spring容器启动
-
读取所有切面配置中的切入点
-
初始化bean,判定bean对应的类中的方法是否匹配到任意切入点
-
匹配失败,创建原始对象
-
匹配成功,创建原始对象(目标对象)的代理对象
-
-
获取bean执行方法
-
获取的bean是原始对象时,调用方法并执行,完成操作
-
获取的bean是代理对象时,根据代理对象的运行模式运行原始方法与增强的内容,完成操作
-
5、Aop通知类型
(1)前置通知@Before:在原始方法执行前执行
(2)后置通知@After:在方法执行后执行,原始方法无论是否异常,After通知都会执行
(3)环绕通知@Around:在方法执行前后执行
(4)返回后通知@AfterReturning:返回后执行,在原始方法后执行,有异常不会执行
(5)异常后通知@AfterThrowing:异常后执行,原始方法产生异常后执行
代码展示
@Slf4j
@Component//交给ioc管理
//@Aspect//是Aop类
@Order(1)//Aop类的执行列次(符合栈的特点)
//切入点(切点表达式所指向的方法)是连接点(能被Aop所代理的方法)的子集
public class MyAspect {
//抽取切点表达式
@Pointcut("execution(* edu.sias.service.*.*(..))")
//private改为public其他的类也可以使用
public void pt() {
}
@Around("pt()")//切点表达式
public void testA(){
//通知
log.info("before前执行的");
//调用原始方法
log.info("after后执行的");
}
@Before("pt()")
public void testB(){
log.info("before");
}
@After("pt()")
public void testAf(){
log.info("after");
}
@AfterReturning("pt()")
public void testAR(){
log.info("afterReturning");
}
@AfterThrowing("pt()")
public void testAT(){
log.info("afterThrowing");
}
}
6、Aop切点表达式
@Pointcut("execution(返回值 包名.包名.类名.方法(参数))")
以英文符号点进行级别的递降,进行更精确的匹配
(1)通配符
通配符 * :单个独立的任意符号,可以独立出现,也可以作为前缀或者后缀的匹配符出现
通配符 .. :.. :多个连续的任意符号,可以独立出现,常用于简化包名与参数的书写