Spring 原始碼(17)Spring Bean的建立過程(8)Bean的初始化

玲丶蹊發表於2022-05-21

知識回顧

Bean的建立過程會經歷getBeandoGetBeancreateBeandoCreateBean,然後Bean的建立又會經歷例項化,屬性填充,初始化。

在例項化createInstance時大致可以分為三種方式進行例項化:

  • 使用Supplier 進行例項化,通過BeanFactoryPostProcessorBeanDefinition進行修改,增加一個Supplier屬性,放置一個lambda表示式用於建立物件
  • 使用factory-method進行例項化
    • 使用例項工廠例項化
    • 使用靜態工廠例項化
  • 使用構造器反射進行例項化
    • 使用SmartInstantiationAwareBeanPostProcessor解析構造器,然後反射例項化
    • 使用無參構造器進行例項化

在屬性填充populateBean時大致可以分為4個步驟:

  • 呼叫InstantiationAwareBeanPostProcessor介面的after方法修改Bean的資訊
  • 自動裝配,將解析的屬性和屬性值放入到pvs變數中
    • autowireByType自動裝配
    • autowireByName自動裝配
  • 執行通過CommonAnnotationBeanPostProcessorAtowiredAnnotationBeanPostProcessor解析的註解,然後注入到欄位上
  • 對屬性的值進行解析,解析pvs, 會涉及到引數轉換,spel表示式解析,引用型別,String型別,List型別,Map型別,Set型別,Properties型別的解析,屬性編輯器的解析等。

接下來解讀初始化階段

bean的初始化

bean的初始化initializeBean方法,直接上原始碼:

protected Object initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd) {
  if (System.getSecurityManager() != null) {
    AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
      invokeAwareMethods(beanName, bean);
      return null;
    }, getAccessControlContext());
  }
  else {
    // 執行Aware 方法
    invokeAwareMethods(beanName, bean);
  }

  Object wrappedBean = bean;
  if (mbd == null || !mbd.isSynthetic()) {
    // 執行 BeanPostProcessor before 介面
    wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
  }

  try {
    // 執行 init-method 方法
    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()) {
    // 執行BeanPostProcessor after 方法
    wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
  }

  return wrappedBean;
}

原始碼邏輯也很簡單,大概就分成了4步:

  • 執行Aware介面的方法invokeAwareMethods
  • 執行BeanPostProcessor#postProcessBeforeInitialization
  • 執行初始化方法
  • 執行BeanPostProcessor#postProcessAfterInitialization

執行Aware介面的方法

點進去:

private void invokeAwareMethods(String beanName, Object bean) {
  if (bean instanceof Aware) {
    // 執行BeanNameAware
    if (bean instanceof BeanNameAware) {
      ((BeanNameAware) bean).setBeanName(beanName);
    }
    // 執行BeanClassLoaderAware
    if (bean instanceof BeanClassLoaderAware) {
      ClassLoader bcl = getBeanClassLoader();
      if (bcl != null) {
        ((BeanClassLoaderAware) bean).setBeanClassLoader(bcl);
      }
    }
    // 執行BeanFactoryAware
    if (bean instanceof BeanFactoryAware) {
      ((BeanFactoryAware) bean).setBeanFactory(AbstractAutowireCapableBeanFactory.this);
    }
  }
}

這裡只執行了3個介面的方法,BeanNameAwareBeanClassLoaderAwreBeanFactoryAware,在Spring容器中不止這些Aware介面,這裡為什麼只執行了三個Aware介面?

Spring容器BeanFactory構造時,對這三個介面進行了忽略:

public AbstractAutowireCapableBeanFactory() {
  super();
  ignoreDependencyInterface(BeanNameAware.class);
  ignoreDependencyInterface(BeanFactoryAware.class);
  ignoreDependencyInterface(BeanClassLoaderAware.class);
}

所以這裡只執行了這三個Aware介面,這裡忽略,實際上就是不然這些屬性通過自動裝配設定屬性值,而是通過Spring自己的回撥進行設定值。

另外我們在開始的準備BeanFactory的時候又進行了忽略Aware介面:

beanFactory.ignoreDependencyInterface(EnvironmentAware.class);
beanFactory.ignoreDependencyInterface(EmbeddedValueResolverAware.class);
beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);
beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);
beanFactory.ignoreDependencyInterface(MessageSourceAware.class);
beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);

這6個介面在哪裡執行的呢?在BeanFactory準備階段註冊了一個BeanPostProcessor的實現叫ApplicationContextAwareProcessor類,這個類的before方法中就進行了呼叫:

public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
  if (!(bean instanceof EnvironmentAware || bean instanceof EmbeddedValueResolverAware ||
        bean instanceof ResourceLoaderAware || bean instanceof ApplicationEventPublisherAware ||
        bean instanceof MessageSourceAware || bean instanceof ApplicationContextAware)){
    return bean;
  }
  AccessControlContext acc = null;
  if (System.getSecurityManager() != null) {
    acc = this.applicationContext.getBeanFactory().getAccessControlContext();
  }
  if (acc != null) {
    AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
      invokeAwareInterfaces(bean);
      return null;
    }, acc);
  }
  else {
    // 執行Aware介面
    invokeAwareInterfaces(bean);
  }

  return bean;
}


private void invokeAwareInterfaces(Object bean) {
  if (bean instanceof EnvironmentAware) {
    ((EnvironmentAware) bean).setEnvironment(this.applicationContext.getEnvironment());
  }
  if (bean instanceof EmbeddedValueResolverAware) {
    ((EmbeddedValueResolverAware) bean).setEmbeddedValueResolver(this.embeddedValueResolver);
  }
  if (bean instanceof ResourceLoaderAware) {
    ((ResourceLoaderAware) bean).setResourceLoader(this.applicationContext);
  }
  if (bean instanceof ApplicationEventPublisherAware) {
    ((ApplicationEventPublisherAware) bean).setApplicationEventPublisher(this.applicationContext);
  }
  if (bean instanceof MessageSourceAware) {
    ((MessageSourceAware) bean).setMessageSource(this.applicationContext);
  }
  if (bean instanceof ApplicationContextAware) {
    ((ApplicationContextAware) bean).setApplicationContext(this.applicationContext);
  }
}

為什麼要分開處理呢?

個人認為主要是做了個區分而已,前面三個介面輸入BeanFactory範疇,而這6個介面屬於ApplicationContext範疇,只是進行了歸類處理而已。

執行BPP的Before方法

程式碼比較簡單,就是迴圈的執行了BPPbefore介面,這裡在執行的時候,實現上也執行了在Bean進行merge的時候解析的@PostConstruct註解。

public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
  LifecycleMetadata metadata = findLifecycleMetadata(bean.getClass());
  try {
    // 執行初始化方法
    metadata.invokeInitMethods(bean, beanName);
  }
  catch (InvocationTargetException ex) {
    throw new BeanCreationException(beanName, "Invocation of init method failed", ex.getTargetException());
  }
  catch (Throwable ex) {
    throw new BeanCreationException(beanName, "Failed to invoke init method", ex);
  }
  return bean;
}

這個方法的實現類為InitDestroyAnnotationBeanPostProcessor

執行初始化方法

執行初始化方法的時候,會分為兩步,一個是執行InitializingBeanafterPropertiesSet方法,另一個是執行自定義的init-method方法

protected void invokeInitMethods(String beanName, Object bean, @Nullable RootBeanDefinition mbd)
  throws Throwable {
  // 判斷當前Bean是否是實現了InitializingBean
  boolean isInitializingBean = (bean instanceof InitializingBean);
  if (isInitializingBean && (mbd == null || !mbd.isExternallyManagedInitMethod("afterPropertiesSet"))) {
    if (logger.isTraceEnabled()) {
      logger.trace("Invoking afterPropertiesSet() on bean with name '" + beanName + "'");
    }
    if (System.getSecurityManager() != null) {
      try {
        AccessController.doPrivileged((PrivilegedExceptionAction<Object>) () -> {
          ((InitializingBean) bean).afterPropertiesSet();
          return null;
        }, getAccessControlContext());
      }
      catch (PrivilegedActionException pae) {
        throw pae.getException();
      }
    }
    else {
      // 執行
      ((InitializingBean) bean).afterPropertiesSet();
    }
  }

  if (mbd != null && bean.getClass() != NullBean.class) {
    String initMethodName = mbd.getInitMethodName();
    if (StringUtils.hasLength(initMethodName) &&
        !(isInitializingBean && "afterPropertiesSet".equals(initMethodName)) &&
        !mbd.isExternallyManagedInitMethod(initMethodName)) {
      // 執行自定義的初始化方法
      invokeCustomInitMethod(beanName, bean, mbd);
    }
  }
}

執行BPP的after介面

BPP的after主要是用來實現AOP的,所以這裡簡單介紹下,迴圈執行after方法的呼叫。

原始碼:

public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
  throws BeansException {

  Object result = existingBean;
  for (BeanPostProcessor processor : getBeanPostProcessors()) {
    Object current = processor.postProcessAfterInitialization(result, beanName);
    if (current == null) {
      return result;
    }
    result = current;
  }
  return result;
}

原始碼比較簡單,就迴圈執行了方法的呼叫。

初始化就解讀完了,SpringBean的建立也基本講完,最終建立出來的Bean物件就會放入到一級快取singletonObjects中。

相關文章