Spring容器启动耗时过长, 主要原因是有些Bean做了复杂初始化的工作.
找到这些Bean, 再做针对性的优化, 才能把Spring容器启动耗时降下来.
如果开发对应用代码还不太熟悉, 本文提供了一种方式, 快速找出这些启动非常耗时的Bean.
- LaunchTimeBeanPostProcessor.java (Bean启动时间抓取)
import org.springframework.beans.BeansException; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.config.BeanPostProcessor; import org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessor; import org.springframework.beans.factory.support.MergedBeanDefinitionPostProcessor; import org.springframework.beans.factory.support.RootBeanDefinition; import org.springframework.stereotype.Component; @Component public class LaunchTimeBeanPostProcessor implements BeanPostProcessor, InstantiationAwareBeanPostProcessor, MergedBeanDefinitionPostProcessor { @Autowired private LaunchTimeManager launchInfoManager; @Override public Object postProcessBeforeInstantiation(Class> beanClass, String beanName) throws BeansException { launchInfoManager.beanStart(beanName, System.currentTimeMillis()); return null; } @Override public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException { return true; } @Override public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { return bean; } @Override public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { launchInfoManager.beanEnd(beanName, System.currentTimeMillis()); return bean; } @Override public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class> beanType, String beanName) { // ignore } }
- LaunchTimeManager.java (Bean启动时间管理器)
import org.springframework.context.ApplicationListener; import org.springframework.context.event.ContextRefreshedEvent; import org.springframework.stereotype.Component; import java.util.Map; import java.util.Objects; import java.util.concurrent.ConcurrentHashMap; @Component public class LaunchTimeManager implements ApplicationListener3. 原理{ private Map launchTimeMap = new ConcurrentHashMap<>(); public void beanStart(String beanName, Long startTime) { if (Objects.nonNull(launchTimeMap.get(beanName))) { System.out.printf("------------%s Bean重复启动 ???-------------n", beanName); return; } LaunchTime launchTime = new LaunchTime(); launchTime.setBeanName(beanName); launchTime.setStartTime(startTime); launchTimeMap.putIfAbsent(beanName, launchTime); } public void beanEnd(String beanName, Long endTime) { if (Objects.isNull(launchTimeMap.get(beanName))) { System.out.printf("------------%s Bean还未启动 ???-------------n", beanName); return; } launchTimeMap.computeIfPresent(beanName, (k, v) -> { v.setEndTime(endTime); return v; }); } @Override public void onApplicationEvent(ContextRefreshedEvent event) { System.out.println("Spring容器启动完成"); launchTimeMap.values().stream() .sorted((e1, e2) -> Long.valueOf(e2.getCostTime() - e1.getCostTime()).intValue()) .limit(10) .forEach(e -> { System.out.printf("启动耗时, beanName:%s, cost:%s n", e.getBeanName(), e.getCostTime()); }); } public static class LaunchTime { private String beanName; private Long startTime; private Long endTime; public String getBeanName() { return beanName; } public void setBeanName(String beanName) { this.beanName = beanName; } public Long getStartTime() { return startTime; } public void setStartTime(Long startTime) { this.startTime = startTime; } public Long getEndTime() { return endTime; } public void setEndTime(Long endTime) { this.endTime = endTime; } public Long getCostTime() { return endTime - startTime; } } }
Spring Bean 生命周期
- 控制台打印
- 测试代码
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)