<menu id="guoca"></menu>
<nav id="guoca"></nav><xmp id="guoca">
  • <xmp id="guoca">
  • <nav id="guoca"><code id="guoca"></code></nav>
  • <nav id="guoca"><code id="guoca"></code></nav>

    Spring容器啟動耗時分析 (Bean啟動耗時)

    VSole2022-04-23 15:05:46

    spring bean 的生命周期

    • 實例化(instantiate), 用構造器創建一個對象
    • 字段賦值(populate)
    • 初始化(initialize), 執行bean配置里的init方法或者InitializingBean#afterPropertiesSet方法
    • 銷毀(destruct)

    實例化和字段賦值一般都很快,但是一些重型的bean被IOC容器創建時,需要調用遠程服務或者執行耗時的操作,這些操作往往在init方法里實現。統計bean初始化耗時可以發現那些bean影響了系統的啟動效率。業務方的bean可以推動業務優化,自己的bean也可以想方法優化性能。

    那么如何統計初始化的耗時呢?

    spring bean初始化源碼分析

    org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#initializeBean 觀察執行初始化方法的邏輯

    protected Object initializeBean(final String beanName, final Object bean, RootBeanDefinition mbd) {
     if (System.getSecurityManager() != null) {
      AccessController.doPrivileged(new PrivilegedAction() {
       @Override
       public Object run() {
        invokeAwareMethods(beanName, bean);
        return null;
       }
      }, getAccessControlContext());
     }
     else {
      invokeAwareMethods(beanName, bean);
     }
    
     Object wrappedBean = bean;
     if (mbd == null || !mbd.isSynthetic()) {
      // 初始化前spring提供的系統鉤子
      wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
     }
    
     try {
      // 執行初始化方法
      invokeInitMethods(beanName, wrappedBean, mbd);
     }
     catch (Throwable ex) {
      throw new BeanCreationException(
        (mbd != null ? mbd.getResourceDescription() : null),
        beanName, "Invocation of init method failed", ex);
     }
     if (mbd == null || !mbd.isSynthetic()) {
      // 初始化后spring提供的系統鉤子
      wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
     }
     return wrappedBean;
    }
    applyBeanPostProcessorsBeforeInitialization做了什么?
    取出所有實現BeanPostProcessor的bean,逐個執行一遍postProcessBeforeInitialization方法。
    同理,applyBeanPostProcessorsAfterInitialization邏輯依然,只是執行的是postProcessInitialization方法。
    @Override
    public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName)
      throws BeansException {
    
     Object result = existingBean;
     for (BeanPostProcessor beanProcessor : getBeanPostProcessors()) {
      result = beanProcessor.postProcessBeforeInitialization(result, beanName);
      if (result == null) {
       return result;
      }
     }
     return result;
    spring系統鉤子 BeanPostProcessor
    Factory hook that allows for custom modification of new bean instances, e.g. checking for marker interfaces or wrapping them with proxies.
    ApplicationContexts can autodetect BeanPostProcessor beans in their bean definitions and apply them to any beans subsequently created. Plain bean factories allow for programmatic registration of post-processors, applying to all beans created through this factory
    BeanPostProcessor接口僅僅提供兩個方法,用在在初始化bean的時候進行定制開發。
    public interface BeanPostProcessor {
    
     Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException;
    
     Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException;
    
    }
    
    


    bean初始化耗時功能開發demo
    簡單demo
    package org.dubbo.server.service.tool;
    
    import com.google.common.collect.Maps;
    import org.springframework.beans.BeansException;
    import org.springframework.beans.factory.config.BeanPostProcessor;
    import org.springframework.stereotype.Component;
    
    import java.util.Map;
    
    /**
     * @author LvSheng
     **/
    @Component
    public class TimeCostBeanPostProcessor implements BeanPostProcessor {
     
     Map costMap = Maps.newConcurrentMap();
     
     @Override
     public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
      costMap.put(beanName, System.currentTimeMillis());
      return bean;
     }
     
     @Override
     public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
      long start = costMap.get(beanName);
      long cost  = System.currentTimeMillis() - start;
      if (cost > 0) {
       costMap.put(beanName, cost);
       System.out.println("class: " + bean.getClass().getName()
                + "\tbean: " + beanName
                + "\ttime" + cost);
      }
      return bean;
     }
    }
    推薦
    主流Java進階技術(學習資料分享)
    Java面試題寶典
    加入Spring技術開發社區
    
    


    PS:因為公眾號平臺更改了推送規則,如果不想錯過內容,記得讀完點一下“在看”,加個“星標”,這樣每次新文章推送才會第一時間出現在你的訂閱列表里。點“在看”支持我們吧!
    
    初始化bean
    本作品采用《CC 協議》,轉載必須注明作者和本文鏈接
    spring bean 的生命周期 實例化(instantiate), 用構造器創建一個對象 字段賦值(populate) 初始化(initialize), 執行bean配置里的init方法或者InitializingBean#afterPropertiesSet方法 銷毀(destruct) 實例化和字段賦值一般都很快,但是一些重型的bean被IOC容器創建時,需要調用遠程服務或者執行耗時的操
    Springboot更是封裝了Spring,遵循約定大于配置,加上自動裝配的機制。讓使用者以最小的代價接入。當然了解了bean的各個生命周期也能促進我們加深對spring的理解。在網上搜索spring擴展點,發現很少有博文說的很全的,只有一些常用的擴展點的說明。并且整理出了一個bean在spring內部從被加載到最后初始化完成所有可擴展點的順序調用圖。這個點允許被用戶自己擴展。用戶可以在整個spring容器還沒被初始化之前做一些事情。
    Spring MVC和Spring WebFlux都通過RquestMappingHandlerMapping和RequestMappingHndlerAdapter兩個類來提供對@RequestMapping注解的支持。
    以下兩個工具方式的差別是,前者在獲取失敗時拋出異常。然后在代碼中就可以獲取spring容器bean了。
    所以,這就要求Spring事務能支持上面各種場景,這就是Spring事務傳播機制的由來。
    spring-boot下的thymeleaf模板注入挺有趣的,本文嘗試對該漏洞一探究竟,如有謬誤,還請同學們指教。
    收集內存馬打入方式
    2023-05-29 09:42:33
    收集內存馬打入方式
    S2-007的漏洞原理是在處理類型轉換的錯誤時會存入錯誤到內存中,在后續調用流程中觸發OGNL表達式注入。
    前言在前面的一章中,主要在理論上進行了各種內存馬的實現,這里就做為上一篇的補充,自己搭建反序列化的漏洞環境來進行上文中理論上內存馬的注入實踐。這是內存馬系列文章的第十四篇。在/unser路由中獲取了請求體輸入流進行了反序列化調用。在debug過程中,發現是因為不能夠找到他的構造方法而報錯,更改后的注入方式。
    fastjson反序列化已經是近幾年繼Struts2漏洞后,最受安全人員歡迎而開發人員抱怨的一個漏洞了。
    VSole
    網絡安全專家
      亚洲 欧美 自拍 唯美 另类