【记录版】SpringBoot框架中排序设计源码解读

2023-12-14 23:25:56

SpringBoot + AnnotationAwareOrderComparator

背景: 在日常框架开发过程中,指定类执行顺序是常见操作,往往在定义Bean的时候就指定其前后顺序,以保证逻辑的正确解析与传递。通过我们直接通过添加@Order注解或者实现Ordered接口来完成,那么底层解析的逻辑是什么样的?本篇仅做简单记录。

Servlet系列精选:
1、Servlet请求体重复读&修改新姿势
2、根据请求获取后端接口详情
3、Filter链式执行设计解读
4、SpringBoot下Filter注册流程
5、SpringBoot下Filter自动适配

一、排序解析核心类
1)org.springframework.core.annotation.AnnotationAwareOrderComparator
2)org.springframework.core.annotation.OrderUtils

二、AnnotationAwareOrderComparator + OrderComparator部分代码【合并版】

public class AnnotationAwareOrderComparator extends OrderComparator {
    // 通常以此方法开始解析类中的优先级属性
    protected int getOrder(@Nullable Object obj) {
        if (obj != null) {
        	// 开始查找类定义中的@Order注解或Order接口属性
            Integer order = this.findOrder(obj);
            if (order != null) {
                return order;
            }
        }
		// 如果未找到相关属性,则默认最低优先级(Integer.MAX_VALUE)
        return 2147483647;
    }
	
    @Nullable
    protected Integer findOrder(Object obj) {
    	// 类实现Ordered接口,直接通过getOrder方法返回指定值
        Integer order = obj instanceof Ordered ? ((Ordered)obj).getOrder() : null;
        // 获取其他场景优先级属性【复杂版】
        return order != null ? order : this.findOrderFromAnnotation(obj);
    }

    @Nullable
    private Integer findOrderFromAnnotation(Object obj) {
    	// AnnotatedElement是jdk1.5引入的反射核心类,Clas、Method、Field、Parameter都是其子类
        AnnotatedElement element = obj instanceof AnnotatedElement ? (AnnotatedElement)obj : obj.getClass();
        // 此处指定注解解析策略,层级搜索,包含父类及父接口的所有注解
        MergedAnnotations annotations = MergedAnnotations.from((AnnotatedElement)element, SearchStrategy.TYPE_HIERARCHY);
        // 通过OrderUtils工具类获取注解集合中的@Order或@Priority
        Integer order = OrderUtils.getOrderFromAnnotations((AnnotatedElement)element, annotations);
        // 如果Bean定义负责,涉及其他框架AOP代理封装,此处将原始Bean定义拿出解析
        // 在此之前没有判断是否代理,其他框架在AOP实现时可以添加优先级属性以实现辅助功能执行顺序调整?+
        // 注意:这块出现了递归调用
        return order == null && obj instanceof DecoratingProxy ? this.findOrderFromAnnotation(((DecoratingProxy)obj).getDecoratedClass()) : order;
    }

    @Nullable
    // Priority注解处理
    public Integer getPriority(Object obj) {
        if (obj instanceof Class) {
            return OrderUtils.getPriority((Class)obj);
        } else {
            Integer priority = OrderUtils.getPriority(obj.getClass());
            return priority == null && obj instanceof DecoratingProxy ? this.getPriority(((DecoratingProxy)obj).getDecoratedClass()) : priority;
        }
    }
}

三、OrderUtils类代码

// 工具类,皆静态方法,abstract修饰类避免创建实例
public abstract class OrderUtils {
    private static final Object NOT_ANNOTATED = new Object();
    private static final String JAVAX_PRIORITY_ANNOTATION = "javax.annotation.Priority";
    // 解析结果缓存,以空间换时间
    // MergedAnnotations搜索优先级属性更耗时为啥没缓存?搜索策略多样的原因吗
    private static final Map<AnnotatedElement, Object> orderCache = new ConcurrentReferenceHashMap(64);

    public OrderUtils() {
    }

    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;
    }

    @Nullable
    public static Integer getOrder(Class<?> type) {
        return getOrder((AnnotatedElement)type);
    }

    @Nullable
    public static Integer getOrder(AnnotatedElement element) {
        return getOrderFromAnnotations(element, MergedAnnotations.from(element, SearchStrategy.TYPE_HIERARCHY));
    }

    @Nullable
    // AnnotationAwareOrderComparator中调用的工具方法
    static Integer getOrderFromAnnotations(AnnotatedElement element, MergedAnnotations annotations) {
        if (!(element instanceof Class)) {
            return findOrder(annotations);
        } else {
            Object cached = orderCache.get(element);
            if (cached != null) {
                return cached instanceof Integer ? (Integer)cached : null;
            } else {
                Integer result = findOrder(annotations);
                orderCache.put(element, result != null ? result : NOT_ANNOTATED);
                return result;
            }
        }
    }

    @Nullable
    private static Integer findOrder(MergedAnnotations annotations) {
       // Order注解解析
        MergedAnnotation<Order> orderAnnotation = annotations.get(Order.class);
        if (orderAnnotation.isPresent()) {
            return orderAnnotation.getInt("value");
        } else {
        	// Priority注解解析
            MergedAnnotation<?> priorityAnnotation = annotations.get("javax.annotation.Priority");
            return priorityAnnotation.isPresent() ? priorityAnnotation.getInt("value") : null;
        }
    }

    @Nullable
    public static Integer getPriority(Class<?> type) {
        return (Integer)MergedAnnotations.from(type, SearchStrategy.TYPE_HIERARCHY).get("javax.annotation.Priority").getValue("value", Integer.class).orElse((Object)null);
    }

优先级属性获取流程都清楚了,日常怎么使用?

public int AnnotationAwareOrderComparator.compare(@Nullable Object o1, @Nullable Object o2)Collection<E>.stream()
	.sorted(AnnotationAwareOrderComparator.INSTANCE)
	.collect(Collectors.toList())

如果自己想获取优先级属性的具体解析值,如Filter适配逻辑中的需求,那怎么办?直接调用getOrder方法吗?其实不是…

public int getOrder(Object value) {
    return (new AnnotationAwareOrderComparator() {
        public int getOrder(Object obj) {
            return super.getOrder(obj);
        }
    }).getOrder(value);
}

为什么这样麻烦?还不是protected惹的祸,设计者就没想对外开放,一般人也没这个需求,工具类都是直接走compare方法了。

总结:
1、优先级围绕Order注解、Ordered接口、@Priority注解展开,优先使用前两个
2、注解从jdk1.5开始,AnnotatedElement父接口提供了反射时注解相关的解析方法,后期给我们自定义注解及AOP使用带了极大的便利性
3、优先级属性只作为参考,只有后台有排序逻辑才有意义,一般只有同类对象才会处理,如Spring各自bean间的执行顺序不依赖此属性
4、如果依赖第三方包,且需要对同类排序,但是依赖实例都没有定义优先级属性,此时默认都是最低优先级,执行顺序就按BeanDefinition的扫描顺序了,这个扫描顺序每个项目还不固定,这时候就考验自己的能力了,各种奇形怪状的问题就会出现了。

文章来源:https://blog.csdn.net/src1025/article/details/134905202
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。