超全面!Java核心知识总结(点击查看)


超全面!Java核心知识总结(点击查看)

  • 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是任何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<BeanDefinition> 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<Set<String>> allMetaTypes = this.metaAnnotationMap.values();
       for (Set<String> metaTypes : allMetaTypes) {
          if (metaTypes.contains(metaAnnotationType)) {
             return true;
          }
       }
       return false;
    }
    }

    逻辑很简单,就是判断该注解的元注解在,在不在metaAnnotationMap中,如果在就返回true。

    这里面核心就是metaAnnotationMap,搜索AnnotationMetadataReadingVisitor类,没有发现赋值的地方??!。

    推荐:Java面试练题宝典

    查找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<AnnotationAttributes> attributeList = this.attributesMap.get(this.annotationType);
          if (attributeList == null) {
             this.attributesMap.add(this.annotationType, this.attributes);
          }
          else {
             attributeList.add(0this.attributes);
          }
          if (!AnnotationUtils.isInJavaLangAnnotationPackage(annotationClass.getName())) {
             try {
                Annotation[] metaAnnotations = annotationClass.getAnnotations();
                if (!ObjectUtils.isEmpty(metaAnnotations)) {
                   Set<Annotation> visited = new LinkedHashSet<>();
                   for (Annotation metaAnnotation : metaAnnotations) {
                      recursivelyCollectMetaAnnotations(visited, metaAnnotation);
                   }
                   if (!visited.isEmpty()) {
                      Set<String> 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方法:

    就是判断当前注解的元注解在不在metaAnnotationMap中。

    AnnotationAttributesReadingVisitor#visitEnd()内部方法recursivelyCollectMetaAnnotations 递归的读取注解,与注解的元注解(读@Service,再读元注解@Component),并设置到metaAnnotationMap

    4.添加到返回结果的list

    如有文章对你有帮助,

    在看”和转发是对我最大的支持!

    整理了大部分常用 技术书籍PDF,持续更新中... 你需要的技术书籍,这里可能都有...


    点击文末“阅读原文”可直达

    整理不易,麻烦各位小伙伴在GitHub中来个一键三连

    本文分享自微信公众号 - Java专栏(finishbug)。
    如有侵权,请联系 [email protected] 删除。
    本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。

    04-15 05:02