javascript
@service注解_Spring 中 @Component、@Service 等注解如何被解析?
前言
@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大體思路如下:
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@Componentpublic?@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?{????@Overridepublic?MetadataReader?getMetadataReader(Resource?resource)?throws?IOException?{???return?new?SimpleMetadataReader(resource,?this.resourceLoader.getClassLoader());}????}這里可以看出
MetadataReader metadataReader =new SimpleMetadataReader(...);
2.查看match方法找重點方法
AnnotationTypeFilter#matchself方法如下:
@Overrideprotected?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{????//?省略部分代碼@Overridepublic?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{@Overridepublic?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{@Overridepublic?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
內部調用的TypeFilter的match方法:
AnnotationTypeFilter#matchself中metadata.hasMetaAnnotation處理元注解
metadata.hasMetaAnnotation=AnnotationMetadataReadingVisitor#hasMetaAnnotation
就是判斷當前注解的元注解在不在metaAnnotationMap中。
AnnotationAttributesReadingVisitor#visitEnd()內部方法recursivelyCollectMetaAnnotations 遞歸的讀取注解,與注解的元注解(讀@Service,再讀元注解@Component),并設置到metaAnnotationMap
總結
以上是生活随笔為你收集整理的@service注解_Spring 中 @Component、@Service 等注解如何被解析?的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: windows键按了没反应_window
- 下一篇: win启动linux iso文件位置,安