AOP:面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。而@Aspect 就是把一个类定义为切面供容器读取。
@before: 前置通知,在方法执行之前执行。
@After:后置通知,在方法执行后执行。
@AfterReturning: 返回通知,在方法返回结果之后执行。
@AfterThrowing:异常通知,在方法抛出异常之后执行。
@Around:环绕通知,围绕着方法执行。
这两个选一个就可以了,推荐使用第一个,因为第一个项目中肯定会用到的。
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
<version>2.5.4version>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-aopartifactId>
dependency>
@Component
@Aspect
public class TestAspect {
@Pointcut("execution( * com.atguigu.gulimall.product.controller.CouponController.*(..))")
private void log(){
}
@Before("log()")
public void TestBefore(){
System.out.println("在调用方法的时候都会调用这个切面");
}
把这个类加入到容器中,然后再添加上注解就可以就可以看成是一个切面容器。
execution( * com.atguigu.gulimall.product.controller.CouponController.*(..));
// 第一个* 代表任意修饰符及任意返回值下的CouponController类下的所有方法。
// 第二个* 代表CouponController类下的所有方法。
// (..) 代表任意参数
// 匹配CouponController类下面的所有共有方法。
@Pointcut("execution( public * com.atguigu.gulimall.product.controller.CouponController.*(..))")
// 第一个* 代表任意返回值
// 第二个* 当表任意方法
//(..) 代表任意参数
// 返回double 类型数值的方法
@Pointcut("execution( public Double com.atguigu.gulimall.product.controller.CouponController.*(..))")
// 匹配第一个参数为Double的方法。
@Pointcut("execution( public Double com.atguigu.gulimall.product.controller.CouponController.*(Double,..))")
// 匹配两个参数都为double 的方法。
@Pointcut("execution( public Double com.atguigu.gulimall.product.controller.CouponController.*(Double,Double))")
@Component
@Aspect
public class TestAspect {
@Pointcut("execution( * com.atguigu.gulimall.product.controller.CouponController.*(..))")
private void log(){
}
@Before("log()")
public void TestBefore(JoinPoint joinPoint){
Object[] args = joinPoint.getArgs();
String name = joinPoint.getSignature().getName();
System.out.println(Arrays.asList(args).toString() +" "+ name);
}
}
@RestController
@RequestMapping("product/coupon")
public class CouponController {
/**
* 列表
*/
@RequestMapping("/list")
public R list(@RequestBody Map<String, Object> params){
return R.ok().put("page", "测试专用");
}
}
当方法抛出异常的时候也不会影响执行切点方法,也就是说不管如何都是会执行切面方法的。
@Component
@Aspect
public class TestAspect {
@Pointcut("execution( * com.atguigu.gulimall.product.controller.CouponController.*(..))")
private void log(){
}
@After("log()")
public void TestBefore(JoinPoint joinPoint){
Object[] args = joinPoint.getArgs();
String name = joinPoint.getSignature().getName();
System.out.println(Arrays.asList(args).toString() +" "+ name);
}
}
/**
* 列表
*/
@RequestMapping("/list")
public R list(@RequestBody Map<String, Object> params){
PageUtils<CouponEntity> page = couponService.queryPage(params);
List<CouponEntity> list = page.getList();
String s = JSONObject.toJSONString(list);
// 当这行抛出异常的时候就不会再执行切点方法了。
int i = 1/0;
return R.ok().put("page", s);
}
@Component
@Aspect
public class TestAspect {
@Pointcut("execution( * com.atguigu.gulimall.product.controller.CouponController.*(..))")
private void log(){
}
@AfterReturning("log()")
public void TestBefore(JoinPoint joinPoint){
Object[] args = joinPoint.getArgs();
String name = joinPoint.getSignature().getName();
System.out.println(Arrays.asList(args).toString() +" "+ name);
}
}
@RequestMapping("/list")
public R list(@RequestBody Map<String, Object> params){
PageUtils<CouponEntity> page = couponService.queryPage(params);
List<CouponEntity> list = page.getList();
String s = JSONObject.toJSONString(list);
int i = 1/0;
return R.ok().put("page", s);
}
@Component
@Aspect
public class TestAspect {
@Pointcut("execution( * com.atguigu.gulimall.product.controller.CouponController.*(..))")
private void log(){
}
@AfterThrowing("log()")
public void TestBefore(JoinPoint joinPoint){
Object[] args = joinPoint.getArgs();
String name = joinPoint.getSignature().getName();
System.out.println(Arrays.asList(args).toString() +" "+ name);
}
}
- 使用 ProceedingJoinPoint 获取参数信息
- 使用joinPoint.proceed()方法调用方法。
- 只有调用上面的方法才能够执行方法
@Component
@Aspect
public class TestAspect {
@Pointcut("execution( * com.atguigu.gulimall.product.controller.CouponController.*(..))")
private void log(){
}
@Around("log()")
public R TestBefore(ProceedingJoinPoint joinPoint) throws Throwable {
Object[] args = joinPoint.getArgs();
Object o = args[0];
HashMap<String, String> stringStringHashMap = null;
if (o instanceof Map){
stringStringHashMap = (HashMap<String, String>) o;
}
if(stringStringHashMap.get("name").equals("xiaobai")){
// 当满足参数中name值xiaobai的时候,才会调用下面的方法。
R proceed = (R) joinPoint.proceed();
return proceed;
}else {
return R.ok().put("name","小周");
}
}
}
/**
* 列表
*/
@RequestMapping("/list")
public R list(@RequestBody Map<String, Object> params){
PageUtils<CouponEntity> page = couponService.queryPage(params);
List<CouponEntity> list = page.getList();
String s = JSONObject.toJSONString(list);
return R.ok().put("page", s);
}
package com.atguigu.gulimall.product.annoation;
import java.lang.annotation.*;
/**
* @author liruiqing
* 注解和@Aspect注解之间的联合使用
*/
@Documented
@Target({ElementType.METHOD}) // 在方法上加
@Retention(RetentionPolicy.RUNTIME) // 运行时
public @interface AnnotationTest {
}
@RequestMapping("/list")
@AnnotationTest
public R list(@RequestBody Map<String, Object> params){
PageUtils<CouponEntity> page = couponService.queryPage(params);
List<CouponEntity> list = page.getList();
String s = JSONObject.toJSONString(list);
return R.ok().put("page", s);
}
@Pointcut("@annotation(com.atguigu.gulimall.product.annoation.AnnotationTest)")
private void annotation(){
}
@After("annotation()")
public void testAnnotation(){
System.out.println("执行注解注释的方法后执行此方法");
}
这样就可以实现切面了。