Spring 自定义切面注解总的来说分为三步:

一、对自定义注解进行声明;

二、对自定义切面进行声明,在自定义切面类中对注解切入时执行的方法进行业务编写;

三、在需要使用注解切入的地方进行注解声明使用;

 

具体的操作说明如下:

1、原测试工程很简单,一个pojo实体类,一个dao类,一个service类,一个controller类

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Person {

    private Integer id;

    private String name;

}

 

@Component
public class PersonDao {

    public Person findPersonById(Integer id) {
        if(id > 10) {
            return null;
        }
        return new Person(id, "person-" + id);
    }
}

 

@Service
public class PersonService {

    private final PersonDao personDao;

    public PersonService(PersonDao personDao) {
        this.personDao = personDao;
    }

    public Person findPersonById(Integer id) {
        return personDao.findPersonById(id);
    }
}

 

@RestController
public class PersonController {

    private final PersonService personService;

    public PersonController(PersonService personService) {
        this.personService = personService;
    }

    @RequestMapping("person/{id}")
    public Person findPerson(@PathVariable("id") Integer id) {
        return personService.findPersonById(id);
    }
}

直接访问localhost:8080/person/1后,显然会得到一个如下的json串 

现在要在findPerson方法上增加自定义的注解,这个注解只做简单的日志输出

1、新建一个annotation包,包里新建一个类YMLog

package com.example.demo.annotation;

import java.lang.annotation.*;

@Documented   //该注解表示支持javaDoc文档导出
@Retention(RetentionPolicy.RUNTIME) //该注解表示生命周期
@Target(ElementType.METHOD)  //该注解表示自定义的注解可以使用的对象
public @interface YMLog {

    String value() default "";
}

2、新建一个切面类,

@Component
@Aspect
public class YMLogAspect {
    private static Logger logger = LoggerFactory.getLogger(MyAuthorizationHandler.class);

    
    @Pointcut("@annotation(com.example.demo.annotation.YMLog)")
    private void pointcut() {}
    
    @Before("pointcut() && @annotation(logger)")
    public void advice(JoinPoint joinPoint, YMLog logger) {
        logger.debug("注解作用的方法名: " + joinPoint.getSignature().getName());
        
        logger.debug("所在类的简单类名: " +         
        joinPoint.getSignature().getDeclaringType().getSimpleName());
        
        logger.debug("所在类的完整类名: " + 
        joinPoint.getSignature().getDeclaringType());
        
        logger.debug("目标方法的声明类型: " + 
        Modifier.toString(joinPoint.getSignature().getModifiers()));

        logger.debug("--- 日志的内容为" + logger.value() + " ---");
    }


    //这里还可以省略pointcut()方法,使用下面的写法
    @Before(value="@annotation(logger)")
    public void advice(JoinPoint joinPoint, YMLog logger) {
        logger.debug("注解作用的方法名: " + joinPoint.getSignature().getName());
        
        logger.debug("所在类的简单类名: " +         
        joinPoint.getSignature().getDeclaringType().getSimpleName());
        
        logger.debug("所在类的完整类名: " + 
        joinPoint.getSignature().getDeclaringType());
        
        logger.debug("目标方法的声明类型: " + 
        Modifier.toString(joinPoint.getSignature().getModifiers()));

        logger.debug("--- 日志的内容为" + logger.value() + " ---");
    }

}

@Pointcut声明了切点(这里的切点是我们自定义的注解类),@Before声明了通知内容(@Before, @After, @Around),在具体的通知中,我们通过@annotation(logger)拿到了自定义的注解对象,所以就能够获取我们在使用注解时赋予的值了。如果这里不明白的,可以学习Spring基础知识,了解什么是AOP;

3、在需要使用的地方进行注解声明使用

@RestController
public class PersonController {

    private final PersonService personService;

    public PersonController(PersonService personService) {
        this.personService = personService;
    }

    @YMLog("这是自定义日志切入")
    @RequestMapping("person/{id}")
    public Person findPerson(@PathVariable("id") Integer id) {
        return personService.findPersonById(id);
    }
}

使用注解还可以修改前台传给后端的参数和后端返回给前台的返回值,具体操作如下:

@Around("pointcut() && @annotation(logger)")
public Object advice(ProceedingJoinPoint joinPoint, YMLog logger) {
   System.out.println("["
                + joinPoint.getSignature().getDeclaringType().getSimpleName()
                + "][" + joinPoint.getSignature().getName()
                + "]-日志内容-[" + logger.value() + "]");

        Object result = null;
        
        Object[] args = joinPoint.getArgs();
        //对前端传入的参数做处理
        for (int i = 0; i < args.length; i++) {
            if(args[i] instanceof Integer) {
                args[i] = (Integer)args[i] - 1;
                break;
            }
        }

        try {
            //这里是执行真正的原方法
            result = joinPoint.proceed(args);
        } catch (Throwable throwable) {
            throwable.printStackTrace();
        }
        
        //这里是在返回之前对返回结果进行处理
        if(result instanceof Person) {
            Person person= (Person) result;
            person.setName("tom");
            return person;
        }
        return result;
}