@Order在同一个类的的不同方法的先后问题

为什么想到这个问题?
在实际工作开发中,因为之前写过一个aop,使用了一个方法,但代码并不多,但是新的需求也是能使用到aop的,且会影响之前写的aop,因此想要在同一个类中针对同一个方法进行排序。事实证明不行。测试如下:

package test.aop;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

@Component
@Aspect
public class AspectTest {
	@Around("execution(void test.aop.*.b(..))")
	@Order(1200)
	public void aroundb(ProceedingJoinPoint joinPoint){
		System.out.println("b1");
		try {
			joinPoint.proceed();
		} catch (Throwable throwable) {
			throwable.printStackTrace();
		}
	}
	@Around("execution(void test.aop.*.b(..))")
	@Order(100)
	public void aroundb2(ProceedingJoinPoint joinPoint){
		System.out.println("b12");
		try {
			joinPoint.proceed();
		} catch (Throwable throwable) {
			throwable.printStackTrace();
		}
	}

}

package test.aop;

import org.springframework.stereotype.Component;

@Component
public class Test {
	public void a(Stu stu){
		System.out.println("aaaaaaaaaaaaaa:"+stu);
	}
	public void b(){
		System.out.println("bbbbbbbbbbb");
	}
}

package test.aop;

import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class App {
	public static void main(String[] args) {
		AnnotationConfigApplicationContext ac=new AnnotationConfigApplicationContext(AppConfig.class);
		Test test = ac.getBean(Test.class);
		Stu stu=new Stu();
		stu.setId(1234);
		stu.setName("XXXX");
//		test.a(stu);
		System.out.println("-------------------------------");
		test.b();


	}
}

如果@Order生效的话,理论上顺序是b12,b1。但实际结果如下:
在这里插入图片描述

实际上这个并不受影响。
如果换成类的话:

package test.aop;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.core.annotation.AnnotatedElementUtils;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

@Component
@Aspect
@Order(1)
public class AspectTest {
	@Around("execution(void test.aop.*.b(..))")
	@Order(1200)
	public void aroundb(ProceedingJoinPoint joinPoint){
		System.out.println("b1");
		try {
			joinPoint.proceed();
		} catch (Throwable throwable) {
			throwable.printStackTrace();
		}
	}


	@Order(100)
	@Around("execution(void test.aop.*.b(..))")
	public void aroundb2(ProceedingJoinPoint joinPoint){
		System.out.println("b12");
		try {
			joinPoint.proceed();
		} catch (Throwable throwable) {
			throwable.printStackTrace();
		}
	}

}

package test.aop;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

@Component
@Aspect
@Order(10)
public class AspectTest2 {


	@Around("execution(void test.aop.*.b(..))")
	public void aroundb2(ProceedingJoinPoint joinPoint){
		System.out.println("b222222");
		try {
			joinPoint.proceed();
		} catch (Throwable throwable) {
			throwable.printStackTrace();
		}
	}

}

运行结果如下:
在这里插入图片描述可以发现确实按类是没有问题的。如果不相信,可以自行调换order的值来证明,这里就不证明了。
为什么会这样呢?我们查看官网:
https://docs.spring.io/spring-framework/docs/current/spring-framework-reference/core.html#beans-autowired-annotation
在这里插入图片描述

Your target beans can implement the org.springframework.core.Ordered interface or use the @Order or standard @Priority annotation if you want items in the array or list to be sorted in a specific order. Otherwise, their order follows the registration order of the corresponding target bean definitions in the container.

You can declare the @Order annotation at the target class level and on @Bean methods, potentially for individual bean definitions (in case of multiple definitions that use the same bean class). @Order values may influence priorities at injection points, but be aware that they do not influence singleton startup order, which is an orthogonal concern determined by dependency relationships and @DependsOn declarations.

Note that the standard javax.annotation.Priority annotation is not available at the @Bean level, since it cannot be declared on methods. Its semantics can be modeled through @Order values in combination with @Primary on a single bean for each type.
有道翻译如下:
您的目标bean可以实现org.springframework.core。如果希望数组或列表中的项按特定顺序排序,请使用@Order或标准@Priority注释。否则,它们的顺序遵循容器中相应的目标bean定义的注册顺序。

您可以在目标类级别和@Bean方法上声明@Order注释,这可能适用于单个bean定义(在多个定义使用同一个bean类的情况下)。@Order值可能会影响注入点的优先级,但是要注意它们不会影响单例启动顺序,这是由依赖关系和@DependsOn声明决定的正交关系。

注意,标准javax.annotation。Priority注释在@Bean级别不可用,因为它不能在方法上声明。它的语义可以通过@Order值和@Primary对每个类型的单个bean进行建模。

从这个翻译可以大致看出@Order主要是针对单个bean的排序,即只能在类或者Bean方法中使用,无法作用于普通方法。@Priority无法作用域方法上,因此该注释也不行。

我们再看看@Order的官方定义:
https://docs.spring.io/spring/docs/5.3.0-SNAPSHOT/javadoc-api/
在这里插入图片描述

看这段:
NOTE: Since Spring 4.0, annotation-based ordering is supported for many kinds of components in Spring, even for collection injection where the order values of the target components are taken into account (either from their target class or from their @Bean method). While such order values may influence priorities at injection points, please be aware that they do not influence singleton startup order which is an orthogonal concern determined by dependency relationships and @DependsOn declarations (influencing a runtime-determined dependency graph).

Since Spring 4.1, the standard Priority annotation can be used as a drop-in replacement for this annotation in ordering scenarios. Note that @Priority may have additional semantics when a single element has to be picked (see AnnotationAwareOrderComparator.getPriority(java.lang.Object)).
翻译如下:
注意:从Spring 4.0开始,Spring中许多类型的组件都支持基于注释的排序,即使是考虑到目标组件的顺序值的集合注入(从它们的目标类或从它们的@Bean方法)也是如此。虽然这些顺序值可能会影响注入点的优先级,但请注意,它们不会影响单例启动顺序,单例启动顺序是由依赖关系和@DependsOn声明决定的正交关系(影响运行时确定的依赖关系图)。
从Spring 4.1开始,在排序场景中,标准优先级注释可以作为该注释的替代。注意,当必须选择单个元素时,@Priority可能具有额外的语义(请参阅注释awareordercomparator . getpriority (java.lang.Object))。

这里明确指示出@Order只是作用域目标类或从它们的@Bean方法,且无法改变启动的顺序。因此从这里也证明了@Order无法对普通方法排序。

因此作用域普通方法的@Order并没有办法起到作用,控制优先级。因为单例一旦加载其顺序已经固定,可能spring认为再去调整类中方法执行的优先级意义不大,且实际使用也很少有此要求。

我们最后再看看aop的排序的介绍:
https://docs.spring.io/spring-framework/docs/current/spring-framework-reference/core.html#aop-ataspectj-advice-ordering
在这里插入图片描述
What happens when multiple pieces of advice all want to run at the same join point? Spring AOP follows the same precedence rules as AspectJ to determine the order of advice execution. 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 (so, given two pieces of after advice, the one with the highest precedence will run second).

When two pieces of advice defined in different aspects both need to run at the same join point, unless you specify otherwise, the order of execution is undefined. You can control the order of execution by specifying precedence. This is done in the normal Spring way by either implementing the org.springframework.core.Ordered interface in the aspect class or annotating it with the Order annotation. Given two aspects, the aspect returning the lower value from Ordered.getValue() (or the annotation value) has the higher precedence.

When two pieces of advice defined in the same aspect both need to run at the same join point, the ordering is undefined (since there is no way to retrieve the declaration order through reflection for javac-compiled classes). Consider collapsing such advice methods into one advice method per join point in each aspect class or refactor the pieces of advice into separate aspect classes that you can order at the aspect level.

翻译如下:
当多个通知都想在同一个连接点上运行时会发生什么?Spring AOP遵循与AspectJ相同的优先规则来确定通知执行的顺序。优先级最高的通知在“进来的路上”首先运行(因此,给定两个before通知,优先级最高的先运行)。从连接点“在出去的路上”,优先级最高的通知最后运行(因此,给定两个after通知,优先级最高的通知将运行在第二位)。

当在不同方面定义的两个通知都需要在同一个连接点上运行时,除非您另外指定,否则执行的顺序是未定义的。您可以通过指定优先级来控制执行的顺序。这是通过实现org.springframework.core以正常的Spring方式完成的。方面类中的有序接口或使用有序注释对其进行注释。给定两个方面,从order . getvalue()(或注释值)返回较低值的方面具有较高的优先级。

当在同一个方面定义的两个通知都需要在同一个连接点上运行时,顺序是未定义的(因为没有办法通过反射为javac编译的类检索声明顺序)。考虑将这些通知方法分解为每个方面类中的每个连接点的一个通知方法,或者将这些通知重新分解为可以在方面级别排序的单独的方面类。

注意理解这句话。就能知道为什么aop没有办法在同一个类中进行排序了。最后一段指明了spring官网就推荐使用类的排序,而不使用方法排序。所以我暂时找不出什么办法来解决这个问题。
因为目前来说:
@Order普通方法的排序不生效。
@Priority不能作用域方法上。
@Primary也不行。
如果某天找到了办法就更新到这里来。

  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值