看完让你吊打面试官-@Autowired注解到底怎么实现的?(下)

简介: 看完让你吊打面试官-@Autowired注解到底怎么实现的?(下)

4 源码分析

通过org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor可以实现依赖自动注入

通过这个类来处理@Autowired @Value Spring

它也可以管理JSR-303的@Inject

  • AutowiredAnnotationBeanPostProcessor构造函数中定义要处理的注解
  • 41.png
  • 42.png
  • 之后,有几种方法对@Autowired处理


第一个,private InjectionMetadata buildAutowiringMetadata(final Class<?> clazz)解析等待自动注入类的所有属性。它通过分析所有字段和方法并初始化org.springframework.beans.factory.annotation.InjectionMetadata类的实例来实现。

private InjectionMetadata buildAutowiringMetadata(final Class<?> clazz) {
    LinkedList<InjectionMetadata.InjectedElement> elements = new LinkedList<>();
    Class<?> targetClass = clazz;
    do {
      final LinkedList<InjectionMetadata.InjectedElement> currElements = new LinkedList<>();
      //分析所有字段
      ReflectionUtils.doWithLocalFields(targetClass, field -> {
              //findAutowiredAnnotation(field)此方法后面会解释
        AnnotationAttributes ann = findAutowiredAnnotation(field);
        if (ann != null) {
          if (Modifier.isStatic(field.getModifiers())) {
            if (logger.isWarnEnabled()) {
              logger.warn("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;
        }
        AnnotationAttributes ann = findAutowiredAnnotation(bridgedMethod);
        if (ann != null && method.equals(ClassUtils.getMostSpecificMethod(method, clazz))) {
          if (Modifier.isStatic(method.getModifiers())) {
            if (logger.isWarnEnabled()) {
              logger.warn("Autowired annotation is not supported on static methods: " + method);
            }
            return;
          }
          if (method.getParameterCount() == 0) {
            if (logger.isWarnEnabled()) {
              logger.warn("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);
    //返回一个InjectionMetadata初始化的对象实例
    return new InjectionMetadata(clazz, elements);
  }
...
  /**
   * 'Native' processing method for direct calls with an arbitrary target instance,
   * resolving all of its fields and methods which are annotated with {@code @Autowired}.
   * @param bean the target instance to process
   * @throws BeanCreationException if autowiring failed
   */
  public void processInjection(Object bean) throws BeanCreationException {
    Class<?> clazz = bean.getClass();
    InjectionMetadata metadata = findAutowiringMetadata(clazz.getName(), clazz, null);
    try {
      metadata.inject(bean, null, null);
    }
    catch (BeanCreationException ex) {
      throw ex;
    }
    catch (Throwable ex) {
      throw new BeanCreationException(
          "Injection of autowired dependencies failed for class [" + clazz + "]", ex);
    }
  }

InjectionMetadata类包含要注入的元素的列表

43.png

注入是通过Java的API Reflection (Field set(Object obj, Object value) 或Method invoke(Object obj,Object … args)方法完成的

此过程直接在AutowiredAnnotationBeanPostProcessor的方法中调用

public void processInjection(Object bean) throws BeanCreationException

它将所有可注入的bean检索为InjectionMetadata实例,并调用它们的inject()方法

public class InjectionMetadata {
  ...
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);
        }
                //看下面静态内部类的方法
        element.inject(target, beanName, pvs);
      }
    }
  }
  ...
    public static abstract class InjectedElement {
    protected final Member member;
    protected final boolean isField;
      ...
        /**
     * Either this or {@link #getResourceToInject} needs to be overridden.
     */
    protected void inject(Object target, @Nullable String requestingBeanName, @Nullable PropertyValues pvs)
        throws Throwable {
      if (this.isField) {
        Field field = (Field) this.member;
        ReflectionUtils.makeAccessible(field);
        field.set(target, getResourceToInject(target, requestingBeanName));
      }
      else {
        if (checkPropertySkipping(pvs)) {
          return;
        }
        try {
                    //具体的注入看此处咯
          Method method = (Method) this.member;
          ReflectionUtils.makeAccessible(method);
          method.invoke(target, getResourceToInject(target, requestingBeanName));
        }
        catch (InvocationTargetException ex) {
          throw ex.getTargetException();
        }
      }
    }
      ...
    }
}

findAutowiredAnnotation(AccessibleObject ao)

分析属于一个字段或一个方法的所有注解来查找@Autowired注解。如果未找到@Autowired注解,则返回null,字段或方法也就视为不可注入。

1.png

目录
相关文章
|
架构师 Java 开发者
得物面试:Springboot自动装配机制是什么?如何控制一个bean 是否加载,使用什么注解?
在40岁老架构师尼恩的读者交流群中,近期多位读者成功获得了知名互联网企业的面试机会,如得物、阿里、滴滴等。然而,面对“Spring Boot自动装配机制”等核心面试题,部分读者因准备不足而未能顺利通过。为此,尼恩团队将系统化梳理和总结这一主题,帮助大家全面提升技术水平,让面试官“爱到不能自已”。
得物面试:Springboot自动装配机制是什么?如何控制一个bean 是否加载,使用什么注解?
|
Java 开发者
【面试题精讲】注解的解析方法有哪几种?
【面试题精讲】注解的解析方法有哪几种?
|
XML Java 关系型数据库
面试一口气说出Spring的声明式事务@Transactional注解的6种失效场景
面试一口气说出Spring的声明式事务@Transactional注解的6种失效场景
569 0
|
Java 编译器 数据库连接
Java面试题:什么是Java中的注解以及如何自定义注解?举例说明注解的经典用法
Java面试题:什么是Java中的注解以及如何自定义注解?举例说明注解的经典用法
265 0
|
Java 编译器 API
【面试问题】注解的实现原理?
【1月更文挑战第27天】【面试问题】注解的实现原理?
|
监控 NoSQL Java
面试官:实际工作中哪里用到了自定义注解?
面试官:实际工作中哪里用到了自定义注解?
213 2
|
Java 编译器 程序员
【面试题精讲】何谓注解?
【面试题精讲】何谓注解?
|
缓存 Java 调度
28个SpringBoot项目中常用注解,日常开发、求职面试不再懵圈(二)
28个SpringBoot项目中常用注解,日常开发、求职面试不再懵圈
207 0
|
JSON 缓存 Java
28个SpringBoot项目中常用注解,日常开发、求职面试不再懵圈(一)
28个SpringBoot项目中常用注解,日常开发、求职面试不再懵圈
411 0
|
Java
面试官,简单讲讲Java的注解
面试官,简单讲讲Java的注解
208 0