有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java获取Springbeans初始化时间

我有一个具有大型spring上下文的应用程序,它加载了许多开发人员编写的许多bean
一些bean可能会对其初始化代码进行一些重要的处理,这可能需要很长时间
我正在寻找一种简单的方法来获得每个bean的加载时间
由于该软件在大量客户的机器上运行,我需要一种在日志中轻松找到瓶颈bean的方法
如果我能注册到诸如“加载bean之前”和“加载bean之后”之类的事件,那就太好了
因此,如果我能有问题地获得这些数据,我可以写下如下内容:

if (beanLoadingTime > 2 seconds) 
    print bean details and loading time to log file

这就是为什么启用日志记录或盈利功能是不够的


共 (2) 个答案

  1. # 1 楼答案

    要查找Java代码中的性能瓶颈,请使用探查器

    探查器将测量被探查的每个方法所花费的时间,包括方法本身以及方法加上它所做的每个调用的总时间。通常,在类或包级别启用评测,例如,如果您的代码在com.example包或子包中,您可以指定该选项,并且评测器将监视您的代码,而不会浪费时间监视Spring代码和Java运行时库

    根据您的IDE,它可能已经内置,或者可以作为扩展/插件提供

    更新

    为了钩住SpringContainers bean实例化过程,一个BeanPostProcessor可能是解决方案。参考说明包括以下内容:

    [...] for each bean instance that is created by the container, the post-processor gets a callback from the container both before container initialization methods (such as InitializingBean’s afterPropertiesSet() and any declared init method) are called as well as after any bean initialization callbacks. The post-processor can take any action with the bean instance, including ignoring the callback completely.

  2. # 2 楼答案

    我不知道我的解决方案是否对你有帮助,但这就是我所做的,因为我需要类似的东西

    首先,我们需要记录两件事,实例化时间和初始化时间。首先,我仅为包“org.springframework.beans.factory”启用日志记录,使用%d{mm:ss,SSS}%m%n作为模式(仅限时间和消息)。Spring记录如下消息:创建bean实例。。。并完成了bean实例的创建。。。对于第二件事,我按照this answer中的建议创建了一个LoggerBeanPostProcessor。代码是:

    public class LoggerBeanPostProcessor implements BeanPostProcessor, Ordered {
    
        protected Log logger = LogFactory.getLog("org.springframework.beans.factory.LoggerBeanPostProcessor");
        private Map<String, Long> start;
        private Map<String, Long> end;
    
        public LoggerBeanPostProcessor() {
            start = new HashMap<>();
            end = new HashMap<>();
        }
    
        @Override
        public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
            start.put(beanName, System.currentTimeMillis());
            return bean;
        }
    
        @Override
        public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
            end.put(beanName, System.currentTimeMillis());
            logger.debug("Init time for " + beanName + ": " + initializationTime(beanName));
            return bean;
        }
    
        @Override
        public int getOrder() {
            return Integer.MAX_VALUE;
        }
    
        // this method returns initialization time of the bean.
        public long initializationTime(String beanName) {
            return end.get(beanName) - start.get(beanName);
        }
    }
    

    我在log4j配置中使用一个文件追加器。然后,我编写了一个简单的代码来解析这些信息,并得到每件事情的毫秒数,然后对它们求和:

    public static void main(String[] argumentos) throws Exception{
            File file = new File("C:\\app\\daily.log");
            List<String> lines = FileUtils.readLines(file);
    
            Map<String,Long> start = new HashMap();
            Map<String,Long> end = new HashMap();
            Map<String,Long> init = new HashMap();
            List<String> beans = new ArrayList();
            int max = 0;
    
            for(String line :  lines) {
                String time = StringUtils.substring(line, 0, 9);
                String msg = StringUtils.substring(line, 10);
    
                if(msg.startsWith("Creating instance")) {
                    int fi = StringUtils.indexOf(msg, '\'') + 1;
                    int li = StringUtils.lastIndexOf(msg, '\'');
                    String bean = StringUtils.substring(msg, fi, li);
                    if(start.containsKey(bean)) {
                        continue;
                    }
                    start.put(bean, parseTime(time));
                    beans.add(bean);
                    max = Math.max(max, bean.length());
    
                } else if(msg.startsWith("Finished creating")) {
                    int fi = StringUtils.indexOf(msg, '\'') + 1;
                    int li = StringUtils.lastIndexOf(msg, '\'');
                    String bean = StringUtils.substring(msg, fi, li);
                    if(end.containsKey(bean)) {
                        continue;
                    }
                    end.put(bean, parseTime(time));
    
                } else if(msg.startsWith("Init time for")) {
                    int li = StringUtils.lastIndexOf(msg, ':');
                    String bean = StringUtils.substring(msg, 14, li);
                    if(init.containsKey(bean)) {
                        continue;
                    }
                    init.put(bean, Long.parseLong(StringUtils.substring(msg, li+2)));
                }
            }
    
            for(String bean : beans) {
                long s = start.get(bean);
                long e = end.get(bean);
                long i = init.containsKey(bean) ? init.get(bean) : -1;
                System.out.println(StringUtils.leftPad(bean, max) + ": " + StringUtils.leftPad(Long.toString((e-s)+i), 6, ' '));
            }
        }
    

    因此:

                                               splashScreen:    172
    org.springframework.aop.config.internalAutoProxyCreator:     31
                                    loggerBeanPostProcessor:   1137
                                                 appContext:   1122
    

    希望这对你和我都有帮助