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

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的扫描顺序了,这个扫描顺序每个项目还不固定,这时候就考验自己的能力了,各种奇形怪状的问题就会出现了。

  • 8
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
springboot框架图书商城系统源码可以用来实现一个功能完善的图书商城,在这个商城,用户可以浏览、搜索和购买图书,管理员可以管理图书库存和订单。 该源码使用了Spring Boot框架,它是基于Java的轻量级应用框架,提供了许多开箱即用的功能和组件,极大地简化了应用的开发和部署过程。 源码使用了MVC(Model-View-Controller)模式进行开发,将应用的业务逻辑、数据模型和用户界面进行了分离。通过使用Spring Boot框架提供的注解和配置,可以快速创建控制器、数据模型和视图,并实现它们之间的交互。 在该图书商城系统,用户可以注册账号并登录,登录后可以浏览图书列表、对图书进行搜索和查看图书的详细信息。用户可以将感兴趣的图书添加到购物车,并在购物车管理数量和删除不需要的图书。用户可以结算购物车的图书,并生成订单。 管理员可以登录后管理图书库存和订单。管理员可以添加、修改和删除图书信息,包括图书的名称、作者、价格和数量。管理员还可以查看和处理用户提交的订单。通过管理员界面,可以方便地进行图书管理和订单管理工作。 总之,该源码基于Spring Boot框架,实现了一个功能完善的图书商城系统,用户和管理员可以方便地进行图书浏览、搜索、购买和管理工作。该源码提供了一个可扩展性强、易于维护的基础,可以根据实际需求进行二次开发和定制。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值