美文网首页
Spring@Autowired注解自动注入流程是怎么样?

Spring@Autowired注解自动注入流程是怎么样?

作者: 程序员麦冬 | 来源:发表于2020-11-23 13:46 被阅读0次

    面试中碰到面试官问:”Spring 注解是如果工作的?“,当前我一惊,完了这不触及到我的知识误区了吗?,还好我机智,灵机一动回了句:Spring 注解的工作流程倒还没有看到,但是我知道@Autowired注解的工作流程,后面不用说了一顿巴拉,面试官都连连点头。

    面试中要活用转移话题,要避免回答 ”不知道“,要引导面试官掉入你擅长的技术,然后才有机会教他作人。

    @Autowired 相关的类

    @Autowired 注解的主要功能就是完成自动注入,使用也非常简单(Spring都安排好了),但是要想知道 @Autowired 注解的内部现实,就需要看一下Spring源码了。接下来一步步的解剖 @Autowired 的实现原理,首先理一下与 @Autowired 注解相关的类,然后一步步的跟踪源码,直到理解 @Autowired 的原理。

    AutowiredAnnotationBeanPostProcessor 类

    AutowiredAnnotationBeanPostProcessor是实现 @Autowired 功能的主要类,它有一些方法是会用解析 @Autowired 注解并实现自动注入的功能,下面是它的继承图:

    从上图可以发现 AutowiredAnnotationBeanPostProcessor 最上层是 BeanPostProcessor 是一个后处理器,当然除了后处理器外中间还有InstantiationAwareBeanPostProcessor和MergedBeanDefinitionPostProcessor:

    InstantiationAwareBeanPostProcessor 接口

    postProcessBeforeInstantiation方法

    在Bean实例化之前调用,可以返回一个Bean实例,默认返回null。

    @Nullabledefault Object postProcessBeforeInstantiation(Class<?> beanClass, String 
    beanName) throws BeansException {      return null;}
    

    postProcessAfterInstantiation方法

    在Bean创建完成后,设置属性之前调用。

    default boolean postProcessAfterInstantiation(Object bean, String 
    beanName) throws BeansException {      return true;}
    

    postProcessProperties方法

    @Nullable default PropertyValues postProcessProperties(PropertyValues pvs, Object 
    bean, String beanName)            throws BeansException {      return null;}
    

    Bean创建完后,设置属性之前调用

    先记住 InstantiationAwareBeanPostProcessor 接口,后面会跟踪调用它的地方,就很容易理解了。

    MergedBeanDefinitionPostProcessor

    MergedBeanDefinitionPostProcessor 也是一个继承 BeanPostProcessor 接口的后处理器,它的主要作用就是可以处理操作BeanDefinition对象,由于Bean的实例化是通过 BeanDefinition 的, 通过操作BeanDefinition ,这样可以使Bean的实例化时发生一些变化。

    MergedBeanDefinitionPostProcessor 只有两个方法

    postProcessMergedBeanDefinition方法

    void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, 
    Class<?> beanType, String beanName);
    

    Bean的BeanDefinition 被合并后调用此方法。

    resetBeanDefinition

    default void resetBeanDefinition(String beanName) {}
    

    当一个BeanDefinition被重置后调用 。

    AutowireCapableBeanFactory 接口

    AutowireCapableBeanFactory继承自BeanFactory,除了提供基础的Bean操作外,从接口的名字就可以推断出的它还有自动注入的能力。AutowireCapableBeanFactory 提供四种注入模型:

    • AUTOWIRE_NO: 没有显示的定义注入模型
    • AUTOWIRE_BY_NAME: 通过Bean名称注入
    • AUTOWIRE_BY_TYPE: 通过Bean的类型注入
    • AUTOWIRE_CONSTRUCTOR:通过Bean的构造方法注入

    AutowireCapableBeanFactory 接口有不少方法,但大部分都是跟自动注入的相关。@Autowired 的主要功能就是在Bean实例化后,为其设置属性,所以在 AutowireCapableBeanFactory 接口有一个createBean方法,用于创建Bean并设置Bean的属性:

    <T> T createBean(Class<T> beanClass) throws BeansException;
    

    createBean方法,它的调用时机是创建Bean的时候,稍后会说到它的调用时机。

    AbstractAutowireCapableBeanFactory

    AbstractAutowireCapableBeanFactory 继承 AbstractBeanFactory并实现了AutowireCapableBeanFactory接口,所以它也实现了AutowireCapableBeanFactory中的createBean方法。

    public <T> T createBean(Class<T> beanClass) throws BeansException {     
    
    // Use prototype bean definition, to avoid registering bean as dependent bean.      
    
    RootBeanDefinition bd = new RootBeanDefinition(beanClass);      
    bd.setScope(SCOPE_PROTOTYPE);     
    
    bd.allowCaching = ClassUtils.isCacheSafe(beanClass, getBeanClassLoader());      
    
    return (T) createBean(beanClass.getName(), bd, null);}
    

    Bean创建的生命周期

    通过了解Bean创建的生命周期,才可以将上面与 @Autowired 相关的类串起来,首先这里不会过多的介绍Bean的创建细节,只关注自动注入相关的代码。

    Bean的创建过程

    Spring中默认的Bean都是懒加载的,所以一个Bean的创建会从调用getBean方法开始,如果不考虑缓存、上层容器的情况,Bean的创建会经过以下方法:

    • getBean:BeanFactory的方法,获取Bean实例
    • doGetBean:获取Bean的实例,获取顺序依次为:单例池、父容器,如果从以上2种途径都没获取到Bean实例就会创建新的
    • createBean:创建 Bean,这里的createBean,跟上面介绍的是一回事
    • doCreateBean:创建Bean实例
    • populateBean:设置Bean属性

    以上流程中的getBean和doGetBean不多作说明了, 重点关注createBean前面提到AbstractAutowireCapableBeanFactory.createBean方法,所以说你在调用getBean方法获取Bean的实例时,如果这个Bean实例还没有被创建,那么createBean就会被调用。

    通过简单的说明Bean创建的生命周期,就能找到 @Autowired 注解实现的入口,接下来再继续跟踪createBean方法。

    收集注入元信息

    收集注入元信息的步骤的,其实就是调用AutowiredAnnotationBeanPostProcessor类方法来实现的。

    Bean 创建之前

    以下是createBean方法,在Bean创建之前调用postProcessBeforeInstantiation的地方。为是阅读方便省略了一些代码,大致的流程就是:

    • 首先调用 resolveBeforeInstantiation 方法,执行 InstantiationAwareBeanPostProcessor.postProcessBeforeInstantiation方法
    • 如果postProcessBeforeInstantiation返回Bean实例那么直接返回这个实例,如果返回nul 继续调用doCreateBean
    @Override
    protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
          throws BeanCreationException {
    
       ...
    
       try {
          // Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.
          Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
          if (bean != null) {
             return bean;
          }
       }
       catch (Throwable ex) {
            ...
       }
    
         ...
        Object beanInstance = doCreateBean(beanName, mbdToUse, args);
        ...
    
       ...
     }
    
     @Nullable
    protected Object resolveBeforeInstantiation(String beanName, RootBeanDefinition mbd) {
       Object bean = null;
       if (!Boolean.FALSE.equals(mbd.beforeInstantiationResolved)) {
          // Make sure bean class is actually resolved at this point.
          if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
             Class<?> targetType = determineTargetType(beanName, mbd);
             if (targetType != null) {
                bean = applyBeanPostProcessorsBeforeInstantiation(targetType, beanName);
                if (bean != null) {
                   bean = applyBeanPostProcessorsAfterInitialization(bean, beanName);
                }
             }
          }
          mbd.beforeInstantiationResolved = (bean != null);
       }
       return bean;
    }
    

    这里 AutowiredAnnotationBeanPostProcessor 的 postProcessBeforeInstantiation 的方法会被调用,由于AutowiredAnnotationBeanPostProcessor 并没有重写这个方法,所以什么都不做。

    操作 BeanDefinition

    上面说过 postProcessBeforeInstantiation 方法返回 null 的话会继续执行doCreateBean方法:

     protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
          throws BeanCreationException {
    
       // Allow post-processors to modify the merged bean definition.
       synchronized (mbd.postProcessingLock) {
          if (!mbd.postProcessed) {
             try {
                applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
             }
             catch (Throwable ex) {
                throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                      "Post-processing of merged bean definition failed", ex);
             }
             mbd.postProcessed = true;
          }
       }
    
      ...
     populateBean(beanName, mbd, instanceWrapper);
     ...
    

    在 doCreateBean 方法中,会调用调用applyMergedBeanDefinitionPostProcessors方法:

    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);
          }
       }
    

    MergedBeanDefinitionPostProcessor接口上面提到到的,AutowiredAnnotationBeanPostProcessor 实现了这个接口所以直接进入到 AutowiredAnnotationBeanPostProcessor 中的 postProcessMergedBeanDefinition方法:

    
    @Override
    public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {
       InjectionMetadata metadata = findAutowiringMetadata(beanName, beanType, null);
       metadata.checkConfigMembers(beanDefinition);
    }
    

    查找注入元数据

    接着继续进入到findAutowiringMetadata,findAutowiringMetadata 会调用buildAutowiringMetadata方法创建注入元数据,然后将元数据缓存到injectionMetadataCache属性中:

    
    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.
       InjectionMetadata metadata = this.injectionMetadataCache.get(cacheKey);
       if (InjectionMetadata.needsRefresh(metadata, clazz)) {
          synchronized (this.injectionMetadataCache) {
             metadata = this.injectionMetadataCache.get(cacheKey);
             if (InjectionMetadata.needsRefresh(metadata, clazz)) {
                ...
                metadata = buildAutowiringMetadata(clazz);
                this.injectionMetadataCache.put(cacheKey, metadata);
             }
          }
       }
       return metadata;
    }
    

    创建注入元数据

    仔细查看buildAutowiringMetadata方法的实现,它会反射类的方法和属性,同时还会向上查找父类,然后生成InjectionMetadata。

    private InjectionMetadata buildAutowiringMetadata(final Class<?> clazz) {
            if (!AnnotationUtils.isCandidateClass(clazz, this.autowiredAnnotationTypes)) {
                return InjectionMetadata.EMPTY;
            }
    
            List<InjectionMetadata.InjectedElement> elements = new ArrayList<>();
            Class<?> targetClass = clazz;
    
            do {
                final List<InjectionMetadata.InjectedElement> currElements = new ArrayList<>();
    
                ReflectionUtils.doWithLocalFields(targetClass, field -> {
                    MergedAnnotation<?> ann = findAutowiredAnnotation(field);
                    if (ann != null) {
                        if (Modifier.isStatic(field.getModifiers())) {
                            if (logger.isInfoEnabled()) {
                                logger.info("Autowired annotation is not supported on static fields: " + field);
                            }
                            return;
                        }
                        boolean required = determineRequiredStatus(ann);
                        currElements.add(new AutowiredFieldElement(field, required));
                    }
                });
    
                ReflectionUtils.doWithLocalMethods(targetClass, method -> {
                    Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(method);
                    if (!BridgeMethodResolver.isVisibilityBridgeMethodPair(method, bridgedMethod)) {
                        return;
                    }
                    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;
                        }
                        if (method.getParameterCount() == 0) {
                            if (logger.isInfoEnabled()) {
                                logger.info("Autowired annotation should only be used on methods with parameters: " +
                                        method);
                            }
                        }
                        boolean required = determineRequiredStatus(ann);
                        PropertyDescriptor pd = BeanUtils.findPropertyForMethod(bridgedMethod, clazz);
                        currElements.add(new AutowiredMethodElement(method, required, pd));
                    }
                });
    
                elements.addAll(0, currElements);
                targetClass = targetClass.getSuperclass();
            }
            while (targetClass != null && targetClass != Object.class);
    
            return InjectionMetadata.forElements(elements, clazz);
        }
    

    小结

    收集注入元数据过程,首先调用AutowiredAnnotationBeanPostProcessor.postProcessMergedBeanDefinition方法,然后调用findAutowiringMetadata方法查找元数据,如果找到相应类的注入元数据 ,就会调用buildAutowiringMetadata方法创建InjectionMetadata,最后将新创建的注入元数据保存在injectionMetadataCache缓存起来。

    设置Bean属性

    收信完注入元数据后,Bean的属性还是没有注入的,还需要将执行属性注入。还是在doCreateBean方法中,收集完注入元数据后,紧接着会调用populateBean:

    protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
    
    boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();
    boolean needsDepCheck = (mbd.getDependencyCheck() != AbstractBeanDefinition.DEPENDENCY_CHECK_NONE);
    
    PropertyDescriptor[] filteredPds = null;
    if (hasInstAwareBpps) {
       if (pvs == null) {
          pvs = mbd.getPropertyValues();
       }
       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;
          }
       }
       }
    }
    
    

    可以看到在populateBean中会调用InstantiationAwareBeanPostProcessor.postProcessProperties方法,由于已经知道 AutowiredAnnotationBeanPostProcessor 是实现 InstantiationAwareBeanPostProcessor 的,所以可以直接查看实现方法:

    @Override
    public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {
       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;
    }
    
    

    postProcessProperties就很简单的,查找 InjectMetadata,然后调用 InjectMetadata.inject方法。到这里其实就已经知道@Autowire的实现机制了,接下来就是根据InjectionMetadata中的信息实现属性注入了。

    如果需要深入研究的话,有兴趣的还可以继续往下看。

    总结

    本文大致讲解了 @Autowire 相关的类与实现的机制,@Autowire 注解的实现主要是理解AutowiredAnnotationBeanPostProcessor类,还有收集注入元数据、设置注入属性的调用时机。

    通过查看AutowiredAnnotationBeanPostProcessor类源码,相信你也可以自定义注入功能。

    最后

    感谢大家看到这里,如果本文有什么不足之处,欢迎多多指教;如果你觉得对你有帮助,请给我点个赞。
    也欢迎大家关注我的公众号:程序员麦冬,每天更新行业资讯!

    相关文章

      网友评论

          本文标题:Spring@Autowired注解自动注入流程是怎么样?

          本文链接:https://www.haomeiwen.com/subject/bpamiktx.html