Spring 依赖注入源码

本文深入探讨了Spring框架的依赖注入机制,包括原始的BY_NAME和BY_TYPE方式以及注解方式,如@Autowired。详细解释了如何寻找注入点并进行注入,以及从BeanFactory中查找并注入对象的过程。最后总结了Spring依赖注入的关键步骤和策略。
摘要由CSDN通过智能技术生成

依赖注入

具体代码是在AbstractAutowireCapableBeanFactory类的populateBean()方法,此方法中主要做的事情如下:

  • 实例化之后,调用InstantiationAwareBeanPostProcessor接口的postProcessAfterInstantiation方法
  • Spring早期通过BY_NAME或BY_TYPE两种方式,并利用set方法进行依赖注入
  • 通过InstantiationAwareBeanPostProcessor接口的postProcessProperties()方法进行依赖注入,典型的代表就是@Autowired等注解的处理
  • 将BeanDefinition中的PropertyValues覆盖@Autowired等注解的值



原始依赖注入方式

在线流程图

在这里插入图片描述


首先分析Spring早期的依赖注入

@Bean(autowire = Autowire.BY_NAME)
public UserService userService(){
   
   return new UserService();
}

接下来就会遍历UserService中所有的set方法进行依赖注入。

对应的Spring源码是

PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null);
int resolvedAutowireMode = mbd.getResolvedAutowireMode();
// 必须是BY_NAME或BY_TYPE
if (resolvedAutowireMode == AUTOWIRE_BY_NAME || resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
   
   // MutablePropertyValues是PropertyValues具体的实现类
   MutablePropertyValues newPvs = new MutablePropertyValues(pvs);
   // 这里会根据我们的配置来分别调用不同的方法
   if (resolvedAutowireMode == AUTOWIRE_BY_NAME) {
   
      autowireByName(beanName, mbd, bw, newPvs);
   }
   if (resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
   
      autowireByType(beanName, mbd, bw, newPvs);
   }
   pvs = newPvs;
}

接下来看autowireByName()方法,主要过程就是先根据set方法找出所有的属性名,然后在遍历属性名集合,去单例池中找,再赋值给pvs变量

protected void autowireByName(
      String beanName, AbstractBeanDefinition mbd, BeanWrapper bw, MutablePropertyValues pvs) {
   

   // 当前Bean中能进行自动注入的属性名,是根据setXXX()方法生成是属性名
   String[] propertyNames = unsatisfiedNonSimpleProperties(mbd, bw);
   // 遍历每个属性名,并去获取Bean对象,并设置到pvs中
   for (String propertyName : propertyNames) {
   
      // 要进行依赖注入的属性在当前容器中是否存在
      if (containsBean(propertyName)) {
   
         // 从容器中取出来,再存入pvs中
         Object bean = getBean(propertyName);
         pvs.add(propertyName, bean);
         // 记录一下propertyName对应的Bean被beanName给依赖了
         registerDependentBean(propertyName, beanName);
         if (logger.isTraceEnabled()) {
   
            logger.trace("Added autowiring by name from bean name '" + beanName +
                  "' via property '" + propertyName + "' to bean named '" + propertyName + "'");
         }
      }
      else {
   
         if (logger.isTraceEnabled()) {
   
            logger.trace("Not autowiring property '" + propertyName + "' of bean '" + beanName +
                  "' by name: no matching bean found");
         }
      }
   }
}

autowireByType()方法其实也类似,首先得到属性名集合,再遍历集合,然后得到方法形参的类型,根据resolveDependency()找到bean对象,再存入pvs



注解方式

在线流程图

在这里插入图片描述


我们常用的方式是利用@Autowired等注解的方式实现依赖注入的,在Spring源码AbstractAutowireCapableBeanFactory类的populateBean()方法中对应的实现其实就是利用InstantiationAwareBeanPostProcessor接口的postProcessProperties()方法实现的

for (InstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().instantiationAware) {
   
   // @Autowired注解 这里会调用AutowiredAnnotationBeanPostProcessor的postProcessProperties()方法,会直接给对象中的属性赋值
   // AutowiredAnnotationBeanPostProcessor内部并不会处理pvs,直接返回了
   PropertyValues pvsToUse = bp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);
   if (pvsToUse == null) {
   
      if (filteredPds == null) {
   
         filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
      }
      pvsToUse = bp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
      if (pvsToUse == null) {
   
         return;
      }
   }
   pvs = pvsToUse;
}

@Autowired@Value注解是通过AutowiredAnnotationBeanPostProcessor类处理的

@Resource注解是通过CommonAnnotationBeanPostProcessor类处理的


实现看AutowiredAnnotationBeanPostProcessor类的定义,它实现了初始化后置处理器以及BeanDefinition后置处理器两个接口,所以该类就会有下面两个方法

InstantiationAwareBeanPostProcessor接口的postProcessProperties()方法

MergedBeanDefinitionPostProcessor接口的postProcessMergedBeanDefinition()方法

public class AutowiredAnnotationBeanPostProcessor implements SmartInstantiationAwareBeanPostProcessor,
      MergedBeanDefinitionPostProcessor, PriorityOrdered, BeanFactoryAware {
   
          ...
}

根据我们对Bean生命周期的了解可以知道,postProcessMergedBeanDefinition()方法先执行,postProcessProperties()方法后执行



寻找注入点

我们可以先想一想如果要自己实现依赖注入应该要怎么做?首先就是找出类里面所有加了@Autowired注解的属性和Set方法,这个也称为注入点,然后在为这些注入点赋值。接下来看具体的实现,首先的BeanDefinition的后置处理器方法

@Override
public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {
   
   // 根据类的class对象找到所有的注入点
   InjectionMetadata metadata = findAutowiringMetadata(beanName, beanType, null);
   metadata.checkConfigMembers(beanDefinition);
}

先看findAutowiringMetadata()方法逻辑

private InjectionMetadata findAutowiringMetadata(String beanName, Class<?> clazz, @Nullable PropertyValues pvs) {
   
   // cacheKey其实就beanName
   String cacheKey = (StringUtils.hasLength(beanName) ? beanName : clazz.getName());
   // 该类的所有注入点会缓存到injectionMetadataCache中
   InjectionMetadata metadata = this.injectionMetadataCache.get(cacheKey);
   if (InjectionMetadata.needsRefresh(metadata, clazz)<
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
Spring循环依赖是指两个或多个Bean之间相互依赖,形成一个循环引用的关系。在Spring容器启动的过程中,如果存在循环依赖,那么默认情况下会抛出BeanCurrentlyInCreationException异常。 下面是Spring循环依赖的源码分析: 1. 当我们向Spring容器中注入一个Bean时,Spring会先检查这个Bean是否已经正在创建中(正在创建的Bean是无法注入的),如果正在创建中,则直接返回一个早期引用,否则继续创建Bean。 2. 在Bean的创建过程中,当遇到依赖注入(如@Autowired注解)时,Spring会检查要注入的Bean是否已经在创建中。如果是,则返回一个代理对象作为占位符,等待真正的Bean创建完毕后再进行注入。 3. Spring使用三级缓存来解决循环依赖问题。第一级缓存是单例池,存放已经创建好的单例Bean。第二级缓存是提前暴露的ObjectFactory,存放早期引用。第三级缓存是用于存放正在创建中的Bean的缓存,用于检测循环依赖。 4. 当检测到循环依赖时,Spring会尝试使用构造函数的方式完成循环依赖。它会先创建一个空对象,并将其放入到第三级缓存中。然后调用构造函数去创建这个Bean,此时依赖的Bean会返回一个早期引用。最后,将这个Bean加入到第一级缓存中,并开始注入依赖。 5. 当所有的Bean都创建完成后,Spring会触发后置处理器的回调方法,完成Bean的初始化。 总结:Spring循环依赖通过使用三级缓存和构造函数来解决,在Bean创建过程中动态地判断和处理循环依赖关系,确保所有的Bean都能被正确地创建和注入。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值