2015-09-06 97 views
0

我有一個應用程序,帶有一個大型的spring上下文,它載入了許多開發人員編寫的大量bean。
某些bean可能會對其初始化代碼執行一些重要的處理,這可能需要很長時間。
我正在尋找一種簡單的方法來獲取每個bean的加載時間。
由於軟件運行在大量客戶的計算機上,我需要一種方法在日誌中輕鬆找到瓶頸瓶頸。
如果我可以註冊一些事件,比如「加載bean之前」,之後會很棒。
所以,如果我能得到這個數據有問題,我可以寫的東西,如:獲取spring beans初始化時間

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

這就是爲什麼啓用日誌記錄或profilng是不夠的。

回答

0

要查找Java代碼中的性能瓶頸,請使用事件探查器

分析器將測量每個正在分析的方法所花費的時間,無論是在方法本身中,還是方法總數以及每次調用的時間。通常,在類或包級別啓用分析,例如如果代碼位於com.example包或子包中,則指定該代碼,並且該概要文件將監視您的代碼,而不會浪費時間監視Spring代碼和Java運行時庫。

取決於您的IDE,它可能已經內置或可能作爲擴展/插件提供。

更新

掛接到春季容器豆實例化過程中,BeanPostProcessor可以是溶液。被引用的描述包括以下內容:

[...]用於由容器創建的每個bean實例,後處理器從容器得到一個回調既之前容器初始化方法(如的InitializingBean的afterPropertiesSet()和任何聲明的init方法)以及之後調用的任何bean初始化回調函數。後處理器可以對bean實例執行任何操作,包括完全忽略回調。

+0

感謝您的回答,但分析並不能解決我的問題(請參閱更新後的問題) –

+0

因此,您說您沒有可配置的QA環境?由於您正在討論初始化時間,因此您不需要實際的應用程序負載,因此QA環境中的值與實際生產環境類似,但當然CPU性能除外,但相對您可以識別有問題的豆子。 – Andreas

+0

由於bean執行的初始化設置特定,它們的性能可能會根據不同的設置而改變。當然,我們正在使用分析來識別許多問題,但我正在尋找額外的工具來識別問題。 –

0

不知道我的解決方案是否會幫助你,但這是我做的,因爲我需要類似的東西。

首先,我們需要記錄兩件事情,實例化時間和初始化時間。首先我使用%d {mm:ss,SSS}%m%n作爲模式(僅限時間和消息)爲包「org.springframework.beans.factory」啓用日誌記錄。 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配置中使用文件appender。然後我寫了一個簡單的代碼來分析這些信息,並得到每個事物milisecond,總結他們:

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 

希望這有助於你儘可能多地幫助了我。