Java @Autowired註解底層原理詳細分析

1.概念

@Autowired 是 Spring 提供的註解,默認的註入方式為 byType (按類型自動註入);@Autowired 註釋,它可以對類成員變量、方法及構造函數進行標註,完成自動裝配的工作;通過 @Autowired的使用來消除 set ,get方法。

2.註入數據的註解

@Value

含義:通過set方式註入基本類型與String,set方法可以省略

語法:@Value("數據")/@Value("${key}")

位置:修飾屬性,set方法

註意:如果動態獲取必須指定加載資源文件 <context:property-placeholderlocation="classpath:msg.properties"> </context:property-placeholder>

@Autowired

替換:autowire屬性,自動裝配(按照類型裝配,通過set方法,且方法可以省略)

位置:修飾屬性,set方法

語法:@Autowired(required="true")

註意:

1.如果容器中沒有一個可以與之匹配且required屬性為true則會報異常

NoSuchBeanDefinitionException

2.如果容器中有多個可以類型可以與之匹配,則自動切換為按照名稱裝配

3.如果名稱也沒有匹配,則報異常NoUniqueBeanDefinitionException

3.@Autowired註解是如何實現的

@Autowired註解在spring源代碼裡的定義:

package org.springframework.beans.factory.annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target({ElementType.CONSTRUCTOR, ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Autowired {
    boolean required() default true;
}

通過代碼看到Autowired註解可以應用在構造方法,普通方法,參數,字段,以及註解這五種類型的地方,它的保留策略是在運行時。

在Spring源代碼當中,Autowired註解位於包org.springframework.beans.factory.annotation之中,實現邏輯位於類:AutowiredAnnotationBeanPostProcessor之中。

核心處理代碼如下:

private InjectionMetadata buildAutowiringMetadata(final Class<?> clazz) {
  LinkedList<InjectionMetadata.InjectedElement> elements = new LinkedList<>();
  Class<?> targetClass = clazz;//需要處理的目標類
  do {
   final LinkedList<InjectionMetadata.InjectedElement> currElements = new LinkedList<>();
            /*通過反射獲取該類所有的字段,並遍歷每一個字段,並通過方法findAutowiredAnnotation遍歷每一個字段的所用註解,並如果用autowired修飾瞭,則返回auotowired相關屬性*/  
   ReflectionUtils.doWithLocalFields(targetClass, field -> {
    AnnotationAttributes ann = findAutowiredAnnotation(field);
    if (ann != null) {//校驗autowired註解是否用在瞭static方法上
     if (Modifier.isStatic(field.getModifiers())) {
      if (logger.isWarnEnabled()) {
       logger.warn("Autowired annotation is not supported on static fields: " + field);
      }
      return;
     }//判斷是否指定瞭required
     boolean required = determineRequiredStatus(ann);
     currElements.add(new AutowiredFieldElement(field, required));
    }
   });
            //和上面一樣的邏輯,但是是通過反射處理類的method
   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));
    }
   });
    //用@Autowired修飾的註解可能不止一個,因此都加在currElements這個容器裡面,一起處理  
   elements.addAll(0, currElements);
   targetClass = targetClass.getSuperclass();
  }
  while (targetClass != null && targetClass != Object.class);
  return new InjectionMetadata(clazz, elements);
 }

最後這個方法返回的就是包含所有帶有autowire註解修飾的一個InjectionMetadata集合。這個類由兩部分組成:

public InjectionMetadata(Class<?> targetClass, Collection<InjectedElement> elements) {
  this.targetClass = targetClass;
  this.injectedElements = elements;
 }

一是處理的目標類,二就是上述方法獲取到的所以elements集合。

有瞭目標類,與所有需要註入的元素集合之後,就可以實現autowired的依賴註入邏輯瞭,實現的方法如下:

@Override
public PropertyValues postProcessPropertyValues(
  PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeanCreationException {
 
 InjectionMetadata metadata = findAutowiringMetadata(beanName, bean.getClass(), pvs);
 try {
  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;
}

它調用的方法是InjectionMetadata中定義的inject方法,如下

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()) {
   for (InjectedElement element : elementsToIterate) {
    if (logger.isTraceEnabled()) {
     logger.trace("Processing injected element of bean '" + beanName + "': " + element);
    }
    element.inject(target, beanName, pvs);
   }
  }
 }

其邏輯就是遍歷,然後調用inject方法,inject方法其實現邏輯如下:

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

inject也使用瞭反射技術並且依然是分成字段和方法去處理的。

到此這篇關於Java @Autowired註解底層原理詳細分析的文章就介紹到這瞭,更多相關Java @Autowired註解內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!

推薦閱讀: