如果想要自定义注解按照想要的顺序来执行,可以通过在注解实现类里面使用@Order注解来指定优先级。
优先级逻辑是:优先级值越小,优先级越大;优先级值越大,优先级越小。
不设置优先级值。会有一个默认值:2147483647,也就是最小优先级。
注解执行顺序是:
优先级大的的前置通知先执行,然后到优先级小的的前置通知; 接着到优先级小的的后置通知,再到优先级大的的后置通知。(也就是优先级大的注解逻辑会把优先级小的注解逻辑包裹在内部)
官方说法:
The highest precedence advice runs first “on the way in” (so, given two pieces of before advice, the one with highest precedence runs first). “On the way out” from a join point, the highest precedence advice runs last
相同优先级值的情况下:我在网上查,GPT的回复是按照注解的声明顺序执行。
代码验证
创建三个优先级相同的注解:(三个注解的定义就只有打印的内容不同,只贴其中一个)
package org.jeecg.modules.test.annotation;
import java.lang.annotation.*;
@Target(ElementType.METHOD) //作用范围
@Retention(RetentionPolicy.RUNTIME) //生效时期
public @interface Test1 {
}
package org.jeecg.modules.test.annotation;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
/**
* @ClassName: Test1Aspect
* @Author:
* @Date: 2023/11/1 10:40
* @Description:
**/
@Aspect
@Order(1)
@Component
public class Test1Aspect {
@Pointcut("@annotation(org.jeecg.modules.test.annotation.Test1)")
public void testPoint(){
}
@Before("testPoint()")
public void around() throws Throwable {
System.out.println("测试1的注解执行前置通知");
}
@After("testPoint()")
public void after() throws Throwable {
System.out.println("测试1的注解执行后置通知");
}
@Around("testPoint()")
public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
System.out.println("测试1的注解执行环绕通知前置通知");
Object proceed = joinPoint.proceed();
System.out.println("测试1的注解执行环绕通知后置通知");
return proceed;
}
}
package org.jeecg.modules.test;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.jeecg.common.util.RedisUtil;
import org.jeecg.modules.test.annotation.Test1;
import org.jeecg.modules.test.annotation.Test2;
import org.jeecg.modules.test.annotation.Test3;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.SetOperations;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.time.LocalDateTime;
import java.util.Set;
import java.util.concurrent.TimeUnit;
/**
* @ClassName: TestController
* @Author:
* @Date: 2023/8/21 14:28
* @Description:
**/
@Slf4j
@RestController
@Api("测试")
public class TestController {
@RequestMapping("/test")
@ApiOperation("测试")
@Test1()
@Test2()
@Test3()
public Object test(String a){
System.out.println("进入测试方法了");
return "ok";
}
}
运行结果(测了很多组,结果均如下)
更改注解顺序
package org.jeecg.modules.test;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.jeecg.common.util.RedisUtil;
import org.jeecg.modules.test.annotation.Test1;
import org.jeecg.modules.test.annotation.Test2;
import org.jeecg.modules.test.annotation.Test3;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.SetOperations;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.time.LocalDateTime;
import java.util.Set;
import java.util.concurrent.TimeUnit;
/**
* @ClassName: TestController
* @Author:
* @Date: 2023/8/21 14:28
* @Description:
**/
@Slf4j
@RestController
@Api("测试")
public class TestController {
@Autowired
private AsyncService asyncService;
@Autowired
private TestService testService;
@Autowired
private RedisTemplate redisTemplate;
@RequestMapping("/test")
@ApiOperation("测试")
@Test3()
@Test2()
@Test1()
public Object test(String a){
System.out.println("进入测试方法了");
return "ok";
}
}
运行结果(测了很多组,结果都是如下)
结论
两次验证,优先级均相同,颠倒了注解的先后顺序,但注解的执行顺序并没有改变。说明优先级相同情况下,注解的执行并不是按照写注解的先后顺序来的。而是按照注解的名字字符的顺序来的。字符对应的编码小,相当于优先级值小,优先级大,先执行。(感谢评论区老哥指正)
整体执行顺序:
- order值小的环绕通知joinPoint.proceed();前面部分
- order值小的前置通知
- order值大的环绕通知joinPoint.proceed();前面部分
- order值大的前置通知
- order值大的后置置通知
- order值大的环绕通知joinPoint.proceed();后面面部分
- order值小的后置置通知
- order值小的环绕通知joinPoint.proceed();后面面部分
如果order值相同则按照注解的字符顺序来执行,字符编码小的先执行。比如A的编码就比B小,相当于A的优先级值小于B,优先级大,先执行。