当前位置 : 主页 > 编程语言 > 其它开发 >

Spring 源码(17)Spring Bean的创建过程(8)Bean的初始化

来源:互联网 收集:自由互联 发布时间:2022-05-22
知识回顾 Bean 的创建过程会经历 getBean , doGetBean , createBean , doCreateBean ,然后 Bean 的创建又会经历实例化,属性填充,初始化。 在实例化 createInstance 时大致可以分为三种方式进行实
知识回顾

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中。

【文章原创作者:香港云服务器 http://www.558idc.com/ne.html 复制请保留原URL】
网友评论