zoukankan      html  css  js  c++  java
  • springboot源码解析-管中窥豹系列之排序(五)

    一、前言

    • Springboot源码解析是一件大工程,逐行逐句的去研究代码,会很枯燥,也不容易坚持下去。
    • 我们不追求大而全,而是试着每次去研究一个小知识点,最终聚沙成塔,这就是我们的springboot源码管中窥豹系列。

     简介

    二、排序

    • 前几节我们讲源码的时候,会遇到一些排序的问题,我们都避而不谈

    比如获取initializer时的排序:

    
    private <T> Collection<T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) {
        ClassLoader classLoader = getClassLoader();
        Set<String> names = new LinkedHashSet<>(SpringFactoriesLoader.loadFactoryNames(type, classLoader));
        List<T> instances = createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);
    
        // 排序
        AnnotationAwareOrderComparator.sort(instances);
    
        return instances;
    }
    
    

    比如对runner排序:

    private void callRunners(ApplicationContext context, ApplicationArguments args) {
        List<Object> runners = new ArrayList<>();
        // (1) 找到ApplicationRunner的实现类,加到list里面
        runners.addAll(context.getBeansOfType(ApplicationRunner.class).values());
        // (2) 找到CommandLineRunner的实现类,加到list里面
        runners.addAll(context.getBeansOfType(CommandLineRunner.class).values());
        
        // (3) 排序
        AnnotationAwareOrderComparator.sort(runners);
        
        // (4) 钩子回调
        for (Object runner : new LinkedHashSet<>(runners)) {
            if (runner instanceof ApplicationRunner) {
                callRunner((ApplicationRunner) runner, args);
            }
            if (runner instanceof CommandLineRunner) {
                callRunner((CommandLineRunner) runner, args);
            }
        }
    }
    

    我们来分析一下这个排序AnnotationAwareOrderComparator.sort(list)的源码。

    三、源码解析

    
    public static final AnnotationAwareOrderComparator INSTANCE = new AnnotationAwareOrderComparator();
    
    public static void sort(List<?> list) {
        if (list.size() > 1) {
            list.sort(INSTANCE);
        }
    }
    
    
    • 已new的AnnotationAwareOrderComparator对象作为参数,排序
    • list.sort(comparator)是jdk自带的排序, 通用的
    default void sort(Comparator<? super E> c) {
        Object[] a = this.toArray();
        Arrays.sort(a, (Comparator) c);
        ListIterator<E> i = this.listIterator();
        for (Object e : a) {
            i.next();
            i.set((E) e);
        }
    }
    
    • 我们知道排序要么实现Comparable接口,要么new Comparator, spring用的第二种
    • 我们重点看下这个comparator : AnnotationAwareOrderComparator
    public class AnnotationAwareOrderComparator extends OrderComparator {
    
        ...
    
    }
    
    public class OrderComparator implements Comparator<Object> {
    
        ...
    
    }
    
    

    compare方法在OrderComparator里面:

    @Override
    public int compare(@Nullable Object o1, @Nullable Object o2) {
        return doCompare(o1, o2, null);
    }
    
    private int doCompare(@Nullable Object o1, @Nullable Object o2, @Nullable OrderSourceProvider sourceProvider) {
        boolean p1 = (o1 instanceof PriorityOrdered);
        boolean p2 = (o2 instanceof PriorityOrdered);
        if (p1 && !p2) {
            return -1;
        }
        else if (p2 && !p1) {
            return 1;
        }
    
        int i1 = getOrder(o1, sourceProvider);
        int i2 = getOrder(o2, sourceProvider);
        return Integer.compare(i1, i2);
    }
    
    • 先判断有没有实现PriorityOrdered接口,实现了的比没实现的有高优先级
    • 再用getOrder()判断
    private int getOrder(@Nullable Object obj, @Nullable OrderSourceProvider sourceProvider) {
        Integer order = null;
        if (obj != null && sourceProvider != null) {
            Object orderSource = sourceProvider.getOrderSource(obj);
            if (orderSource != null) {
                if (orderSource.getClass().isArray()) {
                    Object[] sources = ObjectUtils.toObjectArray(orderSource);
                    for (Object source : sources) {
                        order = findOrder(source);
                        if (order != null) {
                            break;
                        }
                    }
                }
                else {
                    order = findOrder(orderSource);
                }
            }
        }
        return (order != null ? order : getOrder(obj));
    }
    

    sourceProvider为空,我们可以直接看最后一行。

    
    int LOWEST_PRECEDENCE = Integer.MAX_VALUE;
    
    protected int getOrder(@Nullable Object obj) {
        if (obj != null) {
            Integer order = findOrder(obj);
            if (order != null) {
                return order;
            }
        }
        return Ordered.LOWEST_PRECEDENCE;
    }
    
    protected Integer findOrder(Object obj) {
        return (obj instanceof Ordered ? ((Ordered) obj).getOrder() : null);
    }
    
    • 判断有没有实现Ordered接口,如果有就取出来它的order值
    • 如果没有,就取Integer.MAX_VALUE
    • 注意,order值越小,优先级越高
    • 注意,上面findOrder方法是protected, 我们最开始说的AnnotationAwareOrderComparator对它进行了重写
    @Override
    @Nullable
    protected Integer findOrder(Object obj) {
        Integer order = super.findOrder(obj);
        if (order != null) {
            return order;
        }
        return findOrderFromAnnotation(obj);
    }
    
    @Nullable
    private Integer findOrderFromAnnotation(Object obj) {
        AnnotatedElement element = (obj instanceof AnnotatedElement ? (AnnotatedElement) obj : obj.getClass());
        MergedAnnotations annotations = MergedAnnotations.from(element, SearchStrategy.TYPE_HIERARCHY);
        Integer order = OrderUtils.getOrderFromAnnotations(element, annotations);
        if (order == null && obj instanceof DecoratingProxy) {
            return findOrderFromAnnotation(((DecoratingProxy) obj).getDecoratedClass());
        }
        return order;
    }
    
    • 先调用父类的findOrder方法
    • 没找到,再调用findOrderFromAnnotation方法
    • 最重要的是这一行:OrderUtils.getOrderFromAnnotations(element, annotations),我们进去看看
    @Nullable
    static Integer getOrderFromAnnotations(AnnotatedElement element, MergedAnnotations annotations) {
        if (!(element instanceof Class)) {
            return findOrder(annotations);
        }
        Object cached = orderCache.get(element);
        if (cached != null) {
            return (cached instanceof Integer ? (Integer) cached : null);
        }
        Integer result = findOrder(annotations);
        orderCache.put(element, result != null ? result : NOT_ANNOTATED);
        return result;
    }
    
    @Nullable
    private static Integer findOrder(MergedAnnotations annotations) {
        MergedAnnotation<Order> orderAnnotation = annotations.get(Order.class);
        if (orderAnnotation.isPresent()) {
            return orderAnnotation.getInt(MergedAnnotation.VALUE);
        }
        MergedAnnotation<?> priorityAnnotation = annotations.get(JAVAX_PRIORITY_ANNOTATION);
        if (priorityAnnotation.isPresent()) {
            return priorityAnnotation.getInt(MergedAnnotation.VALUE);
        }
        return null;
    }
    
    private static final String JAVAX_PRIORITY_ANNOTATION = "javax.annotation.Priority";
    
    • 两个方法,第一个是简单的缓存,不用看,重点看第二个方法
    • 先判断有没有org.springframework.core.annotation.Order注解
    • 再判断有没有javax.annotation.Priority注解
    • 有注解就去上面的值,没有返回null

    回到最开始的方法,进行int值的排序

    Integer.compare(i1, i2);
    
    public static int compare(int x, int y) {
        return (x < y) ? -1 : ((x == y) ? 0 : 1);
    }
    

    至此,我们的排序源码就分析完了,我们总结一下:

    • (1)先判断有没有实现PriorityOrdered,实现PriorityOrdered比没实现的有高优先级
    • (2)第一步如果比较不出来,判断有没有实现Ordered,如果实现了,取实现方法的int值比较
    • (3)如果没有实现Ordered,判断有没有org.springframework.core.annotation.Order注解, 有注解,取注解上的order值,进行比较
    • (4)如果没有Order注解,判断有没有javax.annotation.Priority注解,取注解上的值比较
    • (5)如果上面都没有,返回Integer.MAX_VALUE,值越大优先级越低

     丰极

    欢迎关注微信公众号:丰极,更多技术学习分享。

  • 相关阅读:
    k8s--容器挂载 error: /proc must be mounted
    mysql--read only
    C#读取Excel文件(.xls .xlsx)
    如何使用BBCode
    markdown使用经验积累
    openlayers学习之-----入门篇
    echarts学习之----动态排序柱状图
    echarts学习之----多图例折线图
    Web3D学习之-----全景图预览插件photo-sphere-viewer
    vue报错解决----npm ERR!
  • 原文地址:https://www.cnblogs.com/zhangbin1989/p/14270982.html
Copyright © 2011-2022 走看看