Spring依赖注入@AutoWired

@Autowired 注解的实现原理 @Autowired注解我们实际工作和学习中,用的是比较频繁的。这篇文章主要是结合源码了解它的实际工作过程即是怎么把我们需要的类注入到我们类中的。@Autowired注入过程,实际上分为三个方面:1、元信息解析;2、依赖查找;3、依赖注入(字段、方法)。 元信息解析,在处理过程中,有一个类叫DependencyDescriptor,比如说我们的依赖描述器或者依赖描... 阅读详情

Spring依赖注入的形式

Spring中的依赖注入要分好几种,我这边大概说明下这几种方式,spring中现在用的最多的是两种方式,第一种是xml模式,但是现在大多数都是注解的方式,现在不是叫做spring boot零配置吗,说白了就是没有使用xml的模式,使用的是注解的方式;spring中依赖注入要分好几种。

XML的方式

手动方式:
1.构造方法注入
2.set方法注入
自动模式:
1.构造方法注入
2.set方法注入
xml的注入方式在最早的时候用的最多的,xml的注入分为手动模式和自动模式,我们先来看下手动的模式,手动模式要在xml文件中写标签来手动注入

<bean name="orderService" class="com.bml10.service.OrderService">

</bean>
<bean name="userService" class="com.bml10.service.UserService">
   <property name="orderService" ref="orderService"/>
</bean>

对应的要在UserService提供set方法

public class UserService {


   private OrderService orderService;
   public void setOrderService(OrderService orderService) {
      this.orderService = orderService;
   }

   public void test(){
      System.out.println("orderService="+ orderService);
   }
}

这样就可以注入了,我们看下这种手动模式在spring的源码中是如何处理的,在spring填充属性的方法,上一篇笔记中已经记录了,方法就是populateBean
在这里插入图片描述
就是这段代码和这个方法的后面的applyPropertyValues(beanName, mbd, bw, pvs);来填充的属性,这种模式就是说在spring扫描的阶段会将你配置的标签扫描成一个PropertyValue,然后最后在初始化实例化bean过后就是填充属性的这个方法applyPropertyValues会将找到的bean填充到bean的属性中,也就是注入到bean的属性中;
如果说xml的方式要通过自动注入怎么做呢?因为一个bean中如果要注入的属性太多,而且你写xml还容易出错,所以xml也提供了一个自动注入的,自动注入分为byType和byName的方式;byName就很简单了,buName就是根据你的属性的set方法,比如setUserSerivce,那么会截取set,得到userService,去spring容器中找,如果找到了就添加到PropertyValues中,后面会调用applyPropertyValues注入,如果没有找到就不注入;如果是byType的方式,就负责点了,首先byType如果找到多个,要报错的,因为xml的自动注入的byType方式找到多个是要报错的,比如这种:

<bean name="orderService" class="com.bml10.service.OrderService">


</bean>
<bean name="orderService1" class="com.bml10.service.OrderService" />

<bean name="userService" class="com.bml10.service.UserService" autowire="byType">
</bean>

在这里插入图片描述
所以xml的自动注入通过byType的方式还是有缺陷的,万一你不小心注入了两个相同类型的bean,byType方式将会不成功;这里再说下,spring的xml的自动注入还有中全局的方式,就是在beans标签中设置一个全局的属性default-autowire
在这里插入图片描述
但是请注意的是设置了全局,那么每个bean里面就不需要设置了,但是如果你的某个bean设置了autowire,那么是局部生效的,不会用全局的,这个特性记住就行。

xml自动注入源码

刚刚上面演示的是spring的xml自动注入的例子,演示过后,我们来看下源码,源码在populateBean中,populateBean方法中的xml自动注入源码片段如下:

/**
 * 下面的这段逻辑处理的是依赖注入,其实下面的代码主要处理xml中的配置的依赖注入
 * 在xml中可以配置byType or byName的依赖注入
 * spring中的依赖注入分为几种模式:
 * 1.手动模式:在xml中配置Property属性,通过set方法进行注入,构造方法注入
 * 2.自动模式:xml中配置autoWier属性(byType or byName),在注解中配置@AutoWired
 * @Autowired可以注入属性,构造方法以及普通的方法
 *下面的代码主要处理在xml中配置了autowire属性的依赖注入
 * 也就是<bean id="xx" class="com.xx" autowire="byType" />
 * 这样配置了话,那么就会根据autowire来进行依赖注入,就不需要写
 * <Property name="" ref=""/>,还有种方式就是在beans中设置全局的default-autowire
 */

//下面的pvs就是找到在扫描过程中,如果xml配置了Property属性的标签会解析成PropertyValue
PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null);

//得到在xml中配置的autowire属性值,比如配置了autowire="byType",那么resolvedAutowireMode就会有值2
int resolvedAutowireMode = mbd.getResolvedAutowireMode();
//在xml配置了byType or byName才会进入下面的依赖注入
if (resolvedAutowireMode == AUTOWIRE_BY_NAME || resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
   /**
    * 下面的是xml的依赖注入,现在使用注解的模式基本上是用不到,但是为了解释清楚,这里还是进行解析一下
    * 其中分了两种默认,byType 和byName,byName的比较好理解
    * byName:根据bean找到bean下面的所有set方法,比如setUserService,那么会截取set得到userService,然后去
    * bd中找,如果找到了,然后进注入到pvs中,在本方法的最后applyPropertyValues进入设置属性进去
    * byType:byType就比较复杂一点
    */
   //先声明一个MutablePropertyValues,把原来的PropertyValues传进去,如果pvs为空,则构建一个list集合
   MutablePropertyValues newPvs = new MutablePropertyValues(pvs);
   // Add property values based on autowire by name if applicable.
   if (resolvedAutowireMode == AUTOWIRE_BY_NAME) {
      //这个是以byName进行注入,bw是包装的bean对象,mbd是BeanDefinition,newpvs是属性注入的对象
      autowireByName(beanName, mbd, bw, newPvs);
   }
   // Add property values based on autowire by type if applicable.
   if (resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
      //byType里面处理的逻辑有点复杂,我看了下,实现原理大概如下:
      //1.先根据bean所在的类找到所有的set方法,然后得到set方法对应的名字,也就是beanName集合
      //然后循环这个集合,将beanName装载成一个属性描述器,然后根据属性描述器得到方法参数对象MethodParameter
      //2.然后在根据MethodParameter封装成一个byType的依赖描述器,请注意,只有byType才实行了依赖描述器的实现类
      //byName是没有的,封装成一个byType的依赖描述器过后,根据这个依赖描述器获取bean,简单来说,就是你ref=“bean”中的
      //bean在容器中的bean对象信息,那出来然后注入到newpvs中,在下面的applyPropertyValues方法填充进去
      autowireByType(beanName, mbd, bw, newPvs);
   }
   pvs = newPvs;
}

autowireByName

protected void autowireByName(
      String beanName, AbstractBeanDefinition mbd, BeanWrapper bw, MutablePropertyValues pvs) {
        //找到这个bean中所有的set方法,并且根据set方法截取beanname,并且返回一个beanName所对应的名字集合
   String[] propertyNames = unsatisfiedNonSimpleProperties(mbd, bw);
   //根据方法返回的属性名字,循环这个beannames集合
   for (String propertyName : propertyNames) {
      if (containsBean(propertyName)) {
         //创建bean或者获取bean然后注入到pvs中
         Object bean = getBean(propertyName);
         pvs.add(propertyName, bean);
         //下面是注入依赖的信息,表示我的这个bean依赖了那些bean
         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

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

   TypeConverter converter = getCustomTypeConverter();
   if (converter == null) {
      converter = bw;
   }

   Set<String> autowiredBeanNames = new LinkedHashSet<>(4);
   String[] propertyNames = unsatisfiedNonSimpleProperties(mbd, bw);
   for (String propertyName : propertyNames) {
      try {
         //属性名字也就是通过set方法得到的beanName获取一个属性描述器
         PropertyDescriptor pd = bw.getPropertyDescriptor(propertyName);
         // Don't try autowiring by type for type Object: never makes sense,
         // even if it technically is a unsatisfied, non-simple property.
         //这里是判断是你的属性描述器,也就是说你的set方法的参数的类型不能是Object
         //因为如果setUserService(Object userService),那么像这个方法,如果是Object,spring根本不知道你要注入那个bean
         //所以不能是Object
         if (Object.class != pd.getPropertyType()) {
            //根据属性描述器获取这个set方法的参数信息
            MethodParameter methodParam = BeanUtils.getWriteMethodParameter(pd);
            // Do not allow eager init for type matching in case of a prioritized post-processor.
            boolean eager = !(bw.getWrappedInstance() instanceof PriorityOrdered);
            /**
             *
             * 根据方法的参数MethodParameter获取一个bean
             * 到这里知道这个方法是byType,byType的原理是根据你的set方法的参数类型得到一个bean,所以这里是通过
             * set方法的参数比如setUserService(UserService uservice)中的UserService来构建一个依赖描述器
             * 这个依赖描述器得到过后,根据这个依赖描述器和其他一些参数得到一个bean
             */
            DependencyDescriptor desc = new AutowireByTypeDependencyDescriptor(methodParam, eager);
            //这个里面的方法有点复杂,大概是知道它做了什么事儿,后面有空再去看下它是如何处理的
            //简单来说就是根据依赖描述器通过下面这个方法得到一个Bean,然后注入到pvs中
            Object autowiredArgument = resolveDependency(desc, beanName, autowiredBeanNames, converter);
            if (autowiredArgument != null) {
               pvs.add(propertyName, autowiredArgument);
            }
            //循环注入到当前bean所依赖的bean,autowiredBeanNames是当前bean锁依赖的bean集合
            for (String autowiredBeanName : autowiredBeanNames) {
               registerDependentBean(autowiredBeanName, beanName);
               if (logger.isTraceEnabled()) {
                  logger.trace("Autowiring by type from bean name '" + beanName + "' via property '" +
                        propertyName + "' to bean named '" + autowiredBeanName + "'");
               }
            }
            autowiredBeanNames.clear();
         }
      }
      catch (BeansException ex) {
         throw new UnsatisfiedDependencyException(mbd.getResourceDescription(), beanName, propertyName, ex);
      }
   }
}

xml的自动注入看上面的源码分析都是不会马上注入,而是添加到pvs中,最后调用applyPropertyValues方法进行属性填充的,所以我们这里总结出一个结论就是
spring 的xml方式注入依赖,分为手动和自动,手动的时候spring会将属性扫描到pvs中,然后如果是自动的话,自动获取的属性对应关系也会放入pvs中,最后调用applyPropertyValues进行属性填充。

以@AutoWired的方式

1.属性方式注入
2.普通非静态方法的注入
3.构造方法的注入

这篇笔记中,我们主要记录下上面几种注入方式中的非构造方法的注入,构造方法的注入在后面会有记录

spring的注解依赖注入

sprng的注解方式@AutoWired注入模式和上面的不太一样,@AutoWired有三种注入模式:
1.属性注入
2.非静态方法注入
3.构造方法注入
这里只讲前两种,第三中在后面讲,@AutoWired注入分为两步,第一步是找到注入点,然后放入缓存,第二步是从缓存获取注入点进行注入,spring中的依赖注入@AutoWired也是通过AutowiredAnnotationBeanPostProcessor这个bean后置处理器实现的,这个后置处理器中提供了两个方法,spring分别是在实例化后初始化前调用,这两个方法是postProcessMergedBeanDefinition和postProcessProperties,其中postProcessMergedBeanDefinition是找到bena的注入点,而postProcessProperties是进行注入,先来看下如何找到注入点的源码,注入点的源码是在doCreateBean中实现的

doCreateBean之注入点

synchronized (mbd.postProcessingLock) {
   if (!mbd.postProcessed) {
      try {
         //spring提供的又一个bean后置处理器,就是在bean实例化完成过后,可以进行调用
         //这个后置处理器可以传入指定的BeanDefinition,也就是你可以改变BeanDefinition的属性
         //但是这个时候bean都已经实例化完成了,就算你修改了beanclass也没有用了
         //但是有些属性我们还是可以设置的,比如可以手动设置初始化的方法mbd.setInitMethodName
         //@AutoWired注解的切入点就是在这个后置处理器中找到的并且注入到缓存中
         applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
      }
      catch (Throwable ex) {
         throw new BeanCreationException(mbd.getResourceDescription(), beanName,
               "Post-processing of merged bean definition failed", ex);
      }
      mbd.postProcessed = true;
   }
}
/**
 * Apply MergedBeanDefinitionPostProcessors to the specified bean definition,
 * invoking their {@code postProcessMergedBeanDefinition} methods.
 * @param mbd the merged bean definition for the bean
 * @param beanType the actual type of the managed bean instance
 * @param beanName the name of the bean
 * @see MergedBeanDefinitionPostProcessor#postProcessMergedBeanDefinition
 * 这个方法我个人的理解是可以被叫做合并bean过后的bean后置处理器
 * @AutoWired注解和@Value以及@Inject注解都是在这个后置处理器中实现的
 * 具体的后置处理器是AutowiredAnnotationBeanPostProcessor,在里面调用了postProcessMergedBeanDefinition
 */
protected void applyMergedBeanDefinitionPostProcessors(RootBeanDefinition mbd, Class<?> beanType, String beanName) {
   for (BeanPostProcessor bp : getBeanPostProcessors()) {
      if (bp instanceof MergedBeanDefinitionPostProcessor) {
         MergedBeanDefinitionPostProcessor bdp = (MergedBeanDefinitionPostProcessor) bp;
         bdp.postProcessMergedBeanDefinition(mbd, beanType, beanName);
      }
   }
}

后置处理器中调用的是postProcessMergedBeanDefinition,这个后置处理器是在AutowiredAnnotationBeanPostProcessor,所以我们看下AutowiredAnnotationBeanPostProcessor类中的注入点代码

postProcessMergedBeanDefinition

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

private InjectionMetadata findAutowiringMetadata(String beanName, Class<?> clazz, @Nullable PropertyValues pvs) {
      // Fall back to class name as cache key, for backwards compatibility with custom callers.
      String cacheKey = (StringUtils.hasLength(beanName) ? beanName : clazz.getName());
      // Quick check on the concurrent map first, with minimal locking.
      /**
       * 先从缓存中获取,如果缓存中没有,就去根据bean的类去找到,找到过后注入到injectionMetadataCache缓存中
       * 我们知道@AutoWired注入可以通过属性、普通方法、构造进行注入,这里对属性和普通方法进行注入
       */
      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);
               }
               //如果metadata不为空,则去找注入点,如果注入点为空那么metadata=InjectionMetadata.EMPTY
               metadata = buildAutowiringMetadata(clazz);
               //找到过后放入缓存
               this.injectionMetadataCache.put(cacheKey, metadata);
            }
         }
      }
      return metadata;
   }

   private InjectionMetadata buildAutowiringMetadata(final Class<?> clazz) {
      //注意,这里不是判断clzz是否实现了@AutoWired,@Value @Inject注解,这里的判断很简单
      //1.你传入的clazz如果是java.开头的则证明是java的内置的类,那么就返回false
      //2.你传入的autowiredAnnotationTypes是否是java开头的注解
      if (!AnnotationUtils.isCandidateClass(clazz, this.autowiredAnnotationTypes)) {
         return InjectionMetadata.EMPTY;
      }

      List<InjectionMetadata.InjectedElement> elements = new ArrayList<>();
      Class<?> targetClass = clazz;

      /**
       * 下面用了一个do while循环去找注入点,
       * 这里需要注意的是为什么要用do while,很简单的例子就是比如一个UserServce加了一个注解,那么是继承了BaseService
       * 而BaseService中没有加@Componet,但是UserService加了@Component注解,那么这个时候以UserService为bean去找注入点
       * spring会找到他的父类,一级一级的往上找,直到找到最顶层的类,所以在父类中加了@AutoWired等注解,就算父类没有@Component
       * 也是可以找到摈弃注入的
       * 下面的循环中是分了两部分来找的,第一部分是属性的注入,第二部分是普通方法的注入,而构造方法的注入不在这里
       */
      do {
         final List<InjectionMetadata.InjectedElement> currElements = new ArrayList<>();

         //属性的注入点寻找,下面使用的是java8的lambad表达式的方式,这里不关心,关心的是lambad里面的逻辑
         ReflectionUtils.doWithLocalFields(targetClass, field -> {
                //循环每个属性,看下属性是否实现了@AutoWired,@Value @Inject注解,如果没有实现,那么就会返回null
            MergedAnnotation<?> ann = findAutowiredAnnotation(field);
            if (ann != null) {
               //spring规定的是静态属性不能注入,也就是说你写的private static UserSerivce userService;
                     //是不能注入的
               if (Modifier.isStatic(field.getModifiers())) {
                  if (logger.isInfoEnabled()) {
                     logger.info("Autowired annotation is not supported on static fields: " + field);
                  }
                  return;
               }
               //这里读取的是@AutoWired上面的required,这个属性默认是true,sping这里的意思就是说
//             //如果你配置了required属性,如果这个属性为false,那么在注入的过程中如果没有找到,注入失败了,那么就不会报错
//             //如果设置为true,那么如果没有注入成功,会报异常
               boolean required = determineRequiredStatus(ann);
               //找到过后然后放入currElements缓存,这里的放入的对象是AutowiredFieldElement,就是针对属性的注入
               currElements.add(new AutowiredFieldElement(field, required));
            }
         });

         //下面的这个方法是针对普通方法注入的处理
         ReflectionUtils.doWithLocalMethods(targetClass, method -> {
            Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(method);
            if (!BridgeMethodResolver.isVisibilityBridgeMethodPair(method, bridgedMethod)) {
               return;
            }
            //这里也是去判断普通注入的方法是否有@AutoWired,@Value @Inject注解
            MergedAnnotation<?> ann = findAutowiredAnnotation(bridgedMethod);
            //如果方法有注解,并且方法是合法的,那么就进入找寻普通方法注入点的逻辑
            if (ann != null && method.equals(ClassUtils.getMostSpecificMethod(method, clazz))) {
               //相同的是注入的方法不能是静态方法
               if (Modifier.isStatic(method.getModifiers())) {
                  if (logger.isInfoEnabled()) {
                     logger.info("Autowired annotation is not supported on static methods: " + method);
                  }
                  return;
               }
               //方法的参数也不能是空,因为@AutoWired方法的注入是通过方法的参数类型进行注入的
               if (method.getParameterCount() == 0) {
                  if (logger.isInfoEnabled()) {
                     logger.info("Autowired annotation should only be used on methods with parameters: " +
                           method);
                  }
               }
               //和属性注入的逻辑一样
               boolean required = determineRequiredStatus(ann);
               //在这里将方法生成一个属性描述器,这里面判断了是写入方法还是读取方法
//             这里的没隔方法的一些细节逻辑封装的有点多,我在这里大部分是为了把spirng的大部分逻辑和思想得到
               //所以一些特别处理的地方就没有去细看,有兴趣的可以去细看下,比如下面这行代码是如何处理的
               PropertyDescriptor pd = BeanUtils.findPropertyForMethod(bridgedMethod, clazz);
               //封装好了AutowiredMethodElement,然后放入缓存
               currElements.add(new AutowiredMethodElement(method, required, pd));
            }
         });

         //每次循环找到注入点注入到currElements后,加入到elements
         elements.addAll(0, currElements);
         //每次本类找到过后,然后获取父类,一级一级的往上找
         targetClass = targetClass.getSuperclass();
      }
      while (targetClass != null && targetClass != Object.class);
      //这里将找到的注入点elements封装成一个InjectionMetadata返回,如果elements=null,那么封装的是InjectionMetadata.EMPTY
      return InjectionMetadata.forElements(elements, clazz);
   }

   @Nullable
   private MergedAnnotation<?> findAutowiredAnnotation(AccessibleObject ao) {
      MergedAnnotations annotations = MergedAnnotations.from(ao);
      for (Class<? extends Annotation> type : this.autowiredAnnotationTypes) {
         MergedAnnotation<?> annotation = annotations.get(type);
         if (annotation.isPresent()) {
            return annotation;
         }
      }
      return null;
   }
   public AutowiredAnnotationBeanPostProcessor() {
   this.autowiredAnnotationTypes.add(Autowired.class);
   this.autowiredAnnotationTypes.add(Value.class);
   try {
      this.autowiredAnnotationTypes.add((Class<? extends Annotation>)
            ClassUtils.forName("javax.inject.Inject", AutowiredAnnotationBeanPostProcessor.class.getClassLoader()));
      logger.trace("JSR-330 'javax.inject.Inject' annotation found and supported for autowiring");
   }
   catch (ClassNotFoundException ex) {
      // JSR-330 API not available - simply skip.
   }
}

源码的注释在上面都已经写了,这边总结下spring的依赖注入@AutoWired的找寻注入点的原理:
1.spring在这个后置处理器中提供了两种方式的依赖注入,属性注入和普通非静态方法的注入;
2.首先根据传过来的bean,找到所有的声明的属性和方法,然后循环这个类,因为这个类可能有父类,找寻要找到所有的父类中看是否有注入的属性和方法,是根据是否实现了@AutoWired来找的;
3.如果找到了属性或者方法,那么如果是属性,就构造一个对象AutowiredFieldElement 或者AutowiredMethodElement,放入缓存,属性对象和方法对象都实现了InjectionMetadata.InjectedElement,所以这两个对象中都实现了inject方法,用来后面注入的。
4.InjectElement就是注入的对象点,也就是需要依赖注入的属性或者方法都保存在InjectElement里面,我们来看下InjectElement这个对象的结构:

/**
 * A single injected element.
 * 注入点,spring的依赖注入的注入点就是InjectedElement
 * member可以是Field或者Method
 */
public abstract static class InjectedElement {

   //注入的成员类型,Field或者Member
   protected final Member member;
       //注入点是否是属性Field
   protected final boolean isField;

   //属性的描述器,如果是属性注入的注入点,那么这个pd值是空的,只有方法的注入才有
   @Nullable
   protected final PropertyDescriptor pd;

   @Nullable
   protected volatile Boolean skip;

   protected InjectedElement(Member member, @Nullable PropertyDescriptor pd) {
      //member中可以是Field可以是method
      this.member = member;
      this.isField = (member instanceof Field);
      this.pd = pd;
   }
   ......

其中member可以是属性可以是方法,就根据你存入的是AutowiredMethodElement还是AutowiredFieldElement;
5.最后找到的所有注入点都缓存到对象private final Map<String, InjectionMetadata> injectionMetadataCache = new ConcurrentHashMap<>(256)中;

@AutoWired依赖注入

@AutoWired的依赖注入也是在bean的后置处理器中实现的,具体的代码是在populateBean这个方法里面,代码片段如下:

/**
    * 这里调用的又是bean的后置处理器,这里的后置处理器是在bean属性填充过后的bean后置处理器
    * 这个后置处理器正在现在用的最多,spring内部定义的InstantiationAwareBeanPostProcessor实现了这个接口,主要处理的是
    * @AutoWired的后置处理器,依赖注入的在这里调用的,最重要的是postProcessProperties这个方法
    * 所以InstantiationAwareBeanPostProcessor的后置处理器方法postProcessProperties是处理@AutoWired @Resource注解的
    * 具体来说就是:
    * @AutowiredannotationBeanPostProcessor处理的是@AutoWired、@Value,@Inject注解
    * @CommonAnnotationBeanPostProcessor处理的是@Resource注解
    * 都是在postProcessProperties方法中处理的
    */
   for (BeanPostProcessor bp : getBeanPostProcessors()) {
      if (bp instanceof InstantiationAwareBeanPostProcessor) {
         InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
         PropertyValues pvsToUse = ibp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);
         if (pvsToUse == null) {
            if (filteredPds == null) {
               filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
            }
            pvsToUse = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
            if (pvsToUse == null) {
               return;
            }
         }
         pvs = pvsToUse;
      }
   }
}

主要是调用后置处理器中的方法postProcessProperties

public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {
   //在实例化过后调用的后置处理器先将注入点找到并且准入到了缓存injectionMetadataCache中了
   //所以这里的就是从缓存中获取,当然了如果在前面的后置处理器中没有注入成功,那么这个也会去注入,一般不会出现这种情况
   //metadata就是bean类的所有注入点,只包括两种:普通非静态方法的注入点和非静态属性的注入点
   //这里的注入点有两个,属性和犯法,所以下面的调用也分为两种
   InjectionMetadata metadata = findAutowiringMetadata(beanName, bean.getClass(), pvs);
   try {
      //开始注入,这里的注入根据是属性和方法调用不同的注入方式
      //AutowiredFieldElement属性的注入
      //AutowiredMethodElement是方法的注入
      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;
}

上面的代码的inject是根据是属性注入还是方法注入调用具体的方法,AutowiredFieldElement中的inject方法和AutowiredMethodElement中的inject方法

AutowiredFieldElement.inejct

/**
       * 这里就是根据属性注入的逻辑
       * @param bean
       * @param beanName
       * @param pvs
       * @throws Throwable
       */
      @Override
      protected void inject(Object bean, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
         Field field = (Field) this.member;
         Object value;
         if (this.cached) {
            value = resolvedCachedArgument(beanName, this.cachedFieldValue);
         }
         else {
//          和xml那边一模一样的,就是先通过属性来构造一个依赖描述器
            DependencyDescriptor desc = new DependencyDescriptor(field, this.required);
            desc.setContainingClass(bean.getClass());
            Set<String> autowiredBeanNames = new LinkedHashSet<>(1);
            Assert.state(beanFactory != null, "No BeanFactory available");
            TypeConverter typeConverter = beanFactory.getTypeConverter();
            try {
               //然后通过依赖描述器来找到一个bean,请注意,这里是属性的依赖注入,比如private UserService uservice
//             //那么这里是来找到bean类下面的属性UserService在spring容器中的ben对象,也就是value
               //resolveDependency在这里是先byType,再byName,当byType有多个的时候,就要进行byName,所以在
//             //在spring中写注入@AutoWired对应的属性名称的时候尽量规范一点
               value = beanFactory.resolveDependency(desc, beanName, autowiredBeanNames, typeConverter);
            }
            catch (BeansException ex) {
               throw new UnsatisfiedDependencyException(null, beanName, new InjectionPoint(field), ex);
            }
            //下面的逻辑是如果开启了缓存cached,默认是false,然后取出注入的属性名称,也就是beanName,然后判断,设置缓存字段值
            synchronized (this) {
               if (!this.cached) {
                  if (value != null || this.required) {
                     this.cachedFieldValue = desc;
                     registerDependentBeans(beanName, autowiredBeanNames);
                     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;
               }
            }
         }
         if (value != null) {
            //如果找到了注入的bena,然后通过反射进行注入
            ReflectionUtils.makeAccessible(field);
            field.set(bean, value);
         }
      }
   }

AutowiredMethodElement.inject

/**
       * 方法的注入,方法注入的要点是:
       * 1.方法必须是普通的非静态方法(非构造方法,构造方法不在此处处理)
       * 2.方法的参数个数必须大于0,也就是至少为1个
       * 3.然后根据前两个条件,然后循环每一个方法的参数,请注意,每个参数应该都是一个bean对象,
       * 然后封装一个参数数组,最后通过反射调用方法进行注入
       * spring代码写的很多,但是我们研究spring的源码要看关键部分,关键部分就是它如何进行依赖注入的
       * 通过属性和普通方法,至于一些很细的细节,就算你现在弄清楚了,过一段时间也会忘,所以太细的如果不太理解,就飘过
       * @param bean
       * @param beanName
       * @param pvs
       * @throws Throwable
       */

      @Override
      protected void inject(Object bean, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
         if (checkPropertySkipping(pvs)) {
            return;
         }
//       方法的注入,member强制转换成一个Method
         Method method = (Method) this.member;
         Object[] arguments;
         if (this.cached) {
            // Shortcut for avoiding synchronization...
            arguments = resolveCachedArguments(beanName);
         }
         else {
            //得到方法参数的个数,并且封装一个Object arguments
            int argumentCount = method.getParameterCount();
//          //这个数组存放的是每个参数对应的bean在spring容器中的bean对象
            arguments = new Object[argumentCount];
            //这里存放的是每个参数对应在spring容器中的bean对象构建的依赖描述器
            DependencyDescriptor[] descriptors = new DependencyDescriptor[argumentCount];
            Set<String> autowiredBeans = new LinkedHashSet<>(argumentCount);
            Assert.state(beanFactory != null, "No BeanFactory available");
            TypeConverter typeConverter = beanFactory.getTypeConverter();
            //下面的代码逻辑就是循环每个方法参数,然后从spring容器中获取bean,然后填充到arguments中
//          逻辑都和属性注入一样,通过依赖描述器调用resolveDependency来获取一个bean对象
            for (int i = 0; i < arguments.length; i++) {
               MethodParameter methodParam = new MethodParameter(method, i);
               DependencyDescriptor currDesc = new DependencyDescriptor(methodParam, this.required);
               currDesc.setContainingClass(bean.getClass());
               descriptors[i] = currDesc;
               try {
                  Object arg = beanFactory.resolveDependency(currDesc, beanName, autowiredBeans, typeConverter);
                  if (arg == null && !this.required) {
                     arguments = null;
                     break;
                  }
                  arguments[i] = arg;
               }
               catch (BeansException ex) {
                  throw new UnsatisfiedDependencyException(null, beanName, new InjectionPoint(methodParam), ex);
               }
            }
            synchronized (this) {
               if (!this.cached) {
                  if (arguments != null) {
                     DependencyDescriptor[] cachedMethodArguments = Arrays.copyOf(descriptors, arguments.length);
                     registerDependentBeans(beanName, autowiredBeans);
                     if (autowiredBeans.size() == argumentCount) {
                        Iterator<String> it = autowiredBeans.iterator();
                        Class<?>[] paramTypes = method.getParameterTypes();
                        for (int i = 0; i < paramTypes.length; i++) {
                           String autowiredBeanName = it.next();
                           if (beanFactory.containsBean(autowiredBeanName) &&
                                 beanFactory.isTypeMatch(autowiredBeanName, paramTypes[i])) {
                              cachedMethodArguments[i] = new ShortcutDependencyDescriptor(
                                    descriptors[i], autowiredBeanName, paramTypes[i]);
                           }
                        }
                     }
                     this.cachedMethodArguments = cachedMethodArguments;
                  }
                  else {
                     this.cachedMethodArguments = null;
                  }
                  this.cached = true;
               }
            }
         }
         if (arguments != null) {
            try {
               //然后进行调用,就类似于setXxx(UserService u1,UsereSerivce u2),两个参数就是argumentgs
               //arguments就是上面循环从spring容器中获取的
               ReflectionUtils.makeAccessible(method);
               method.invoke(bean, arguments);
            }
            catch (InvocationTargetException ex) {
               throw ex.getTargetException();
            }
         }
      }

大概总结下spring的@AutoWired依赖注入的要点:
1.从缓存中获取注入点,然后开始循环注入点;
2.如果是属性的注入点,那么就调用AutowiredFieldElement中的inject方法,在该方法中处理不用看spring源码大家也能知道,无非就是通过反射对feild进行赋值,也就是set方法区赋值,但是这里有点重要的点就是spring的@AutoWired是先byType,在byName的,什么意思呢?在注入的方法中有个方法特别重要就是resolveDependency,这个方法就是根据你注入的属性去spring的容器中找到对应的bean;比如我们有个属性是private UserService userservice;那么spring会根据userserivce去spring容器中找到,找到了直接返回,然后调用field.set进行注入赋值;但是在这个过程中spring的处理方式是:
先根据byType,也就是你的UserService找到对应的bean对象列表,这个时候分为三种情况:
1).如果为空,则证明在spring容器中不存在这个bean,如果这个时候你的@AutoWired设置了required属性,并且为false,那么就注入不成功;
2).如果不为空,只有一条数据,则证明在容器中已经找到了相对应的bean,直接返回注入就可了。
3).如果返回多条,则证明在容器中存在多个相同的Bean对象,那么这个时候就要开始byName,根据字段的byName得到唯一的一个Bean,所以spring的@AutoWired依赖注入是先byType,在byName的。

3.如果是方法的注入点,那就调用AutowiredMethodElement中的inject方法,找bean的方式和属性的是一样的,我只是说byType和byName的方式和属性的是一样的,一样的调用了resolveDependency这个方法;但是方法的注入和属性注入不一样,比如我的注入方法如下:

public void setxxx(UserService userServie){
     .....
}
public void setxxx(UserService userServie,OrderService){
     .....
}

所以方法注入的要看方法的参数,所以spring的方法注入需要遵循两点:
1.方法的参数不能为空,为空谈何注入;
2.方法必须是普通的非静态方法。
那么spring会构建一个arguments数组,然后获取每个参数,然后根据参数去spring容器中找bean,找bean的过程也是先byType再byName,找到过后赋值给arguments[i]=object,最后找到了所有的参数对应的bean过后,执行
method.invoke(target,arguments)进行反射调用方法注入进行注入。

@Autowired例子演示

上面已经把@AutoWired的依赖注入的源码分析,但是我们要如何证明所述,其实属性的注入我就不演示不证明了,这个大家都用非常多,肯定是能注入的,我主要演示下方法的注入,一个参数和多个参数的方法注入:

@Component
public class UserService {


   private OrderService orderService1;

   private OrderService orderService2;

   @Autowired
   public void xxx(OrderService o1,OrderService o2){
      this.orderService1 = o1;
      this.orderService2 = o2;
   }




   public void test()
   {
      System.out.println("orderService1="+ orderService1);
      System.out.println("orderService2="+ orderService2);
   }
}

我的orderService1和orderService2都没有加@AutoWired注解,而是通过xxx方法进行注入的,看输出结果如下
在这里插入图片描述
所以spring是肯定能支持普通方法注入和属性注入的
最后附上一张@AutoWired依赖注入的图,仅供参考:
在这里插入图片描述

Spring依赖注入推荐使用构造函数注入而非@Autowired 在Spring框架中,依赖注入(Dependency Injection, DI)是实现组件之间松耦合的关键技术。Spring支持多种依赖注入方式,其中构造函数注入和基于@Autowired注解的注入是两种常见的方法。然而,Spring官方以及许多经验丰富的开发者更倾向于推荐使用构造函数注入。接下来,我们将详细解释为什么构造函数注入是更好的选择,以及它与@Autowired注解注入之间的主要区别。 阅读详情

相关推荐

Spring Boot如何使用@Autowired来实现依赖注入

为了详细地解释@Autowired在Spring Boot中的使用,我们将通过一个完整的实例和代码来展示其用法。在这个实例中,我们将创建一个简单的Spring Boot应用程序,演示如何使用@Autowired来实现依赖注入。

专注于深入研究多种编程语言,以实战为导向,逐步拓展开发技能,提升工程化编码和思维能力,展现无敌技术实力。 555

一文搞懂Spring @Autowired注解的使用及其原理

依赖注入(DI)是Spring核心特性之一,而@Autowired也是我们日常高频使用的Spring依赖注入方式之一,因此有必要对它的使用以及原理做一个全面的掌握。本文从@Autowired使用、原理入手记录,并扩展延伸Spring中其他具备注入功能的注解。

MarkusZhang的博客 1万+

Spring使用@Autowired为抽象父类注入依赖代码实例

主要介绍了Spring使用@Autowired为抽象父类注入依赖代码实例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下

【Spring】依赖注入(DI)时常用的注解@Autowired和@Value

如果是非SpringBoot配置文件,需要额外通过@PropertySource去指定属性文件的类路径,如果是SpringBoot配置文件(application.properties),就无需额外配置@PropertySource。

m0_65277261的博客 2418

python机器人编程——用pytorch实现六轴机械臂的正向和逆向数值解算,及python算法解析

前面对六轴(或多轴)机械臂进行了一些研究,特别是利用几何进行简化,实现逆解,来完成比较简单的搬用任务。然而,如果需要比较精确的操作任务,可能需要更加复杂的机械臂解算。其中比较复杂的是数值解算,这种解算往往涉及到比较复杂的机器人运动等原理知识,比较难以上手。但是,python的生态挺全面,已经有很多牛人实现了数值解法,但是去看他们的代码,还是觉得费劲。此外,随着深度神经网络的兴起,很多是用建立深度学习神经网络,去利用机械臂输入输出的大数据,训练机械臂的控制模型,这个上手也比较慢。

JAMES费的空间 5794

Labview实现服务器(server)与多客户端(clients)通信

服务器可以接收多个客户端发送的消息,并显示消息来源。 服务器可以发送消息到指定客户端 客户端可以自动连接服务器,断连后重连 客户端可以发送消息到服务器,可接收服务器消息 类似框架可以用做中央服务器及客户端项目

u013809089的博客 7980

@Autowired 注入三种方式

问题 在使用 IDEA 开发 SpringBoot 项目时,在Controller类中使用注解 @Autowired 注入一个依赖出现了警告提示。这是怎么回事? 当我们鼠标停留在警告线处会出现提示:Field injection is not recommended(不建议Field注入) Spring Bean 的注入方式 1.变量(Field)注 @RestController @RequestMapping(value = "/test") public class ParkMapContr

weixin_45342958的博客 7727

876-基于STM32的毫米波雷达智能睡眠监测系统

基于STM32的毫米波雷达智能睡眠监测系统通过非接触式毫米波雷达检测人体呼吸频率和体动次数,结合WIFI数据传输和OLED显示,实现睡眠质量分析与远程监控。系统核心功能包括生理参数采集、阈值设置、数据可视化及远程交互。

m0_50083169的博客 1544

【Java】Spring的依赖注入理解,@Autowired用法

依赖注入(Dependency Injection)由 Spring 容器来管理对象之间的依赖关系,并自动将依赖对象注入到目标对象中。问题回答什么是依赖注入?Spring 自动帮你把需要的对象注入进来怎么使用?构造器、Setter、字段注入(@Autowired@Autowired是干嘛的?注入引用类型(Bean)@Value是干嘛的?注入简单类型(字符串、数字等)为什么@Bean方法里可以直接加形参?Spring 会根据类型自动装配@Autowired这里不能用吗?在@Bean。

m0_74282926的博客 857

AGX Orin设计-外围电路设计之一

AGX ORIN是英伟达Jetson系列中算力规格最高端的模组,其高达200TOPS/275TOPS的算力可以为各类场景提供澎湃的算力支持,本篇文章针对AGX ORIN的常规外围电路设计做分析描述。

zhiyuchenkeji的博客 4484

UVM验证中,为什么我的pack_bytes()返回长度是0?手把手教你排查自定义do_pack函数

本文深入解析UVM验证中pack_bytes()返回长度为0的常见原因及系统排查方法。从UVM打包机制原理出发,详细列举了super.do_pack()缺失、field automation冲突等典型问题,并提供动态数组处理、位宽计算等进阶调试技巧,帮助开发者快速定位和解决自定义do_pack函数问题。

weixin_42523693的博客 127

Spring系列第21篇:注解实现依赖注入(@Autowired、@Resource、@Primary、@Qulifier)

先来看几个问题通过注解的方式注入依赖对象,介绍一下你知道的几种方式@Autowired和@Resource有何区别说一下@Autowired查找候选者的...

路人甲Java 4万+

卫星监测“America”级#两#栖#攻#击#舰#(LHA-6)出港

卫星监测“America”级#两#栖#攻#击#舰#(LHA-6)出港 前脚刚走,后脚又来,山姆大叔又来刷存在感,2020年7月28日,USS Ronald Reagan流窜在我国东海海区被卫星拍了下来: 2020年8月1日,最新卫星图像显示USS Ronald Reagan已经返回母港日本横须贺:距离其出港(2020年6月8日)已经过去了快两个月 然而事情并没有到此结束,“America”级#两#栖#攻#击#舰#(LHA-6)选择在 “八.一” 这个特殊的日子前后出港颇具挑衅的味道。 根据2020年

qq_46071146的博客 1565

Spring 依赖注入方式及@Autowired 和 @Resource

任何人都可以提交 JSR给 Java 官方,但只有最终确定的 JSR,才会以 JSR-XXX 的格式发布,如 JSR-250,而被发布的 JSR 就可以看作是 Java 语言的规范或标准。构造方法和属性注入不同,构造方法注入可适用于任何环境,无论是 IoC 框架还是非 IoC 框架,构造方法注入的代码都是通用的,所以它的通用性更好。因为依赖对象是在构造方法中执行的,而构造方法是在对象创建之初执行的,因此被注入的对象在使用之前,会被完全初始化,这也是构造方法注入的优点之一。...

cristianoxm的博客 2187

Java全栈AI视频生成开发实战:从DeepSeek接入到剪映自动化(附完整源码)

【代码】Java全栈AI视频生成开发实战:从DeepSeek接入到剪映自动化(附完整源码)

weixin_39169967的博客 4148

使用字体解密技术爬取懂车帝二手车数据

本文介绍了一种针对懂车帝二手车平台的字体加密数据采集方案。通过抓包分析,识别出关键API接口并解析了字体加密机制,成功实现了价格等敏感数据的解密。方案采用requests库发送POST请求获取JSON数据,利用fontTools解析字体映射关系,建立加密字符到真实数字的转换算法。程序支持多页采集,提取车辆名称、价格、年份等12个维度的信息,并自动保存为Excel格式。技术亮点包括动态字体解析、健壮的数据处理和分页优化,为二手车市场分析提供了可靠的数据支持。文中特别强调数据采集的合法合规性,建议仅用于学术研究

那些看似不起波澜的日复一日,会在某天让你看到坚持的意义 1313

Spring @Autowired:依赖注入的核心奥秘

Spring的@Autowired注解是实现依赖注入的关键机制,通过自动装配Bean来简化组件间的依赖管理。它可以标注在字段、构造方法、Setter方法或配置方法上,Spring容器会根据类型匹配自动注入依赖。该注解支持required属性控制依赖是否强制,并通过@Qualifier解决多Bean冲突。构造器注入是推荐方式,能保证依赖完整性和线程安全。@Autowired体现了控制反转思想,相比手动创建对象更利于松耦合和可测试性,是Spring框架实现IoC容器的核心手段之一。

2301_80215285的博客 557

C# WinForm 基于DirectShow.dll编写的程序,可边预览边保存视频,音频和图片

基于微软的DirectShow.dll的二次开发1.自动识别连接的摄像头跟麦克风且可以对其进行选择(默认选中第一个)2.可录制wmv和avi两种格式的视频并且都带有音频,avi可以录制的分辨率和帧数进行选择,wmv默认进行了淸晰度优化如不喜欢可去除代码中有相关提示3.可在预览点开之后进行拍照,也可边录制视频边拍照4.添加了视频和音频的压缩功能(酌情使用)这次二次开发发现C#对DirectShow的相关信息太少,这次做完也不敢藏私共享出来,还望大家指正

在Spring Boot中依赖注入的工具只有 @Autowired吗

在Spring Boot中依赖注入的工具只有 @Autowired吗

weixin_60680210的博客 1212

STM32F407中文手册

STM32f407中文手册 本参考手册面向应用开发人员,提供有关使用 STM32F405xx/07xx、STM32F415xx/17xx、 STM32F42xxx 和 STM32F43xxx 微控制器存储器与外设的完整信息。STM32F405xx/07xx、STM32F415xx/17xx、STM32F42xxx 和 STM32F43xxx 构成一个微 控制器系列,各产品具有不同的存储器大小、封装和外设。有关订购信息以及器件的机械与电气特性,请参见数据手册。有关 ARM Cortex™-M4F 内核的信息,请参见《Cortex™-M4F 技术参考手册》。

霍尼韦尔SoftMaster使用说明

霍尼韦尔SoftMaster使用说明

Spring 依赖注入之 @Autowired 与@Resource的区别

Spring不但支持自己定义的@Autowired注解,还支持几个由JSR-250规范定义的注解,它们分别是@Resource、@PostConstruct以及@PreDestroy。这里只说@Autowired和@Resource注解的区别。 1、@Autowired与@Resource都可以用来装配bean. 都可以写在字段上,或写在setter方法上。 2、@Autowired默认按...

MrLee的博客 1403

ET2012新版免狗免安装绿色软件

ET2012新版免狗免安祖昂绿色软件。,新界面,新视觉,

spring之普通工具类使用@Autowired依赖注入

使用到的注解@Component、@Autowried、@PostConstruct 一、类头部需要添加@Component ,把当前类注册成一个bean 二、在需要注入的类引入Autowired 三、使用@PostConstruct注解执行类所需的初始化操作 四、在别的类使用这个类的时候不能用new,只能用注入的方式 如下实例: @Component public clas...

Eflyings的博客 3198

spring源码-依赖注入@Autowired

依赖注入@Autowired

路漫漫其修远兮,吾将上下而求索。 395

Spring中注解@Autowired与@Resource的依赖注入源码分析

   上篇文章Spring中Xml配置Bean的依赖注入源码分析,讲的是通过XML方式配置Bean来实现依赖注入的,主要是通过BeanWrapperImpl.setPropertyValue方法,调用java类提供的Setter方法,利用反射机制注入属性值,完成依赖注入。     这次讲讲注解@Autowired与@Resource,是如何实现依赖注入的。     1.@Autowired实现依赖...

陈俊的马蹄印 4899

Spring依赖注入之@Autowired、@Qualifier、@Primary、@Priority注解用法

@Autowired注解可以声明一个bean依赖的其他bean,spring在创建bean时会将这些依赖的bean注入进来,涉及到的注解有@Autowired、@Value、@Qualifier、@Primary、@Priority,本节主要介绍@Autowired、@Qualifier、@Primary、@Priority这几个注解的用法

qq_32868023的博客 2708

Spring系列之注解实现依赖注入(@Autowired、@Resource、@Primary、@Qulifier)

先来看几个问题 通过注解的方式注入依赖对象,介绍一下你知道的几种方式 @Autowired和@Resource有何区别 说一下@Autowired查找候选者的过程 说一下@Resource查找候选者的过程 @Qulifier有哪些用法? @Qulifier加在类上面是干什么用的? @Primary是做什么的? 泛型注入用过么? 这些问题如果你都ok,那么恭喜你,很厉害。 本文内容 介绍spring中通过注解实现依赖注入的

azhou的代码园 5330

Spring依赖注入之@Autowired、@Qualifier、@Primary、@Priority注解原理(下)

@Autowired注解可以声明一个bean依赖的其他bean,spring在创建bean时会将这些依赖的bean注入进来。接依赖注入@Autowired原理(上),本节从AutowireCapableBeanFactory#resolveDependency方法开始分析resolveDependency方法的依赖注入过程。

qq_32868023的博客 1080

《Spring 框架必知必会:@Autowired 依赖注入的底层原理与场景实践》​

`@Autowired` 是 Spring 框架中用于实现 **依赖注入(Dependency Injection, DI)** 的核心注解之一。它的核心作用是自动装配 Bean,简化代码中对依赖对象的显式获取和管理。以下是详细解析: --- ### **一、核心作用** 1. **自动注入依赖** 自动查找匹配的 Bean 并注入到目标对象中,无需手动通过 `new` 或 `ApplicationContext.getBean()` 创建对象。 2. **降低耦合** 通过依赖注入

2401_83923080的博客 1505
上一篇: Spring bean生命周期之doCreateBean方法详解
下一篇: Spring依赖注入之注入Bean获取详解
Life  journey
博客等级 码龄17年 1万+粉丝 80原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值