【小家Spring】AbstractAutowireCapableBeanFactory#populateBean实现Bean的属性赋值和initializeBean对Bean的初始化(中)

本文涉及的产品
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
全局流量管理 GTM,标准版 1个月
云解析 DNS,旗舰版 1个月
简介: 【小家Spring】AbstractAutowireCapableBeanFactory#populateBean实现Bean的属性赋值和initializeBean对Bean的初始化(中)

AutowiredAnnotationBeanPostProcessor、CommonAnnotationBeanPostProcessor#postProcessPropertyValues实现注解给属性赋值:

从上面看到了,Bean已经解析拿到了注解的一些元信息,因此此处就调用一些处理器的postProcessPropertyValues方法,来给赋值了:


//AutowiredAnnotationBeanPostProcessor:这里就是解析该Bean的Autowired信息,然后给inject进去
  @Override
  public PropertyValues postProcessPropertyValues(
      PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeanCreationException {
    InjectionMetadata metadata = findAutowiringMetadata(beanName, bean.getClass(), pvs);
    try {
      metadata.inject(bean, beanName, pvs);
    } catch (BeanCreationException ex) {
      throw ex;
    } catch (Throwable ex) {
      throw new BeanCreationException(beanName, "Injection of autowired dependencies failed", ex);
    }
    return pvs;
  }
//CommonAnnotationBeanPostProcessor:逻辑和上面一毛一样,它处理的JSR-250的注解,比如@Resource
  @Override
  public PropertyValues postProcessPropertyValues(
      PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeansException {
    InjectionMetadata metadata = findResourceMetadata(beanName, bean.getClass(), pvs);
    try {
      metadata.inject(bean, beanName, pvs);
    } catch (Throwable ex) {
      throw new BeanCreationException(beanName, "Injection of resource dependencies failed", ex);
    }
    return pvs;
  }
//RequiredAnnotationBeanPostProcessor:它就是去校验,标注了@Required注解的,必须是是存在这个Bean的
  @Override
  public PropertyValues postProcessPropertyValues(
      PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeansException {
    if (!this.validatedBeanNames.contains(beanName)) {
      if (!shouldSkip(this.beanFactory, beanName)) {
        List<String> invalidProperties = new ArrayList<>();
        for (PropertyDescriptor pd : pds) {
          if (isRequiredProperty(pd) && !pvs.contains(pd.getName())) {
            invalidProperties.add(pd.getName());
          }
        }
        if (!invalidProperties.isEmpty()) {
          throw new BeanInitializationException(buildExceptionMessage(invalidProperties, beanName));
        }
      }
      this.validatedBeanNames.add(beanName);
    }
    return pvs;
  }


InjectionMetadata#inject处理依赖注入:


  public void inject(Object target, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
    Collection<InjectedElement> checkedElements = this.checkedElements;
    Collection<InjectedElement> elementsToIterate =
        (checkedElements != null ? checkedElements : this.injectedElements);
    if (!elementsToIterate.isEmpty()) {
      boolean debug = logger.isDebugEnabled();
      for (InjectedElement element : elementsToIterate) {
        if (debug) {
          logger.debug("Processing injected element of bean '" + beanName + "': " + element);
        }
        // 主要的方法,还是在InjectedElement#inject里
        element.inject(target, beanName, pvs);
      }
    }
  }


InjectedElement实现如下:


image.png


这里我们就以最常用的AutowiredFieldElement为例讲解(它是一个普通内部类,为private的):


    @Override
    protected void inject(Object bean, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
      // 拿到这个字段名
      Field field = (Field) this.member;
      Object value;
      // 大多数情况下,这里都是false
      if (this.cached) {
        value = resolvedCachedArgument(beanName, this.cachedFieldValue);
      } else {
        DependencyDescriptor desc = new DependencyDescriptor(field, this.required);
        desc.setContainingClass(bean.getClass());
        Set<String> autowiredBeanNames = new LinkedHashSet<>(1);
        Assert.state(beanFactory != null, "No BeanFactory available");
        // 转换器,没有手动注册,默认都是SimpleTypeConverter===============
        TypeConverter typeConverter = beanFactory.getTypeConverter();
        try {
          // 把当前bean所依赖的这个Bean解析出来(从Spring容器里面拿,或者别的地方获取吧~~~)
          value = beanFactory.resolveDependency(desc, beanName, autowiredBeanNames, typeConverter);
        } catch (BeansException ex) {
          throw new UnsatisfiedDependencyException(null, beanName, new InjectionPoint(field), ex);
        }
        synchronized (this) {
          if (!this.cached) {
            // 如果已经拿到了这个Bean实例,
            if (value != null || this.required) {
              this.cachedFieldValue = desc;
              // 把该Bean的依赖关系再注册一次
              registerDependentBeans(beanName, autowiredBeanNames);
              // 因为是按照类型注入,所以肯定只能指导一个这个的依赖Bean,否则上面解析就已经报错了
              if (autowiredBeanNames.size() == 1) {
                String autowiredBeanName = autowiredBeanNames.iterator().next();
                // 这里是来处理放置缓存的字段值
                if (beanFactory.containsBean(autowiredBeanName) &&
                    beanFactory.isTypeMatch(autowiredBeanName, field.getType())) {
                  this.cachedFieldValue = new ShortcutDependencyDescriptor(
                      desc, autowiredBeanName, field.getType());
                }
              }
            } else {
              this.cachedFieldValue = null;
            }
            this.cached = true;
          }
        }
      }
      // 给该对象的该字段赋值。注意这里makeAccessible设置为true了,所以即使你的字段是private的也木有关系哦~~~
      if (value != null) {
        ReflectionUtils.makeAccessible(field);
        field.set(bean, value);
      }
    }
  }

initializeBean进行Bean的初始化工作


上面步骤已经完成了Bean的属性的赋值工作,接下里就进行Bean的一些初始化工作,其中包括:

1:Bean后置处理器初始化

2:Bean的一些初始化方法的执行init-method等等

3:Bean的实现的声明周期相关接口的属性注入

  protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {
    // 第一步:先执行所有的AwareMethods,具体如下代码,比较简单
    if (System.getSecurityManager() != null) {
      AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
        invokeAwareMethods(beanName, bean);
        return null;
      }, getAccessControlContext());
    } else {
      invokeAwareMethods(beanName, bean);
    }
    Object wrappedBean = bean;
    if (mbd == null || !mbd.isSynthetic()) {
      // 执行所有的BeanPostProcessor#postProcessBeforeInitialization  初始化之前的处理器方法
      // 规则:只要谁反悔了null,后面的就都不要执行了
      // 这里面实现postProcessBeforeInitialization 的处理器就很多了,有很多对Aware进行了扩展的,具体如下面的具体介绍吧=================
      wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
    }
    try {
      //这里就开始执行afterPropertiesSet(实现了InitializingBean接口)方法和initMethod 
      // 备注:这里initMethod方法的名称不能是afterPropertiesSet,并且这个类不是 InitializingBean类型才会调用,需要特别注意。
      //(然后该方法只有方法名,所以肯定是反射调用,效率稍微低那么一丢丢)
      // 由此可以见,实现这个接口的初始化方法,是在标注形如@PostConstruct之后执行的
      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()) {
      // 整个Bean都初始化完成了,就执行后置处理器的这个方法
      // 如果谁反悔了null,后面的处理器都不会再执行了
      wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
    }
    return wrappedBean;
  }
相关文章
|
1月前
|
XML 安全 Java
|
12天前
|
存储 Java Spring
【Spring】获取Bean对象需要哪些注解
@Conntroller,@Service,@Repository,@Component,@Configuration,关于Bean对象的五个常用注解
|
12天前
|
存储 Java 应用服务中间件
【Spring】IoC和DI,控制反转,Bean对象的获取方式
IoC,DI,控制反转容器,Bean的基本常识,类注解@Controller,获取Bean对象的常用三种方式
|
18天前
|
XML Java 数据格式
Spring容器Bean之XML配置方式
通过对以上内容的掌握,开发人员可以灵活地使用Spring的XML配置方式来管理应用程序的Bean,提高代码的模块化和可维护性。
54 6
|
20天前
|
XML Java 数据格式
🌱 深入Spring的心脏:Bean配置的艺术与实践 🌟
本文深入探讨了Spring框架中Bean配置的奥秘,从基本概念到XML配置文件的使用,再到静态工厂方式实例化Bean的详细步骤,通过实际代码示例帮助读者更好地理解和应用Spring的Bean配置。希望对你的Spring开发之旅有所助益。
84 3
|
2月前
|
缓存 Java Spring
实战指南:四种调整 Spring Bean 初始化顺序的方案
本文探讨了如何调整 Spring Boot 中 Bean 的初始化顺序,以满足业务需求。文章通过四种方案进行了详细分析: 1. **方案一 (@Order)**:通过 `@Order` 注解设置 Bean 的初始化顺序,但发现 `@PostConstruct` 会影响顺序。 2. **方案二 (SmartInitializingSingleton)**:在所有单例 Bean 初始化后执行额外的初始化工作,但无法精确控制特定 Bean 的顺序。 3. **方案三 (@DependsOn)**:通过 `@DependsOn` 注解指定 Bean 之间的依赖关系,成功实现顺序控制,但耦合性较高。
实战指南:四种调整 Spring Bean 初始化顺序的方案
|
1月前
|
安全 Java 开发者
Spring容器中的bean是线程安全的吗?
Spring容器中的bean默认为单例模式,多线程环境下若操作共享成员变量,易引发线程安全问题。Spring未对单例bean做线程安全处理,需开发者自行解决。通常,Spring bean(如Controller、Service、Dao)无状态变化,故多为线程安全。若涉及线程安全问题,可通过编码或设置bean作用域为prototype解决。
35 1
|
3月前
|
人工智能 自然语言处理 前端开发
SpringBoot + 通义千问 + 自定义React组件:支持EventStream数据解析的技术实践
【10月更文挑战第7天】在现代Web开发中,集成多种技术栈以实现复杂的功能需求已成为常态。本文将详细介绍如何使用SpringBoot作为后端框架,结合阿里巴巴的通义千问(一个强大的自然语言处理服务),并通过自定义React组件来支持服务器发送事件(SSE, Server-Sent Events)的EventStream数据解析。这一组合不仅能够实现高效的实时通信,还能利用AI技术提升用户体验。
261 2
|
13天前
|
Java 数据库连接 Maven
最新版 | 深入剖析SpringBoot3源码——分析自动装配原理(面试常考)
自动装配是现在面试中常考的一道面试题。本文基于最新的 SpringBoot 3.3.3 版本的源码来分析自动装配的原理,并在文未说明了SpringBoot2和SpringBoot3的自动装配源码中区别,以及面试回答的拿分核心话术。
最新版 | 深入剖析SpringBoot3源码——分析自动装配原理(面试常考)
|
20天前
|
NoSQL Java Redis
Spring Boot 自动配置机制:从原理到自定义
Spring Boot 的自动配置机制通过 `spring.factories` 文件和 `@EnableAutoConfiguration` 注解,根据类路径中的依赖和条件注解自动配置所需的 Bean,大大简化了开发过程。本文深入探讨了自动配置的原理、条件化配置、自定义自动配置以及实际应用案例,帮助开发者更好地理解和利用这一强大特性。
75 14

热门文章

最新文章