最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Java @Autowired注解底層原理詳細(xì)分析

 更新時(shí)間:2022年11月05日 10:11:17   作者:OlaiolaiO  
@Autowired注解可以用在類屬性,構(gòu)造函數(shù),setter方法和函數(shù)參數(shù)上,該注解可以準(zhǔn)確地控制bean在何處如何自動(dòng)裝配的過程。在默認(rèn)情況下,該注解是類型驅(qū)動(dòng)的注入

1.概念

@Autowired 是 Spring 提供的注解,默認(rèn)的注入方式為 byType (按類型自動(dòng)注入);@Autowired 注釋,它可以對(duì)類成員變量、方法及構(gòu)造函數(shù)進(jìn)行標(biāo)注,完成自動(dòng)裝配的工作;通過 @Autowired的使用來消除 set ,get方法。

2.注入數(shù)據(jù)的注解

@Value

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

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

位置:修飾屬性,set方法

注意:如果動(dòng)態(tài)獲取必須指定加載資源文件 <context:property-placeholderlocation="classpath:msg.properties"> </context:property-placeholder>

@Autowired

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

位置:修飾屬性,set方法

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

注意:

1.如果容器中沒有一個(gè)可以與之匹配且required屬性為true則會(huì)報(bào)異常

NoSuchBeanDefinitionException

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

3.如果名稱也沒有匹配,則報(bào)異常NoUniqueBeanDefinitionException

3.@Autowired注解是如何實(shí)現(xiàn)的

@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注解可以應(yīng)用在構(gòu)造方法,普通方法,參數(shù),字段,以及注解這五種類型的地方,它的保留策略是在運(yùn)行時(shí)。

在Spring源代碼當(dāng)中,Autowired注解位于包org.springframework.beans.factory.annotation之中,實(shí)現(xiàn)邏輯位于類:AutowiredAnnotationBeanPostProcessor之中。

核心處理代碼如下:

private InjectionMetadata buildAutowiringMetadata(final Class<?> clazz) {
  LinkedList<InjectionMetadata.InjectedElement> elements = new LinkedList<>();
  Class<?> targetClass = clazz;//需要處理的目標(biāo)類
  do {
   final LinkedList<InjectionMetadata.InjectedElement> currElements = new LinkedList<>();
            /*通過反射獲取該類所有的字段,并遍歷每一個(gè)字段,并通過方法findAutowiredAnnotation遍歷每一個(gè)字段的所用注解,并如果用autowired修飾了,則返回auotowired相關(guān)屬性*/  
   ReflectionUtils.doWithLocalFields(targetClass, field -> {
    AnnotationAttributes ann = findAutowiredAnnotation(field);
    if (ann != null) {//校驗(yàn)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修飾的注解可能不止一個(gè),因此都加在currElements這個(gè)容器里面,一起處理  
   elements.addAll(0, currElements);
   targetClass = targetClass.getSuperclass();
  }
  while (targetClass != null && targetClass != Object.class);
  return new InjectionMetadata(clazz, elements);
 }

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

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

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

有了目標(biāo)類,與所有需要注入的元素集合之后,就可以實(shí)現(xiàn)autowired的依賴注入邏輯了,實(shí)現(xiàn)的方法如下:

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

它調(diào)用的方法是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);
   }
  }
 }

其邏輯就是遍歷,然后調(diào)用inject方法,inject方法其實(shí)現(xiàn)邏輯如下:

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也使用了反射技術(shù)并且依然是分成字段和方法去處理的。

到此這篇關(guān)于Java @Autowired注解底層原理詳細(xì)分析的文章就介紹到這了,更多相關(guān)Java @Autowired注解內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • java教程之java注解annotation使用方法

    java教程之java注解annotation使用方法

    這篇文章主要介紹了java注解annotation使用方法,注解可以定義到方法上,類上,一個(gè)注解相當(dāng)與一個(gè)類,就相當(dāng)于實(shí)例了一個(gè)對(duì)象,加上了注解,就相當(dāng)于加了一個(gè)標(biāo)志
    2014-01-01
  • 如何查找YUM安裝的JAVA_HOME環(huán)境變量詳解

    如何查找YUM安裝的JAVA_HOME環(huán)境變量詳解

    這篇文章主要給大家介紹了關(guān)于如何查找YUM安裝的JAVA_HOME環(huán)境變量的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧。
    2017-10-10
  • Java 網(wǎng)絡(luò)編程之 TCP 實(shí)現(xiàn)簡(jiǎn)單的聊天系統(tǒng)

    Java 網(wǎng)絡(luò)編程之 TCP 實(shí)現(xiàn)簡(jiǎn)單的聊天系統(tǒng)

    這篇文章主要介紹了Java 網(wǎng)絡(luò)編程之 TCP 實(shí)現(xiàn)簡(jiǎn)單的聊天系統(tǒng),幫助大家更好的理解和學(xué)習(xí)Java 網(wǎng)絡(luò)編程,感興趣的朋友可以了解下
    2020-11-11
  • Spring整合Mybatis 掃描注解創(chuàng)建Bean報(bào)錯(cuò)的解決方案

    Spring整合Mybatis 掃描注解創(chuàng)建Bean報(bào)錯(cuò)的解決方案

    這篇文章主要介紹了Spring 整合Mybatis 掃描注解創(chuàng)建Bean報(bào)錯(cuò)的解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-10-10
  • Java的StringBuilder在高性能場(chǎng)景下的正確用法

    Java的StringBuilder在高性能場(chǎng)景下的正確用法

    StringBuilder?對(duì)字符串的操作是直接改變字符串對(duì)象本身,而不是生成新的對(duì)象,所以新能開銷小.與StringBuffer相比StringBuilder的性能略高,StringBuilder則沒有保證線程的安全,從而性能略高于StringBuffer,需要的朋友可以參考下
    2023-05-05
  • Java+mysql本地圖片上傳數(shù)據(jù)庫及下載示例

    Java+mysql本地圖片上傳數(shù)據(jù)庫及下載示例

    本篇文章主要介紹了Java+mysql本地圖片上傳數(shù)據(jù)庫及下載示例,具有一定的參加價(jià)值,有興趣的可以了解一下。
    2017-01-01
  • java web中的servlet3 upload上傳文件實(shí)踐

    java web中的servlet3 upload上傳文件實(shí)踐

    這篇文章主要介紹了servlet3 upload上傳文件實(shí)踐,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友可以參考下
    2017-11-11
  • 詳解基于SpringBoot使用AOP技術(shù)實(shí)現(xiàn)操作日志管理

    詳解基于SpringBoot使用AOP技術(shù)實(shí)現(xiàn)操作日志管理

    這篇文章主要介紹了詳解基于SpringBoot使用AOP技術(shù)實(shí)現(xiàn)操作日志管理,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-11-11
  • Java Stax解析XML示例

    Java Stax解析XML示例

    這篇文章主要介紹了Java Stax解析XML示例,幫助大家更好的理解和使用Java,感興趣的朋友可以了解下
    2020-09-09
  • Java String 拼接字符串原理詳解

    Java String 拼接字符串原理詳解

    在本篇文章里小編給大家分享的是關(guān)于Java String 拼接字符串原理詳解的相關(guān)資源內(nèi)容,有需要的朋友們可以跟著學(xué)習(xí)參考下。
    2020-02-02

最新評(píng)論

日照市| 诸城市| 东乡| 凤翔县| 二连浩特市| 三河市| 潜江市| 巩义市| 七台河市| 张北县| 沙雅县| 东丽区| 崇礼县| 德昌县| 漳州市| 肃宁县| 堆龙德庆县| 凤翔县| 漳浦县| 崇信县| 榕江县| 偃师市| 博乐市| 合江县| 丹东市| 五华县| 元江| 建德市| 南川市| 砀山县| 内江市| 大宁县| 新安县| 龙里县| 岳普湖县| 济南市| 裕民县| 鄂尔多斯市| 城口县| 江油市| 定结县|