Spring源码分析之Bean的创建过程详解(二)

本文涉及的产品
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
全局流量管理 GTM,标准版 1个月
云解析 DNS,旗舰版 1个月
简介: Spring源码分析之Bean的创建过程详解

createBeanInstance

protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args){
  // 获取beanClass
  Class<?> beanClass = resolveBeanClass(mbd, beanName);
  // 使用AutowiredAnnotationBeanPostProcessor进行构造器推断,找到所有的有参构造器
  Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
  if (ctors != null || mbd.getResolvedAutowireMode() == AUTOWIRE_CONSTRUCTOR ||
        mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) {
    // 实例化bean,并根据参数自动装配
    return autowireConstructor(beanName, mbd, ctors, args);
  }
  // 调用无参的构造方法实例化
  return instantiateBean(beanName, mbd);
}

determineConstructorsFromBeanPostProcessors

protected Constructor<?>[] determineConstructorsFromBeanPostProcessors(@Nullable Class<?> beanClass, String beanName)
      throws BeansException {
  if (beanClass != null && hasInstantiationAwareBeanPostProcessors()) {
    for (BeanPostProcessor bp : getBeanPostProcessors()) {
      if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {
        // 只有AutowiredAnnotationBeanPostProcessor进行了实现,其他的都返回null
        SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp;
        // 确认候选的构造器
        Constructor<?>[] ctors = ibp.determineCandidateConstructors(beanClass, beanName);
        if (ctors != null) {
          return ctors;
        }
      }
    }
  }
  return null;
}

AutowiredAnnotationBeanPostProcessor#determineCandidateConstructors

public Constructor<?>[] determineCandidateConstructors(Class<?> beanClass, final String beanName){
  // 获取到所有的构造方法
  rawCandidates = beanClass.getDeclaredConstructors();
  for (Constructor<?> candidate : rawCandidates) {
    // 是否带有@Autowired注解
    MergedAnnotation<?> ann = findAutowiredAnnotation(candidate);
    if (ann != null) {
      // 是否必须
      boolean required = determineRequiredStatus(ann);
      candidates.add(candidate);
    }
    else if (candidate.getParameterCount() == 0) {
      // 无参构造器
      defaultConstructor = candidate;
    }
  }
  // 候选的构造器不为空
  if (!candidates.isEmpty()) {
    // 候选的构造器不为空而requiredConstructor为空表示有@Autowired标识的构造器
    // 但是required=false
    if (requiredConstructor == null) {
      if (defaultConstructor != null) {
        // 将无参构造器也加入到候选构造器集合中
        candidates.add(defaultConstructor);
      }
    }
    // 将集合中的构造器转化为数组
    candidateConstructors = candidates.toArray(new Constructor<?>[0]);
  }
  // 候选的构造器为空,但有一个有参构造器,则使用有参构造器作为候选的构造器
  else if (rawCandidates.length == 1 && rawCandidates[0].getParameterCount() > 0) {
    candidateConstructors = new Constructor<?>[] {rawCandidates[0]};
  }
  // 返回候选构造器数组
  return (candidateConstructors.length > 0 ? candidateConstructors : null);
}

autowireConstructor 实例化并自动装配,摘取代码片段

protected BeanWrapper autowireConstructor(
      String beanName, RootBeanDefinition mbd, @Nullable Constructor<?>[] ctors, @Nullable Object[] explicitArgs) {
  return new ConstructorResolver(this).autowireConstructor(beanName, mbd, ctors, explicitArgs);
}
public BeanWrapper autowireConstructor(String beanName, RootBeanDefinition mbd,
      @Nullable Constructor<?>[] chosenCtors, @Nullable Object[] explicitArgs) {
  for (Constructor<?> candidate : candidates) {
    // 获取参数的类型
    Class<?>[] paramTypes = candidate.getParameterTypes();
    // 获取依赖的bean
    argsHolder = createArgumentArray(beanName, mbd, resolvedValues, bw, paramTypes, paramNames..);
    // 调用instantiate方法进行实例化bean
    bw.setBeanInstance(instantiate(beanName, mbd, constructorToUse, argsToUse));
  }
}

以上便是bean的实例化过程

applyMergedBeanDefinitionPostProcessors

第三次主要是将标识了需要自动装配注解的属性或方法解析出来,包含的注解主要有 @Resource @Autowired @Value @Inject @PostConstruct @PreDestroy

protected void applyMergedBeanDefinitionPostProcessors(RootBeanDefinition mbd, Class<?> beanType, String beanName) {
  for (BeanPostProcessor bp : getBeanPostProcessors()) {
    if (bp instanceof MergedBeanDefinitionPostProcessor) {
      // CommonAnnotationBeanPostProcessor解析@PostConstruct @PreDestroy @Resource
      // AutowiredAnnotationBeanPostProcessor 解析@Autowired @Value @Inject
      MergedBeanDefinitionPostProcessor bdp = (MergedBeanDefinitionPostProcessor) bp;
      bdp.postProcessMergedBeanDefinition(mbd, beanType, beanName);
    }
  }
}

CommonAnnotationBeanPostProcessor#postProcessMergedBeanDefinition

public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {
  // 父类为InitDestroyAnnotationBeanPostProcessor
  // 寻找@PostConstruct @PreDestroy注解的方法
  // 用于bean的生命周期中初始化前的处理逻辑
  super.postProcessMergedBeanDefinition(beanDefinition, beanType, beanName);
  // 寻找@Resource注解标识的属性或方法元数据
  // 将这些元数据保存到缓存中,用于在属性装配阶段使用
  InjectionMetadata metadata = findResourceMetadata(beanName, beanType, null);
  // 检查是否有重复的元数据,去重处理,如一个属性上既有@Autowired注解,又有@Resource注解
  // 只使用一种方式进行注入,由于@Resource先进行解析,所以会选择@Resource的方式
  metadata.checkConfigMembers(beanDefinition);
}

InitDestroyAnnotationBeanPostProcessor#postProcessMergedBeanDefinition

public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {
  // 寻找PostConstruct @PreDestroy注解的方法
  LifecycleMetadata metadata = findLifecycleMetadata(beanType);
  // 去重处理
  metadata.checkConfigMembers(beanDefinition);
}

所有的后置处理器的过程是相似的,这里取CommonAnnotationBeanPostProcessor进行分析

我们先来看看寻找元数据的过程

private InjectionMetadata findResourceMetadata(String beanName, final Class<?> clazz, @Nullable PropertyValues pvs) {
  String cacheKey = (StringUtils.hasLength(beanName) ? beanName : clazz.getName());
  // 从缓存中获取
  // 调用postProcessMergedBeanDefinition方法时将元数据解析放入缓存
  // 调用postProcessProperties方法时将元数据取出
  InjectionMetadata metadata = this.injectionMetadataCache.get(cacheKey);
  if (InjectionMetadata.needsRefresh(metadata, clazz)) {
    synchronized (this.injectionMetadataCache) {
      metadata = this.injectionMetadataCache.get(cacheKey);
      if (InjectionMetadata.needsRefresh(metadata, clazz)) {
        if (metadata != null) {
          metadata.clear(pvs);
        }
        // 创建元数据,寻找@Resouce标识的属性或方法
        metadata = buildResourceMetadata(clazz);
        this.injectionMetadataCache.put(cacheKey, metadata);
      }
    }
  }
  return metadata;
}

buildResourceMetadata

private InjectionMetadata buildResourceMetadata(final Class<?> clazz){
  // 判断是否为候选的class,不是则返回默认的空元数据
  // resourceAnnotationTypes为Annotation集合,里面包含了@Resource @EJB @WebServiceRef
  // 我们一般常用的只是@Resource
  if (!AnnotationUtils.isCandidateClass(clazz, resourceAnnotationTypes)) {
    return InjectionMetadata.EMPTY;
  }
  do {
    // 循环所有的属性,判断属性是否存在WebServiceRef、EJB、Resource注解,有则构建元数据
    // doWithLocalFields中就是将targetClass的所有field取出进行循环
    ReflectionUtils.doWithLocalFields(targetClass, field -> {
      if (webServiceRefClass != null && field.isAnnotationPresent(webServiceRefClass)) {
        currElements.add(new WebServiceRefElement(field, field, null));
      }
      else if (ejbClass != null && field.isAnnotationPresent(ejbClass)) {
        currElements.add(new EjbRefElement(field, field, null));
      }
      // 是否存在@Resource注解
      else if (field.isAnnotationPresent(Resource.class)) {
        if (!this.ignoredResourceTypes.contains(field.getType().getName())) {
          currElements.add(new ResourceElement(field, field, null));
        }
      }
    }); 
    // 与上一步相似,判断方法上是否存在这些注解
    ReflectionUtils.doWithLocalMethods(targetClass, method -> {
      //......省略
    });
    // 获取父类
    targetClass = targetClass.getSuperclass();
  }
  // 父类不是Object则继续循环父类中的属性和方法
  while (targetClass != null && targetClass != Object.class);
  // 将构建好的元数据封装到InjectionMetadata中返回
  return InjectionMetadata.forElements(elements, clazz);
}

现在我们再来看看去重处理的过程

public void checkConfigMembers(RootBeanDefinition beanDefinition) {
    Set<InjectedElement> checkedElements = new LinkedHashSet<>(this.injectedElements.size());
  for (InjectedElement element : this.injectedElements) {
    Member member = element.getMember();
    // 检查该beanDefinition的externallyManagedConfigMembers集合中是否已经包含该成员(属性或者方法)
    if (!beanDefinition.isExternallyManagedConfigMember(member)) {
      // 不包含则将该成员注册
      beanDefinition.registerExternallyManagedConfigMember(member);
      // 加入到已检查的集合
      checkedElements.add(element);
    }
  }
  this.checkedElements = checkedElements;
}

由于第四次,用于获取早期对象时的处理的调用,在Spring的内置处理器中也没有相应的实现,跳过

这一步和第一步一样,在AOP时将会用到,我们放到下章分析

紧接着就是填充属性的步骤了

populateBean

protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
  // 在这里可进行中止填充属性操作,实现InstantiationAwareBeanPostProcessor接口
  // 并postProcessAfterInstantiation返回false,则直接返回,不会再往下执行
  // Spring内中的后置处理器皆返回的true
  if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
    for (BeanPostProcessor bp : getBeanPostProcessors()) {
      if (bp instanceof InstantiationAwareBeanPostProcessor) {
        InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
        if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
          return;
        }
      }
    }
  }
  // 获得自动装配的类型,默认为0,
  // 这里只有xml配置,ImportBeanDefinitionRegistrar,BeanFactoryPostProcessor可进行改变
  // Spring整合Mybatis中,将Mapper的自动装配类型改成了BY_TYPE,
  // 于是在Mapper得以在这里被填充SqlSessionTemplate,SqlSessionFactory属性
  int resolvedAutowireMode = mbd.getResolvedAutowireMode();
  if (resolvedAutowireMode == AUTOWIRE_BY_NAME || resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
    MutablePropertyValues newPvs = new MutablePropertyValues(pvs);
    if (resolvedAutowireMode == AUTOWIRE_BY_NAME) {
      autowireByName(beanName, mbd, bw, newPvs);
    }
    if (resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
      // 获取到依赖的bean并放到newPvs中
      autowireByType(beanName, mbd, bw, newPvs);
    }
    // 将新的属性列表赋给旧的引用
    pvs = newPvs;
  }
}

autowireByName 和 autowireByType差不多,autowireByType更为复杂一些,这里只分析autowireByType的处理过程

protected void autowireByType(
      String beanName, AbstractBeanDefinition mbd, BeanWrapper bw, MutablePropertyValues pvs) {
  // 查询非简单(Java内置 基本类型,String,Date等)的属性
  String[] propertyNames = unsatisfiedNonSimpleProperties(mbd, bw);
  // 循环所有属性名
  for (String propertyName : propertyNames) {
    // 获取方法参数
    MethodParameter methodParam = BeanUtils.getWriteMethodParameter(pd);
    // 构建一个依赖描述符
    DependencyDescriptor desc = new AutowireByTypeDependencyDescriptor(methodParam, eager);
    // 获取依赖的bean 
    // resolveDependency方法中调用了doResolveDependency,该方法我们在下一步的后置处理器调用中分析
    Object autowiredArgument = resolveDependency(desc, beanName, autowiredBeanNames, converter);
    // 将bean放置到属性集合中
    if (autowiredArgument != null) {
      pvs.add(propertyName, autowiredArgument);
    }
  }
}

现在,回到填充属性的过程

目录
相关文章
|
25天前
|
XML 安全 Java
|
1月前
|
监控 Java 应用服务中间件
Spring Boot整合Tomcat底层源码分析
【11月更文挑战第20天】Spring Boot是一个用于快速构建基于Spring框架的应用程序的开源框架。它通过自动配置和起步依赖等特性,大大简化了Spring应用的开发和部署过程。本文将深入探讨Spring Boot的背景历史、业务场景、功能点以及底层原理,并通过Java代码手写模拟Spring Boot的启动过程,特别是其与Tomcat的整合。
61 1
|
3天前
|
设计模式 XML Java
【23种设计模式·全精解析 | 自定义Spring框架篇】Spring核心源码分析+自定义Spring的IOC功能,依赖注入功能
本文详细介绍了Spring框架的核心功能,并通过手写自定义Spring框架的方式,深入理解了Spring的IOC(控制反转)和DI(依赖注入)功能,并且学会实际运用设计模式到真实开发中。
【23种设计模式·全精解析 | 自定义Spring框架篇】Spring核心源码分析+自定义Spring的IOC功能,依赖注入功能
|
1天前
|
存储 Java Spring
【Spring】获取Bean对象需要哪些注解
@Conntroller,@Service,@Repository,@Component,@Configuration,关于Bean对象的五个常用注解
|
1天前
|
存储 Java 应用服务中间件
【Spring】IoC和DI,控制反转,Bean对象的获取方式
IoC,DI,控制反转容器,Bean的基本常识,类注解@Controller,获取Bean对象的常用三种方式
|
7天前
|
XML Java 数据格式
Spring容器Bean之XML配置方式
通过对以上内容的掌握,开发人员可以灵活地使用Spring的XML配置方式来管理应用程序的Bean,提高代码的模块化和可维护性。
37 6
|
9天前
|
XML Java 数据格式
🌱 深入Spring的心脏:Bean配置的艺术与实践 🌟
本文深入探讨了Spring框架中Bean配置的奥秘,从基本概念到XML配置文件的使用,再到静态工厂方式实例化Bean的详细步骤,通过实际代码示例帮助读者更好地理解和应用Spring的Bean配置。希望对你的Spring开发之旅有所助益。
56 3
|
1月前
|
缓存 Java Spring
实战指南:四种调整 Spring Bean 初始化顺序的方案
本文探讨了如何调整 Spring Boot 中 Bean 的初始化顺序,以满足业务需求。文章通过四种方案进行了详细分析: 1. **方案一 (@Order)**:通过 `@Order` 注解设置 Bean 的初始化顺序,但发现 `@PostConstruct` 会影响顺序。 2. **方案二 (SmartInitializingSingleton)**:在所有单例 Bean 初始化后执行额外的初始化工作,但无法精确控制特定 Bean 的顺序。 3. **方案三 (@DependsOn)**:通过 `@DependsOn` 注解指定 Bean 之间的依赖关系,成功实现顺序控制,但耦合性较高。
实战指南:四种调整 Spring Bean 初始化顺序的方案
|
22天前
|
安全 Java 开发者
Spring容器中的bean是线程安全的吗?
Spring容器中的bean默认为单例模式,多线程环境下若操作共享成员变量,易引发线程安全问题。Spring未对单例bean做线程安全处理,需开发者自行解决。通常,Spring bean(如Controller、Service、Dao)无状态变化,故多为线程安全。若涉及线程安全问题,可通过编码或设置bean作用域为prototype解决。
32 1
|
1月前
|
前端开发 Java Spring
Spring MVC源码分析之DispatcherServlet#getHandlerAdapter方法
`DispatcherServlet`的 `getHandlerAdapter`方法是Spring MVC处理请求的核心部分之一。它通过遍历预定义的 `HandlerAdapter`列表,找到适用于当前处理器的适配器,并调用适配器执行具体的处理逻辑。理解这个方法有助于深入了解Spring MVC的工作机制和扩展点。
38 1