Java应用启动优化

1,326 阅读2分钟

Java应用在启动的时候需要做大量的编译工作,如果应用依赖了Spring,因为其IOC的特性会提前加载运行时所需的各种Bean,随着项目变的复杂,里面的Bean也越来越多...

其中带来一个新的问题就是项目每次启动非常慢: 见过比较慢的应用启动一次要30分钟,一个下午发布几次代码时间就没了。 就算是自己应用,写了两年之后,发现每次启动也需要个5~10分钟的时间,这种启动速度会极大的降低开发的效率。

如何优化应用的启动时间?

找出最耗时的Bean有哪些

通过Spring的BeanPostProcessor接口可以统计到每个Bean的初始化耗时时长。

@Service
@Slf4j
public class BeanInitMetrics implements BeanPostProcessor {

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

    //private Map<String,Integer> metrics = new HashMap<>();


    private List<Metric> metrics = new ArrayList<>();

    @Data
    static class Metric{

        public Metric() {
        }

        public Metric(String name, Integer value) {
            this.name = name;
            this.value = value;
            this.createDate = new Date();
        }

        private String name;

        private Integer value;

        private Date createDate;
    }

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

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        Long start = stats.get(beanName);
        if (start != null) {
            metrics.add(new Metric(beanName, Math.toIntExact(System.currentTimeMillis() - start)));
        }
        return bean;
    }

    public List<Metric> getMetrics() {
        metrics.sort((o1, o2) -> {
            try {
                return o2.getValue() - o1.getValue();
            }catch (Exception e){
                return 0;
            }
        });
        log.info("metrics {}", JSON.toJSONString(metrics));
        return UnmodifiableList.unmodifiableList(metrics);
    }

}

分类优化

中间件优化

  • 配置一些中间件的超时时长;开发环境、预发环境超时时长设置短一点;
  • 考虑升级一些中间件版本:Tomcat,Spring,JDK等
  • 中间件一般属于应用的最底层,判断能否进行并行优化;

StackOverFlow上有人给出了一些参考方式:stackoverflow.com/questions/6…

应用层历史包袱

  • Maven的分析有哪些包没有被使用,排除掉这些Jar包:maven.apache.org/shared/mave…
  • 代码中一些已经迁移到其他应用中的业务,有些已经迁移了但是还遗留了大量的代码,这种在开发环境下都可以先进行排除

应用层其它优化

  • 一些Bean考虑是否可以懒加载
  • 一些引入的重量级Bean预加载范围过大,设置下业务范围; 有些富客户端的Client在启动的时候会预加载需要的配置,有些配置量非常的大,一个Bean的启动都需要几分钟的时间,对这种Client考虑可以配置范围预加载,只提前加载自己业务下的配置。

其它优化

  • 使用热部署...
  • 不要依赖Snapshot包
  • 编译优化:Maven并行编译

实践结果

有效的动作:

1、真正导致应用启动耗时久的主要是前几十个Bean,主要原因一般是预加载内容多,或者线程池,或者IO。
2、容器支持一些配置参数,开启异步,禁止一些启动分析等。

项目从5~10分钟的启动时间缩短到3分钟启动;以上是启动优化的一点经验,希望能对读者有所启发。