通过BeanPostProcessor统计每一个Bean初始化耗时|通过优先级队列PriorityQueue构建小顶堆获取动态添加数列的TopK算法

通过BeanPostProcessor统计每一个Bean初始化耗时

思路:

  • 统计Bean耗时的基础数据结构是个Map,Map的键是Bean的名称,值是初始化耗费时间。
  • postProcessBeforeInitialization在Bean初始化之前执行,因此记录初始化开始时间
  • postProcessAfterInitialization在Bean初始化之后执行,因此通过初始化结束时间减去初始化开始时间得出初始化耗时
  • 通过监听ContextRefreshedEvent事件判断容器加载完毕,将最耗时的K个Bean日志输出。

通过优先级队列构建小顶堆获取动态添加数列的最大TopK个值

使用PriorityQueue构建TopK算法找出容器中初始化最耗时的K个Bean

思路:

  • 添加新数据进来,将新数据和堆顶的最小值进行比较
  • 新数据比堆顶最小值大,新数据得到晋升,抛弃堆顶最小值
  • 新数据比堆顶最小值小,忽略新数据,堆保持不变

代码示例

使用BeanPostProcessor统计每个Bean的耗时
public class LoggerBeanLoadCostPostProcessor implements BeanPostProcessor, Ordered, ApplicationListener<ContextRefreshedEvent> {

    private Map<String, Long> cost = new HashMap<>(500);

    private static final int TOPK = 5;

    private static AtomicInteger beanCount = new AtomicInteger(0);

    private TopK<CostInfo> topK = new TopK<>(TOPK);

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        cost.put(beanName, Instant.now().toEpochMilli());
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        beanCount.incrementAndGet();

        Long startStamp = cost.get(beanName);
        if (startStamp != null) {
            Long currentCost = Instant.now().toEpochMilli() - startStamp;
            cost.put(beanName, currentCost);
            topK.add(new CostInfo(beanName, currentCost));
        }
        return bean;
    }


    @Override
    public void onApplicationEvent(ContextRefreshedEvent event) {
        printBeanInitCostLog();
    }

    private void printBeanInitCostLog() {
        StringBuilder stringBuilder = new StringBuilder().append("\r\n");
        List<CostInfo> costInfos = Lists.newArrayList(topK.toArray(new CostInfo[0])).stream().sorted(Comparator.reverseOrder()).collect(Collectors.toList());
        for (int i = 0; i < costInfos.size(); i++) {
            stringBuilder.append(" costRank" + (i + 1) + ",beanName=" + costInfos.get(i).name + ",cost=" + costInfos.get(i).cost).append("\r\n");
        }
        LogBase.getSysLogger().info("load_spring_bean_cost_info,bean created count:{},info:{}", beanCount.get(), stringBuilder.toString());
    }

    @Override
    public int getOrder() {
        return Integer.MAX_VALUE;
    }

    public static class CostInfo implements Comparable<CostInfo> {
        private String name;
        private Long cost;

        public CostInfo(String name, Long cost) {
            this.name = name;
            this.cost = cost;
        }

        public String getName() {
            return name;
        }

        public Long getCost() {
            return cost;
        }

        @Override
        public int compareTo(CostInfo o) {
            return this.cost.compareTo(o.getCost());
        }
    }
}

使用PriorityQueue构建小顶堆计算TopK
public class TopK<E> {
    private PriorityQueue<E> queue;
    private int k;

    public TopK(int k) {
        this.k = k;
        this.queue = new PriorityQueue<>(k);
    }

    public void addAll(Collection<? extends E> c) {
        for (E e : c) {
            add(e);
        }
    }

    public void add(E e) {
        if (queue.size() < k) {
            queue.add(e);
            return;
        }
        Comparable<? super E> head = (Comparable<? super E>) queue.peek();
        if (head.compareTo(e) > 0) {
            //新元素比不上已有TopK中的最小值直接忽略
            return;
        }
        //新元素入驻TopK,将已有TopK中的堆顶最小值删除,将新元素加入
        queue.poll();
        queue.add(e);
    }

    public <T> T[] toArray(T[] a) {
        return queue.toArray(a);
    }

    public E getKth() {
        return queue.peek();
    }

    public PriorityQueue<E> getQueue() {
        return queue;
    }

    public static void main(String[] args) {
        TopK<Integer> topK = new TopK<>(5);
        List<Integer> origin = new ArrayList<>();
        for (int i = 0; i < 20; i++) {
            Integer cur = RandomUtils.nextInt() % 1000;
            origin.add(cur);
            topK.add(cur);
        }
        System.out.println("origin=" + JSON.toJSONString(origin));
        Integer[] integers = topK.toArray(new Integer[0]);
        List<Integer> topKOrdered = Lists.newArrayList(integers).stream().sorted(Comparator.reverseOrder()).collect(Collectors.toList());
        System.out.println("topK=" + JSON.toJSONString(topKOrdered));
    }
}

你可能感兴趣的:(Spring,开发经验分享)