深入理解Spring IOC(六)、 bean的填充以及初始化工作(下)

简介: 深入理解Spring IOC(六)、 bean的填充以及初始化工作(下)

代码块3中3处


到了3.3这里,spring已经知道了bean的哪个属性需要注入,并且注入的值已经拿到,我们来看看这里的代码:


代码块6
protected void applyPropertyValues(String beanName, BeanDefinition mbd, BeanWrapper bw, PropertyValues pvs) {
  // 如果pvs为空过直接返回
  if (pvs == null || pvs.isEmpty()) {
    return;
  }
  MutablePropertyValues mpvs = null;
  List<PropertyValue> original;
  if (System.getSecurityManager() != null) {
    if (bw instanceof BeanWrapperImpl) {
      ((BeanWrapperImpl) bw).setSecurityContext(getAccessControlContext());
    }
  }
  if (pvs instanceof MutablePropertyValues) {
    mpvs = (MutablePropertyValues) pvs;
    // 如果mpvs的属性值已经被转换成为对应的类型,则可以直接去设置
    if (mpvs.isConverted()) {
      try {
        // 这里也是为什么使用BeanWrapper而不是使用beanInstance的原因
        // 因为BeanWrapper实现了PropertyAccessor接口,可以直接给set值
        // 这块有兴趣的可以自行研究一下
        bw.setPropertyValues(mpvs);
        return;
      }catch (BeansException ex) {
        throw new BeanCreationException(
            mbd.getResourceDescription(), beanName, "Error setting property values", ex);
      }
    }
    original = mpvs.getPropertyValueList();
  }else {
    // 获取原始的属性
    original = Arrays.asList(pvs.getPropertyValues());
  }
  TypeConverter converter = getCustomTypeConverter();
  if (converter == null) {
    converter = bw;
  }
  // 获取解析器
  BeanDefinitionValueResolver valueResolver = new BeanDefinitionValueResolver(this, beanName, mbd, converter);
  // 对原始属性进行深拷贝,避免修改后引起的原始属性值修改
  // deepcopy是后边直接用作给bean填充属性的
  List<PropertyValue> deepCopy = new ArrayList<PropertyValue>(original.size());
  boolean resolveNecessary = false;
  for (PropertyValue pv : original) {
    // 如果某个属性被转换过则直接加入deepCopy
    if (pv.isConverted()) {
      deepCopy.add(pv);
    // 否则的话进行转换
    }else {
      // 拿到原始属性值和属性名称
      String propertyName = pv.getName();
      Object originalValue = pv.getValue();
      // 并进行解析,并进行必要的解析
      Object resolvedValue = valueResolver.resolveValueIfNecessary(pv, originalValue);
      Object convertedValue = resolvedValue;
      // propertyName对应的属性是个可以写的 && 不能是嵌套属性或者下标属性
      boolean convertible = bw.isWritableProperty(propertyName) &&
          !PropertyAccessorUtils.isNestedOrIndexedProperty(propertyName);
      if (convertible) {
        convertedValue = convertForProperty(resolvedValue, propertyName, bw, converter);
      }
      // 将转换过的值存起来避免重新转换
      if (resolvedValue == originalValue) {
        if (convertible) {
          pv.setConvertedValue(convertedValue);
        }
        deepCopy.add(pv);
      }else if (convertible && originalValue instanceof TypedStringValue &&
          !((TypedStringValue) originalValue).isDynamic() &&
          !(convertedValue instanceof Collection || ObjectUtils.isArray(convertedValue))) {
        pv.setConvertedValue(convertedValue);
        deepCopy.add(pv);
      }else {
        resolveNecessary = true;
        deepCopy.add(new PropertyValue(pv, convertedValue));
      }
    }
  }
  // 将converted设置为true
  if (mpvs != null && !resolveNecessary) {
    mpvs.setConverted();
  }
  // 用deepCopy里的值来进行属性填充
  try {
    bw.setPropertyValues(new MutablePropertyValues(deepCopy));
  }catch (BeansException ex) {
    throw new BeanCreationException(
        mbd.getResourceDescription(), beanName, "Error setting property values", ex);
  }
}


这下doCreateBean中对bean的填充也完了,其实对bean的工作都是在BeanPostProcessor中完成的,在populateBean这个方法中只是对BeanPostProcessor的方法进行了调用而已。我们继续看1.4处,这个方法主要是针对bean的初始化的。


代码块1中4处


代码块7
protected Object initializeBean(final String beanName, final Object bean, RootBeanDefinition mbd) {
    // 调用几个Aware接口
    if (System.getSecurityManager() != null) {
      AccessController.doPrivileged(new PrivilegedAction<Object>() {
        @Override
        public Object run() {
          // 1.调用aware
          invokeAwareMethods(beanName, bean);
          return null;
        }
      }, getAccessControlContext());
    }
    else {
      invokeAwareMethods(beanName, bean);
    }
    // 2.调用所有的BeanPostProcessor的postProcessBeforeInitialization
    Object wrappedBean = bean;
    if (mbd == null || !mbd.isSynthetic()) {
      wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
    }
    try {
      // 3.调用InitializingBean的方法和自定义初始化方法
      invokeInitMethods(beanName, wrappedBean, mbd);
    }catch (Throwable ex) {
      throw new BeanCreationException(
          (mbd != null ? mbd.getResourceDescription() : null),
          beanName, "Invocation of init method failed", ex);
    }
    // 4.执行所有BeanPostProcessor的postProcessAfterInitialization方法
    if (mbd == null || !mbd.isSynthetic()) {
      wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
    }
    return wrappedBean;
  }


第1处主要是调用aware接口,aware接口我也会去写文章专门介绍,我们这会先来看这个方法做了什么:


代码块7中1处


代码块8
private void invokeAwareMethods(final String beanName, final Object bean) {
  // 所谓的xxxAware,就是让这个bean和xxx产生关联
  if (bean instanceof Aware) {
    // 设置名称
    if (bean instanceof BeanNameAware) {
      ((BeanNameAware) bean).setBeanName(beanName);
    }
    // 类加载器
    if (bean instanceof BeanClassLoaderAware) {
      ((BeanClassLoaderAware) bean).setBeanClassLoader(getBeanClassLoader());
    }
    // 我们有时候使用BeanFactoryAware去拿BeanFactory,就是在这步设置的
    if (bean instanceof BeanFactoryAware) {
      ((BeanFactoryAware) bean).setBeanFactory(AbstractAutowireCapableBeanFactory.this);
    }
  }
}


代码块7中2处


代码块9
public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName)
      throws BeansException {
  Object result = existingBean;
  // 调用所有的BeanPostProcessor的postProcessBeforeInitialization(前置处理)方法
  // 其中@PostConstruct就是在CommonAnnotationBeanPostProcessor中执行的
  for (BeanPostProcessor beanProcessor : getBeanPostProcessors()) {
    result = beanProcessor.postProcessBeforeInitialization(result, beanName);
    if (result == null) {
      return result;
    }
  }
  return result;
}


代码块7中3处

这个方法主要是执行初始化方法,主要执行@InitialBean中的初始化方法和自定义的初始化方法:


代码块10
protected void invokeInitMethods(String beanName, final Object bean, RootBeanDefinition mbd)
      throws Throwable {
  // 调用InitializingBean的afterPropertiesSet方法,还是特权调用和普通调用
  boolean isInitializingBean = (bean instanceof InitializingBean);
  if (isInitializingBean && (mbd == null || !mbd.isExternallyManagedInitMethod("afterPropertiesSet"))) {
    if (logger.isDebugEnabled()) {
      logger.debug("Invoking afterPropertiesSet() on bean with name '" + beanName + "'");
    }
    if (System.getSecurityManager() != null) {
      try {
        AccessController.doPrivileged(new PrivilegedExceptionAction<Object>() {
          @Override
          public Object run() throws Exception {
            // 
            ((InitializingBean) bean).afterPropertiesSet();
            return null;
          }
        }, getAccessControlContext());
      }
      catch (PrivilegedActionException pae) {
        throw pae.getException();
      }
    }
    else {
      ((InitializingBean) bean).afterPropertiesSet();
    }
  }
  if (mbd != null) {
    String initMethodName = mbd.getInitMethodName();
    if (initMethodName != null && !(isInitializingBean && "afterPropertiesSet".equals(initMethodName)) &&
        !mbd.isExternallyManagedInitMethod(initMethodName)) {
      // 调用自定义的初始化方法,主要是通过反射调用
      invokeCustomInitMethod(beanName, bean, mbd);
    }
  }
}


代码块7中4处


这个方法也是初始化的最后一步


代码块11
public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
      throws BeansException {
  // 执行所有BeanPostProcessor的postProcessAfterInitialization(后置处理)方法
  Object result = existingBean;
  // 遍历执行
  for (BeanPostProcessor beanProcessor : getBeanPostProcessors()) {
    result = beanProcessor.postProcessAfterInitialization(result, beanName);
    if (result == null) {
      return result;
    }
  }
  return result;
}


至此,xml中bean的加载解析我们已经讲完,下一篇,我们将对整个流程做个总结,以及扩充一些面试涉及到的点,以让你更好的理解bean加载的整个流程。

目录
相关文章
|
14天前
|
缓存 Java 数据库连接
Spring Boot奇迹时刻:@PostConstruct注解如何成为应用初始化的关键先生?
【8月更文挑战第29天】作为一名Java开发工程师,我一直对Spring Boot的便捷性和灵活性着迷。本文将深入探讨@PostConstruct注解在Spring Boot中的应用场景,展示其在资源加载、数据初始化及第三方库初始化等方面的作用。
42 0
|
27天前
|
XML Java 数据格式
Spring5入门到实战------8、IOC容器-Bean管理注解方式
这篇文章详细介绍了Spring5框架中使用注解进行Bean管理的方法,包括创建Bean的注解、自动装配和属性注入的注解,以及如何用配置类替代XML配置文件实现完全注解开发。
Spring5入门到实战------8、IOC容器-Bean管理注解方式
|
20天前
|
Java Spring
|
21天前
|
前端开发 Java 开发者
|
21天前
|
缓存 Java Maven
Java本地高性能缓存实践问题之SpringBoot中引入Caffeine作为缓存库的问题如何解决
Java本地高性能缓存实践问题之SpringBoot中引入Caffeine作为缓存库的问题如何解决
|
2月前
|
Java 测试技术 数据库
Spring Boot中的项目属性配置
本节课主要讲解了 Spring Boot 中如何在业务代码中读取相关配置,包括单一配置和多个配置项,在微服务中,这种情况非常常见,往往会有很多其他微服务需要调用,所以封装一个配置类来接收这些配置是个很好的处理方式。除此之外,例如数据库相关的连接参数等等,也可以放到一个配置类中,其他遇到类似的场景,都可以这么处理。最后介绍了开发环境和生产环境配置的快速切换方式,省去了项目部署时,诸多配置信息的修改。
|
2月前
|
Java 应用服务中间件 开发者
Java面试题:解释Spring Boot的优势及其自动配置原理
Java面试题:解释Spring Boot的优势及其自动配置原理
95 0
|
14天前
|
缓存 Java 数据库连接
Spring Boot 资源文件属性配置,紧跟技术热点,为你的应用注入灵动活力!
【8月更文挑战第29天】在Spring Boot开发中,资源文件属性配置至关重要,它让开发者能灵活定制应用行为而不改动代码,极大提升了可维护性和扩展性。Spring Boot支持多种配置文件类型,如`application.properties`和`application.yml`,分别位于项目的resources目录下。`.properties`文件采用键值对形式,而`yml`文件则具有更清晰的层次结构,适合复杂配置。此外,Spring Boot还支持占位符引用和其他外部来源的属性值,便于不同环境下覆盖默认配置。通过合理配置,应用能快速适应各种环境与需求变化。
26 0
|
1月前
|
XML Java 数据库连接
Spring Boot集成MyBatis
主要系统的讲解了 Spring Boot 集成 MyBatis 的过程,分为基于 xml 形式和基于注解的形式来讲解,通过实际配置手把手讲解了 Spring Boot 中 MyBatis 的使用方式,并针对注解方式,讲解了常见的问题已经解决方式,有很强的实战意义。在实际项目中,建议根据实际情况来确定使用哪种方式,一般 xml 和注解都在用。
|
2月前
|
Java Spring 容器
Spring Boot 启动源码解析结合Spring Bean生命周期分析
Spring Boot 启动源码解析结合Spring Bean生命周期分析
78 11