日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

@bean注解和@component注解的区别_通过源码查看 @Component,@Service 等注解是如何被解析的...

發布時間:2024/9/27 编程问答 26 豆豆
生活随笔 收集整理的這篇文章主要介紹了 @bean注解和@component注解的区别_通过源码查看 @Component,@Service 等注解是如何被解析的... 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

點擊上方“匠心零度”,選擇“設為星標”

做積極的人,而不是積極廢人

來源:my.oschina.net/floor/blog/4325651

  • 前言
  • 1.@Component解析流程
    • 找入口
    • 找核心方法
    • 概要分析
    • 2.查文檔找思路
  • 3. 探尋@Component派生性流程
    • 1. 確定metadataReader
    • 2.查看match方法找重點方法
    • 逐步分析
  • 總結

前言

@Component和@Service都是工作中常用的注解,Spring如何解析?

1.@Component解析流程

找入口

Spring Framework2.0開始,引入可擴展的XML編程機制,該機制要求XML Schema命名空間需要與Handler建立映射關系。

該關系配置在相對于classpath下的/META-INF/spring.handlers中。

如上圖所示 ContextNamespaceHandler對應context:... 分析的入口。

找核心方法

瀏覽ContextNamespaceHandler

在parse中有一個很重要的注釋

// Actually scan for bean definitions and register them.

ClassPathBeanDefinitionScanner scanner = configureScanner(parserContext, element);

大意是:ClassPathBeanDefinitionScanner#doScan是掃描BeanDefinition并注冊的實現

ClassPathBeanDefinitionScanner 的源碼如下:

protected?Set?doScan(String...?basePackages)?{
???Assert.notEmpty(basePackages,?"At?least?one?base?package?must?be?specified");
???Set?beanDefinitions?=?new?LinkedHashSet<>();for?(String?basePackage?:?basePackages)?{//findCandidateComponents?讀資源裝換為BeanDefinition
??????Set?candidates?=?findCandidateComponents(basePackage);for?(BeanDefinition?candidate?:?candidates)?{
?????????ScopeMetadata?scopeMetadata?=?this.scopeMetadataResolver.resolveScopeMetadata(candidate);
?????????candidate.setScope(scopeMetadata.getScopeName());
?????????String?beanName?=?this.beanNameGenerator.generateBeanName(candidate,?this.registry);if?(candidate?instanceof?AbstractBeanDefinition)?{
????????????postProcessBeanDefinition((AbstractBeanDefinition)?candidate,?beanName);
?????????}if?(candidate?instanceof?AnnotatedBeanDefinition)?{
????????????AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition)?candidate);
?????????}if?(checkCandidate(beanName,?candidate))?{
????????????BeanDefinitionHolder?definitionHolder?=?new?BeanDefinitionHolder(candidate,?beanName);
????????????definitionHolder?=
??????????????????AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata,?definitionHolder,?this.registry);
????????????beanDefinitions.add(definitionHolder);
????????????registerBeanDefinition(definitionHolder,?this.registry);
?????????}
??????}
???}return?beanDefinitions;
}

上邊的代碼,從方法名,猜測:

findCandidateComponents:從classPath掃描組件,并轉換為備選BeanDefinition,也就是要做的解析@Component的核心方法。

概要分析

findCandidateComponents在其父類ClassPathScanningCandidateComponentProvider 中。

public?class?ClassPathScanningCandidateComponentProvider?implements?EnvironmentCapable,?ResourceLoaderAware?{
//省略其他代碼
public?Set?findCandidateComponents(String?basePackage)?{
???if?(this.componentsIndex?!=?null?&&?indexSupportsIncludeFilters())?{
??????return?addCandidateComponentsFromIndex(this.componentsIndex,?basePackage);
???}
???else?{
??????return?scanCandidateComponents(basePackage);
???}
}
private?Set?scanCandidateComponents(String?basePackage)?{
???Set?candidates?=?new?LinkedHashSet<>();try?{
??????String?packageSearchPath?=?ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX?+
????????????resolveBasePackage(basePackage)?+?'/'?+?this.resourcePattern;
??????Resource[]?resources?=?getResourcePatternResolver().getResources(packageSearchPath);//省略部分代碼for?(Resource?resource?:?resources)?{//省略部分代碼if?(resource.isReadable())?{try?{
???????????????MetadataReader?metadataReader?=?getMetadataReaderFactory().getMetadataReader(resource);if?(isCandidateComponent(metadataReader))?{
??????????????????ScannedGenericBeanDefinition?sbd?=?new?ScannedGenericBeanDefinition(metadataReader);
??????????????????sbd.setSource(resource);if?(isCandidateComponent(sbd))?{
?????????????????????candidates.add(sbd);//省略部分代碼
??????}
???}catch?(IOException?ex)?{//省略部分代碼?}return?candidates;
}
}

findCandidateComponents大體思路如下:

  • String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX resolveBasePackage(basePackage) + '/' + this.resourcePattern; ? ? ? ? ? ? ? ? ? ? ? ? ? ?將package轉化為ClassLoader類資源搜索路徑packageSearchPath,例如:com.wl.spring.boot轉化為classpath*:com/wl/spring/boot/**/*.class
  • Resource[] resources = getResourcePatternResolver().getResources(packageSearchPath); 加載搜素路徑下的資源。
  • isCandidateComponent 判斷是否是備選組件
  • candidates.add(sbd); 添加到返回結果的list
  • ClassPathScanningCandidateComponentProvider#isCandidateComponent其源碼如下:

    protected?boolean?isCandidateComponent(MetadataReader?metadataReader)?throws?IOException?{
    ????//省略部分代碼
    ???for?(TypeFilter?tf?:?this.includeFilters)?{
    ??????if?(tf.match(metadataReader,?getMetadataReaderFactory()))?{
    ?????????return?isConditionMatch(metadataReader);
    ??????}
    ???}
    ???return?false;
    }

    includeFilters由registerDefaultFilters()設置初始值,有@Component,沒有@Service啊?

    protected?void?registerDefaultFilters()?{
    ???this.includeFilters.add(new?AnnotationTypeFilter(Component.class));
    ???ClassLoader?cl?=?ClassPathScanningCandidateComponentProvider.class.getClassLoader();
    ???try?{
    ??????this.includeFilters.add(new?AnnotationTypeFilter(
    ????????????((Class?extends?Annotation>)?ClassUtils.forName("javax.annotation.ManagedBean",?cl)),?false));
    ??????logger.trace("JSR-250?'javax.annotation.ManagedBean'?found?and?supported?for?component?scanning");
    ???}
    ???catch?(ClassNotFoundException?ex)?{
    ??????//?JSR-250?1.1?API?(as?included?in?Java?EE?6)?not?available?-?simply?skip.
    ???}
    ???try?{
    ??????this.includeFilters.add(new?AnnotationTypeFilter(
    ????????????((Class?extends?Annotation>)?ClassUtils.forName("javax.inject.Named",?cl)),?false));
    ??????logger.trace("JSR-330?'javax.inject.Named'?annotation?found?and?supported?for?component?scanning");
    ???}
    ???catch?(ClassNotFoundException?ex)?{
    ??????//?JSR-330?API?not?available?-?simply?skip.
    ???}
    }

    Spring如何處理@Service的注解的呢????

    2.查文檔找思路

    查閱官方文檔,下面這話:

    https://docs.spring.io/spring/docs/5.0.17.RELEASE/spring-framework-reference/core.html#beans-meta-annotations

    @Component is a generic stereotype for any Spring-managed component. @Repository, @Service, and @Controller are specializations of @Component

    大意如下:

    @Component是任何Spring管理的組件的通用原型。@Repository、@Service和@Controller是派生自@Component。

    @Target({ElementType.TYPE})
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    //?@Service?派生自@Component
    @Component
    public?@interface?Service?{

    ???/**
    ????*?The?value?may?indicate?a?suggestion?for?a?logical?component?name,
    ????*?to?be?turned?into?a?Spring?bean?in?case?of?an?autodetected?component.
    ????*?@return?the?suggested?component?name,?if?any?(or?empty?String?otherwise)
    ????*/
    ???@AliasFor(annotation?=?Component.class)
    ???String?value()?default?"";

    }

    @Component是@Service的元注解,Spring 大概率,在讀取@Service,也讀取了它的元注解,并將@Service作為@Component處理。

    3. 探尋@Component派生性流程

    回顧ClassPathScanningCandidateComponentProvider 中的關鍵的代碼片段如下:

    private?Set?scanCandidateComponents(String?basePackage)?{
    ?//省略其他代碼
    ?MetadataReader?metadataReader
    ?????????????=getMetadataReaderFactory().getMetadataReader(resource);
    ???if(isCandidateComponent(metadataReader)){
    ???????//....
    ???}
    }
    public?final?MetadataReaderFactory?getMetadataReaderFactory()?{
    ???if?(this.metadataReaderFactory?==?null)?{
    ??????this.metadataReaderFactory?=?new?CachingMetadataReaderFactory();
    ???}
    ???return?this.metadataReaderFactory;
    }

    1. 確定metadataReader

    CachingMetadataReaderFactory繼承自 SimpleMetadataReaderFactory,就是對SimpleMetadataReaderFactory加了一層緩存。

    其內部的SimpleMetadataReaderFactory#getMetadataReader 為:

    public?class?SimpleMetadataReaderFactory?implements?MetadataReaderFactory?{
    ????@Override
    public?MetadataReader?getMetadataReader(Resource?resource)?throws?IOException?{
    ???return?new?SimpleMetadataReader(resource,?this.resourceLoader.getClassLoader());
    }
    ????}

    這里可以看出

    MetadataReader metadataReader =new SimpleMetadataReader(...);

    2.查看match方法找重點方法

    AnnotationTypeFilter#matchself方法如下:

    @Override
    protected?boolean?matchSelf(MetadataReader?metadataReader)?{
    ???AnnotationMetadata?metadata?=?metadataReader.getAnnotationMetadata();
    ???return?metadata.hasAnnotation(this.annotationType.getName())?||
    ?????????(this.considerMetaAnnotations?&&?metadata.hasMetaAnnotation(this.annotationType.getName()));
    }

    是metadata.hasMetaAnnotation法,從名稱看是處理元注解,我們重點關注

    逐步分析

    找metadata.hasMetaAnnotation

    metadata=metadataReader.getAnnotationMetadata();

    metadataReader =new SimpleMetadataReader(...)

    metadata= new SimpleMetadataReader#getAnnotationMetadata()

    //SimpleMetadataReader?的構造方法
    SimpleMetadataReader(Resource?resource,?@Nullable?ClassLoader?classLoader)?throws?IOException?{
    ???InputStream?is?=?new?BufferedInputStream(resource.getInputStream());
    ???ClassReader?classReader;
    ???try?{
    ??????classReader?=?new?ClassReader(is);
    ???}
    ???catch?(IllegalArgumentException?ex)?{
    ??????throw?new?NestedIOException("ASM?ClassReader?failed?to?parse?class?file?-?"?+
    ????????????"probably?due?to?a?new?Java?class?file?version?that?isn't?supported?yet:?"?+?resource,?ex);
    ???}
    ???finally?{
    ??????is.close();
    ???}

    ???AnnotationMetadataReadingVisitor?visitor?=
    ????????????new?AnnotationMetadataReadingVisitor(classLoader);
    ???classReader.accept(visitor,?ClassReader.SKIP_DEBUG);

    ???this.annotationMetadata?=?visitor;
    ???//?(since?AnnotationMetadataReadingVisitor?extends?ClassMetadataReadingVisitor)
    ???this.classMetadata?=?visitor;
    ???this.resource?=?resource;
    }

    metadata=new SimpleMetadataReader(...)**.**getAnnotationMetadata()= new AnnotationMetadataReadingVisitor(。。)

    也就是說

    metadata.hasMetaAnnotation=AnnotationMetadataReadingVisitor#hasMetaAnnotation

    其方法如下:

    public?class?AnnotationMetadataReadingVisitor{
    ????//?省略部分代碼
    @Override
    public?boolean?hasMetaAnnotation(String?metaAnnotationType)?{
    ???Collection>?allMetaTypes?=?this.metaAnnotationMap.values();for?(Set?metaTypes?:?allMetaTypes)?{if?(metaTypes.contains(metaAnnotationType))?{return?true;
    ??????}
    ???}return?false;
    }
    }

    邏輯很簡單,就是判斷該注解的元注解在,在不在metaAnnotationMap中,如果在就返回true。

    這里面核心就是metaAnnotationMap,搜索AnnotationMetadataReadingVisitor類,沒有發現賦值的地方??!。

    查找metaAnnotationMap賦值

    回到SimpleMetadataReader 的方法,

    //這個accept方法,很可疑,在賦值之前執行
    SimpleMetadataReader(Resource?resource,?@Nullable?ClassLoader?classLoader)?throws?IOException?{
    //省略其他代碼
    AnnotationMetadataReadingVisitor?visitor?=?new?AnnotationMetadataReadingVisitor(classLoader);
    classReader.accept(visitor,?ClassReader.SKIP_DEBUG);
    ?this.annotationMetadata?=?visitor;
    ?}

    發現一個可疑的語句:classReader.accept。

    查看accept方法

    public?class?ClassReader?{
    ????????//省略其他代碼
    public?void?accept(..省略代碼){
    ????//省略其他代碼
    ????readElementValues(
    ????classVisitor.visitAnnotation(annotationDescriptor,?/*?visible?=?*/?true),
    ????currentAnnotationOffset,
    ?????true,
    ????charBuffer);
    }
    }

    查看readElementValues方法

    public?class?ClassReader{
    ????//省略其他代碼
    private?int?readElementValues(final?AnnotationVisitor?annotationVisitor,final?int?annotationOffset,final?boolean?named,final?char[]?charBuffer)?{
    ??int?currentOffset?=?annotationOffset;
    ??//?Read?the?num_element_value_pairs?field?(or?num_values?field?for?an?array_value).
    ??int?numElementValuePairs?=?readUnsignedShort(currentOffset);
    ??currentOffset?+=?2;
    ??if?(named)?{
    ????//?Parse?the?element_value_pairs?array.
    ????while?(numElementValuePairs--?>?0)?{
    ??????String?elementName?=?readUTF8(currentOffset,?charBuffer);
    ??????currentOffset?=
    ??????????readElementValue(annotationVisitor,?currentOffset?+?2,?elementName,?charBuffer);
    ????}
    ??}?else?{
    ????//?Parse?the?array_value?array.
    ????while?(numElementValuePairs--?>?0)?{
    ??????currentOffset?=
    ??????????readElementValue(annotationVisitor,?currentOffset,?/*?named?=?*/?null,?charBuffer);
    ????}
    ??}
    ??if?(annotationVisitor?!=?null)?{
    ????annotationVisitor.visitEnd();
    ??}
    ??return?currentOffset;
    }
    }

    這里面的核心就是 annotationVisitor.visitEnd();

    確定annotationVisitor

    這里的annotationVisitor=AnnotationMetadataReadingVisitor#visitAnnotation

    源碼如下,注意這里傳遞了metaAnnotationMap!!

    public?class?AnnotationMetadataReadingVisitor{
    @Override
    public?AnnotationVisitor?visitAnnotation(String?desc,?boolean?visible)?{
    ???String?className?=?Type.getType(desc).getClassName();
    ???this.annotationSet.add(className);
    ???return?new?AnnotationAttributesReadingVisitor(
    ?????????className,?this.attributesMap,
    ??????????????this.metaAnnotationMap,?this.classLoader);
    }
    }

    annotationVisitor=AnnotationAttributesReadingVisitor

    查閱annotationVisitor.visitEnd()

    annotationVisitor=AnnotationAttributesReadingVisitor#visitEnd()

    public?class?AnnotationAttributesReadingVisitor{
    @Override
    public?void?visitEnd()?{
    ???super.visitEnd();

    ???Class?extends?Annotation>?annotationClass?=?this.attributes.annotationType();
    ???if?(annotationClass?!=?null)?{
    ??????List?attributeList?=?this.attributesMap.get(this.annotationType);if?(attributeList?==?null)?{this.attributesMap.add(this.annotationType,?this.attributes);
    ??????}else?{
    ?????????attributeList.add(0,?this.attributes);
    ??????}if?(!AnnotationUtils.isInJavaLangAnnotationPackage(annotationClass.getName()))?{try?{
    ????????????Annotation[]?metaAnnotations?=?annotationClass.getAnnotations();if?(!ObjectUtils.isEmpty(metaAnnotations))?{
    ???????????????Set?visited?=?new?LinkedHashSet<>();for?(Annotation?metaAnnotation?:?metaAnnotations)?{
    ??????????????????recursivelyCollectMetaAnnotations(visited,?metaAnnotation);
    ???????????????}if?(!visited.isEmpty())?{
    ??????????????????Set?metaAnnotationTypeNames?=?new?LinkedHashSet<>(visited.size());for?(Annotation?ann?:?visited)?{
    ?????????????????????metaAnnotationTypeNames.add(ann.annotationType().getName());
    ??????????????????}this.metaAnnotationMap.put(annotationClass.getName(),?metaAnnotationTypeNames);
    ???????????????}
    ????????????}
    ?????????}catch?(Throwable?ex)?{if?(logger.isDebugEnabled())?{
    ???????????????logger.debug("Failed?to?introspect?meta-annotations?on?"?+?annotationClass?+?":?"?+?ex);
    ????????????}
    ?????????}
    ??????}
    ???}
    }
    }

    內部方法recursivelyCollectMetaAnnotations 遞歸的讀取注解,與注解的元注解(讀@Service,再讀元注解@Component),并設置到metaAnnotationMap,也就是AnnotationMetadataReadingVisitor 中的metaAnnotationMap中。

    總結

    大致如下:

    ClassPathScanningCandidateComponentProvider#findCandidateComponents

    1、將package轉化為ClassLoader類資源搜索路徑packageSearchPath

    2、加載搜素路徑下的資源。

    3、isCandidateComponent 判斷是否是備選組件。

    內部調用的TypeFilter的match方法:

    AnnotationTypeFilter#matchself中metadata.hasMetaAnnotation處理元注解

    metadata.hasMetaAnnotation=AnnotationMetadataReadingVisitor#hasMetaAnnotation

    就是判斷當前注解的元注解在不在metaAnnotationMap中。

    AnnotationAttributesReadingVisitor#visitEnd()內部方法recursivelyCollectMetaAnnotations 遞歸的讀取注解,與注解的元注解(讀@Service,再讀元注解@Component),并設置到metaAnnotationMap

    4、添加到返回結果的list

    END

    如果讀完覺得有收獲的話,歡迎點【好看】,關注【匠心零度】,查閱更多精彩歷史!!!

    讓我“好看”?

    總結

    以上是生活随笔為你收集整理的@bean注解和@component注解的区别_通过源码查看 @Component,@Service 等注解是如何被解析的...的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。