Aop一般有以下常用注解:
@Aspect: 该注解是把此类声明为一个切面类。
@Before: 该注解是声明此方法为前置通知 (目标方法执行之前就会先执行被此注解标注的方法)
@After: 该注解是声明此方法为后置通知 (目标方法执行完之后就会执行被此注解标注的方法)
@AfterReturning: 该注解是声明此方法为返回通知 (目标方法正常执行返回后就会执行被此注解标注的方法)
@AfterThrowing: 该注解是声明此方法为异常通知 (目标方法在执行出现异常时就会执行被此注解标注的方法)
@Around: 该注解是环绕通知是动态的,可以在前后都设置执行
@PointCut: 该注解是声明一个公用的切入点表达式(通知行为的注解的都可以直接拿来复用)
通知类型包括:
● 前置通知:@Before 目标方法执行之前的通知
● 后置通知:@AfterReturning 目标方法执行之后的通知
● 环绕通知:@Around 目标方法之前添加通知,同时目标方法执行之后添加通知。
● 异常通知:@AfterThrowing 发生异常之后执行的通知
● 最终通知:@After 放在finally语句块中的通知
注解式开发
接下来,编写程序来测试这几个通知的执行顺序:
第一步:创建切面类:
//切面=通知加切点
//这里通知Advice以方法的形式出现,因为方法中可以写代码
//例如@Before注解标注的方法就是一个前置通知。括号里面是切点表达式 // 格式是@Before(“execution(修饰符 返回值类型 全限定类名 方法名(形式参数列表 )) 异常”)
不会切点表达式的或者想了解详情的请点击下面博主的另一篇查看详情哦!
spring Aop之切点表达式
package com.powernode.spring6.sevice;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
/**
* @author 阿离小稚
* @date 2023/12/13/22:10
*/
@Component
@Aspect //切面是需要这个注解标注的。
public class LogAspect {//切面类
//切面=通知加切点
//这里通知Advice以方法的形式出现,因为方法中可以写代码
//@Before注解标注的方法就是一个前置通知。里面是切点表达式
// @Before("execution(修饰符 返回值类型 全限定类名 方法名(形式参数列表 )) 异常")
@Before("execution( * com.powernode.spring6.sevice..*(..))")
public void beforeAdvice(){
System.out.println("前置通知。。。");
}
//后置通知
@AfterReturning("execution( * com.powernode.spring6.sevice..generate(..))")
public void afterReturningAdvice(){
System.out.println("后置通知。。。");
}
//环绕通知(环绕是最大的通知,在前置通知之前,在后置通知之后)
@Around("execution( * com.powernode.spring6.sevice..*(..))")
public void aroundAdvice(ProceedingJoinPoint joinPoint) throws Throwable {
System.out.println("前环绕haha");
//执行目标
joinPoint.proceed();
System.out.println("后环绕haha");
}
//异常通知
@AfterThrowing("execution( * com.powernode.spring6.sevice..*(..))")
public void afterThrowingAdvice(){
System.out.println("异常通知ooo");
}
//最终通知(finally语句块中的通知)
@After("execution( * com.powernode.spring6.sevice..*(..))")
public void afeterAdvice(){
System.out.println("最终通知!!");
}
}
第二步:创建目标类和目标方法:
package com.powernode.spring6.service;
import org.springframework.stereotype.Component;
// 目标类
@Component
public class OrderService {
// 目标方法
public void generate(){
System.out.println("订单已生成!");
}
}
第三步:创建测试程序:
package com.powernode.spring6.test;
import com.powernode.spring6.service.OrderService;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class AOPTest {
@Test
public void testAOP(){
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");
OrderService orderService = applicationContext.getBean("orderService", OrderService.class);
orderService.generate();
}
}
第四步:运行测试程序查看运行结果:
通过上面的执行结果就可以判断他们的执行顺序了,这里不再赘述。
结果中没有异常通知,这是因为目标程序执行过程中没有发生异常。我们尝试让目标方法发生异常:
package com.powernode.spring6.service;
import org.springframework.stereotype.Component;
// 目标类
@Component
public class OrderService {
// 目标方法
public void generate(){
System.out.println("订单已生成!");
if (1 == 1) {
throw new RuntimeException("运行时异常...");
}
}
}
再次执行测试程序,结果如下:
通过测试得知,当发生异常之后,最终通知也会执行,因为最终通知@After会出现在finally语句块中。
出现异常之后,后置通知和环绕通知的结束部分不会执行。
好了以上就是各种通知类型的演示(Aop注解开发)。想要了解切面的先后顺序的请看小编的下一篇博客
spring Aop基于注解之切面的先后顺序
@PointCut注解的使用
切点表达式没有得到复用我们可以用以下方法:
public class LogAspect {//切面类
@Pointcut("execution( * com.powernode.spring6.sevice..*(..))")
public void 通用切点(){
//zhe个方法只是个标记,方法名随意,方法体中也不需要写任何代码
}
//切面=通知加切点
//这里通知Advice以方法的形式出现,因为方法中可以写代码
//@Before注解标注的方法就是一个前置通知。里面是切点表达式
// @Before("execution(修饰符 返回值类型 全限定类名 方法名(形式参数列表 )) 异常")
@Before("通用切点()")
public void beforeAdvice(){
System.out.println("前置通知。。。");
}
如图所示