Java项目启动时间过长的问题

Published on
75 5~7 min

问题描述:

项目启动缓慢,且中间有部分时间出现日志打印卡住的情况,极大的影响本地调试的效率

原因总结:

项目中引用了jOOQ ,导致@execution的aspectj扫描大量的实例和方法,影响项目启动速度

修改方式:

在不影响切面功能的基础上,用within代替execution,目前排查下来的只有一个针对所有controller的切面使用到了,修改掉项目启动速度由150s降到98s左右

参考:jOOQ,spring-boot and aop. · Issue #5902 · jOOQ/jOOQ (github.com)

排查过程

  1. 查看启动时的打印日志,确定下项目启动时缓慢的时间段

  2. 使用 BeanPostProcessor获取启动时加载时间大于1s的bean对象

  3. 逐步排查到dslContext的加载速度比较缓慢,直接从网上查询到相似问题,使用对应解决方案,over

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Component;

import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;

@Component
@Configuration
@Slf4j
public class BeanCostTimePostProcessor implements BeanPostProcessor {

    /**
     * 项目启动时会执行此方法 实现了BeanPostProcessor接口,充当钩子函数,记录bean加载的时间
     */
    private static final ConcurrentHashMap<String,Long> TIME_MAP = new ConcurrentHashMap<>();



    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        TIME_MAP.put(beanName,System.currentTimeMillis());
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {

        Long time = TIME_MAP.get(beanName);

        if (Objects.nonNull(time)){
            long end = System.currentTimeMillis();
            long cost = end - time;
            if (cost > 1000L) {
                log.info("=======================slow beanName:{} class path :{} , cost :{}", beanName, bean.getClass().getName(), cost);
            }
        }

        return bean;
    }

}