Spring之类的优先级设置

Order注解

@Order 注解定义了类、方法和字段的优先级(排序情况),value 是可选的,默认为Ordered.LOWEST_PRECEDENCE,即最低优先级。表示 Ordered 接口中的 order 属性。

目前看到的 @Order 注解都是用在类上的,没有看到过用在方法和字段上的,包括 Spring 自有类 DefaultErrorAttributes、LogbackLoggingSystem.Factory 等。

1
2
3
4
5
6
7
8
9
10
11
12
13
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD})
@Documented
public @interface Order {

/**
* 优先级排序值,value 的值越大,优先级越低
* 默认值为 Ordered.LOWEST_PRECEDENCE(Integer.MAX_VALUE)
* @see Ordered#getOrder()
*/
int value() default Ordered.LOWEST_PRECEDENCE;

}

从 Spring 4.0 开始,Spring 中的很多组件都支持基于 Order 注解的排序,使用了该注解后,会影响依赖注入的优先级,但是不影响bean的加载顺序,因为加载顺序受依赖关系和 @DependsOn声明影响的。

这句理解上还是有问题~

从 Spring 4.1 开始,jakarta.annotation.Priority 可在一些排序场景中替代 @Order 的作用,但是在修饰单个元素时,@Priority 可能具有其他语义。

除了这两个注解外,也可以实现 Ordered 接口,来设置优先级信息,相对使用注解的方式更加灵活。

Priority注解

@Priority 注解位于 jakarta.annotation 包下,可以标识类或参数以什么样的顺序来执行或使用。

Priority 注解的具体作用由具体的使用类来定义,如在Jakarta Interceptors 规范定义了使用拦截器的优先级来控制调用拦截器的顺序。

value 一般情况下应该是非负值,负值作为保留值有特定的含义,如“未定义”或“未指定”等。

定义 @Priority 使用的规范可以定义允许的优先级范围和任何具有特殊含义的优先级值。

1
2
3
4
5
6
7
8
9
@Target({TYPE,PARAMETER}) //只能用于TYPE和PARAMETER,这是和Order注解不一样的地方
@Retention(RUNTIME)
@Documented
public @interface Priority {
/**
* 优先级排序值
*/
int value();
}

@Priorityvalue 越小,优先级越高。

OrderUtils类

OrderUtils 用于对添加了 @Order注解和 @Priority注解的类,根据声明的顺序和优先级进行处理,相当于是两个注解的具体实现。

OrderUtils 提供了三个常量:

1
2
3
4
5
6
7
8
//用于缓存每个Class的排序值value,如果没有使用 @Order注解,则使用NOT_ANNOTATED标记记录
private static final Map<AnnotatedElement, Object> orderCache = new ConcurrentReferenceHashMap<>(64);

//未用 @Order 注解的缓存标记
private static final Object NOT_ANNOTATED = new Object();

//Priority注解的类路径
private static final String JAVAX_PRIORITY_ANNOTATION = "jakarta.annotation.Priority";

针对 @Order@Priority 注解提供了4个 getOrder 的方法,进行排序值的获取。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
//获取某个类的排序值,如果排序值未设置,则返回默认值
public static int getOrder(Class<?> type, int defaultOrder) {
Integer order = getOrder(type);
return (order != null ? order : defaultOrder);
}

//获取某个类的排序值,如果排序值未设置,则返回默认值
@Nullable
public static Integer getOrder(Class<?> type, @Nullable Integer defaultOrder) {
Integer order = getOrder(type);
return (order != null ? order : defaultOrder);
}

//获取某个类的排序值,可返回null值
@Nullable
public static Integer getOrder(Class<?> type) {
return getOrder((AnnotatedElement) type);
}

//获取某个类的排序值,可返回null值
@Nullable
public static Integer getOrder(AnnotatedElement element) {
return getOrderFromAnnotations(element, MergedAnnotations.from(element, SearchStrategy.TYPE_HIERARCHY));
}

可以看到,getOrder(Class<?> type, int defaultOrder)getOrder(Class<?> type, @Nullable Integer defaultOrder)调用了 getOrder(Class<?> type) , 而 getOrder(Class<?> type) 则调用了 getOrder(AnnotatedElement element)

看看 getOrderFromAnnotations 的具体实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
/**
* 从指定的 Order注解集合中返回对应的顺序值
*
*
*
*/
@Nullable
static Integer getOrderFromAnnotations(AnnotatedElement element, MergedAnnotations annotations) {

if (!(element instanceof Class)) {
return findOrder(annotations);
}
//缓存中是否已存在
Object cached = orderCache.get(element);
if (cached != null) {
//转换成Integer类型
return (cached instanceof Integer ? (Integer) cached : null);
}
//获取Order的排序值,并写入到orderCache中
Integer result = findOrder(annotations);
orderCache.put(element, result != null ? result : NOT_ANNOTATED);
//返回排序值
return result;
}

@Nullable
private static Integer findOrder(MergedAnnotations annotations) {
//判断是否加了Order注解,如果加了,则获取VALUE值,并返回
MergedAnnotation<Order> orderAnnotation = annotations.get(Order.class);
if (orderAnnotation.isPresent()) {
return orderAnnotation.getInt(MergedAnnotation.VALUE);
}
//判断是否加了Priority注解,如果加了,则获取VALUE值,并返回
MergedAnnotation<?> priorityAnnotation = annotations.get(JAVAX_PRIORITY_ANNOTATION);
if (priorityAnnotation.isPresent()) {
return priorityAnnotation.getInt(MergedAnnotation.VALUE);
}
//Order和Priority注解都没有,则返回null值
return null;
}

最后针对 @Priority 注解单独提供了 getPriority(Class<?> type) 方法,获取优先级的数值,如果没有添加注解或者 value 未设值,则返回 null。

1
2
3
4
5
@Nullable
public static Integer getPriority(Class<?> type) {
return MergedAnnotations.from(type, SearchStrategy.TYPE_HIERARCHY).get(JAVAX_PRIORITY_ANNOTATION)
.getValue(MergedAnnotation.VALUE, Integer.class).orElse(null);
}

Ordered接口

优先级排序接口,和 @Order 注解一样,获取到的 order 值越小,优先级越高。

1
2
3
4
5
//最高优先级
int HIGHEST_PRECEDENCE = Integer.MIN_VALUE;

//最低的优先级
int LOWEST_PRECEDENCE = Integer.MAX_VALUE;

提供获取排序值的方法,如果两个对象的 order 值相同,则会进行随机排序。

1
int getOrder();

PriorityOrdered接口

Ordered接口的扩展接口,表示优先级排序。

PriorityOrdered 接口的优先级要高于 Ordered接口的优先级,即使后者对应的 order 值比较小,也是 PriorityOrdered 的优先级高。

在对一组对象进行排序时, PriorityOrdered对象和 Ordered对象可以被看作两个单独的子集,其中一组 PriorityOrdered对象位于一组 Ordered 对象之前,然后在这两个子集中再根据 order 进行相对排序。

PriorityOrdered 是一个专用接口,用于标记特别重要的的对象,甚至不需要获取剩余的对象,比如 Spring 中优先级比较高的后置处理器 ApplicationContextPriorityOrdered 相关的后置处理器 Bean 在特殊阶段进行初始化,早于其他的后置处理器,这巧妙地影响了它们的自动装配行为:只会针对不需要急切初始化类型匹配的 bean 进行自动装配。

PriorityOrdered 的应用可参见 org.springframework.beans.factory.config.PropertyOverrideConfigurer 类。