spring源码分析7----注册@Bean修饰的bean

作者:[email protected]转载请注明作者

前面的文章分析了bean的实例化,bean字段/成员变量的填充。这一篇来看一下@Bean注解。最早分析的是读xml中的定义,现在来看一下代码中的@Bean又是怎么生效的。文章的篇幅越来越大,因为代码贴上去占了太多空间,但是只摘取一段代码,这样又对读者不友好,读文章的时候又要不停返回去看代码对照。篇幅大就大吧,我尽量不贴图片,这样的话,文字再多,占的体积也是有限的。这一篇文章又会很长。

从AnnotationConfigApplicationContext讲起,基于xml配置时,一般使用ClassPathXmlApplication进行spring应用上下文加载。基于java配置时,就使用AnnotationConfigApplicationContext进行spring应用上下文加载。它会注册@Bean注释的方法所返回的bean。这里有一个要注意的地方,就是要使用这两个构造方法,才会去注册bean。

/**
 * Create a new AnnotationConfigApplicationContext, deriving bean definitions
 * from the given component classes and automatically refreshing the context.
 * @param componentClasses one or more component classes — for example,
 * {@link Configuration @Configuration} classes
 */
public AnnotationConfigApplicationContext(Class... componentClasses) {
   this();
   register(componentClasses); 
   refresh(); //熟悉吧
}

/**
 * Create a new AnnotationConfigApplicationContext, scanning for components
 * in the given packages, registering bean definitions for those components,
 * and automatically refreshing the context.
 * @param basePackages the packages to scan for component classes
 */
public AnnotationConfigApplicationContext(String... basePackages) {
   this();
   scan(basePackages);
   refresh(); //很眼熟
}

refresh这里就不讲了,这个类也只是为了提供一个入口,下面来看scan方法。

/**
 * Perform a scan within the specified base packages.
 * 

Note that {@link #refresh()} must be called in order for the context * to fully process the new classes. * @param basePackages the packages to scan for component classes * @see #register(Class...) * @see #refresh() */ @Override public void scan(String... basePackages) { Assert.notEmpty(basePackages, "At least one base package must be specified"); this.scanner.scan(basePackages); }

再看一下scanner,是在无参构造方法里赋值的。

/**
 * Create a new AnnotationConfigApplicationContext that needs to be populated
 * through {@link #register} calls and then manually {@linkplain #refresh refreshed}.
 */
public AnnotationConfigApplicationContext() {
   this.reader = new AnnotatedBeanDefinitionReader(this);
   this.scanner = new ClassPathBeanDefinitionScanner(this);
}

/**
 * Create a new AnnotationConfigApplicationContext with the given DefaultListableBeanFactory.
 * @param beanFactory the DefaultListableBeanFactory instance to use for this context
 */
public AnnotationConfigApplicationContext(DefaultListableBeanFactory beanFactory) {
   super(beanFactory);
   this.reader = new AnnotatedBeanDefinitionReader(this);
   this.scanner = new ClassPathBeanDefinitionScanner(this);
}

好,下面去ClassPathBeanDefinitionScanner里看看scan方法。注意一下scan方法参数传的是package路径,包路径。

/**
 * Perform a scan within the specified base packages.
 * @param basePackages the packages to check for annotated classes
 * @return number of beans registered
 */
public int scan(String... basePackages) {
   int beanCountAtScanStart = this.registry.getBeanDefinitionCount();

   doScan(basePackages); //扫描开始

   // Register annotation config processors, if necessary.
   if (this.includeAnnotationConfig) {
      AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);
   }

   return (this.registry.getBeanDefinitionCount() - beanCountAtScanStart);
}

去doScan里看看

/**
 * Perform a scan within the specified base packages,
 * returning the registered bean definitions.
 * 

This method does not register an annotation config processor * but rather leaves this up to the caller. * @param basePackages the packages to check for annotated classes * @return set of beans registered if any for tooling registration purposes (never {@code null}) */ protected Set doScan(String... basePackages) { //这里传参是a,b,c,d,e,f,g这种形式 Assert.notEmpty(basePackages, "At least one base package must be specified"); Set beanDefinitions = new LinkedHashSet<>(); for (String basePackage : basePackages) { //遍历路径 Set candidates = findCandidateComponents(basePackage); //取bean 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)) { //检查当前bean和已注册的有没有冲突 BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName); definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry); beanDefinitions.add(definitionHolder); registerBeanDefinition(definitionHolder, this.registry); //注册bean } } } return beanDefinitions; }

从代码看,就是遍历package,然后取出里面的bean。再对bean进行遍历,判定没冲突就注册,一共两个for循环,代码不复杂,要继续关注的是怎么从package取bean。再提一句,这一篇分析所有的scan相关的代码是在refresh之前的,也就是完全不涉及bean的实例化,属性初始化。

/**
 * Scan the class path for candidate components.
 * @param basePackage the package to check for annotated classes
 * @return a corresponding Set of autodetected bean definitions
 */
public Set findCandidateComponents(String basePackage) {
   if (this.componentsIndex != null && indexSupportsIncludeFilters()) { //不进这里componentsIndex为null
      return addCandidateComponentsFromIndex(this.componentsIndex, basePackage);
   }
   else {
      return scanCandidateComponents(basePackage); //进这里
   }
}

返回的是BeanDefinition的集合。根据前面的代码,结合ClassPathScanningCandidateComponentProvider的构造方法,可以确定this.componentsIndex为空。

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); //获取resource
      boolean traceEnabled = logger.isTraceEnabled();
      boolean debugEnabled = logger.isDebugEnabled();
      for (Resource resource : resources) { //遍历resource
         if (traceEnabled) {
            logger.trace("Scanning " + resource);
         }
         if (resource.isReadable()) { //可读取
            try {
               MetadataReader metadataReader = getMetadataReaderFactory().getMetadataReader(resource); //从resource里取bean信息
               if (isCandidateComponent(metadataReader)) {
                  ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader);
                  sbd.setResource(resource);
                  sbd.setSource(resource);
                  if (isCandidateComponent(sbd)) {
                     if (debugEnabled) {
                        logger.debug("Identified candidate component class: " + resource);
                     }
                     candidates.add(sbd);
                  }
                  else {
                     if (debugEnabled) {
                        logger.debug("Ignored because not a concrete top-level class: " + resource);
                     }
                  }
               }
               else {
                  if (traceEnabled) {
                     logger.trace("Ignored because not matching any filter: " + resource);
                  }
               }
            }
            catch (Throwable ex) {
               throw new BeanDefinitionStoreException(
                     "Failed to read candidate component class: " + resource, ex);
            }
         }
         else {
            if (traceEnabled) {
               logger.trace("Ignored because not readable: " + resource);
            }
         }
      }
   }
   catch (IOException ex) {
      throw new BeanDefinitionStoreException("I/O failure during classpath scanning", ex);
   }
   return candidates;
}

看看ScannerGenericBeanDefinition

/**
 * Create a new ScannedGenericBeanDefinition for the class that the
 * given MetadataReader describes.
 * @param metadataReader the MetadataReader for the scanned target class
 */
public ScannedGenericBeanDefinition(MetadataReader metadataReader) {
   Assert.notNull(metadataReader, "MetadataReader must not be null");
   this.metadata = metadataReader.getAnnotationMetadata();
   setBeanClassName(this.metadata.getClassName());
}

这个类得到的信息都是从metadataReader里获取的,取了类名,还有元数据。还是去看看metadataReader做了什么。metadataReader来源于CachingMetadataReaderFactory。

/**
 * Return the MetadataReaderFactory used by this component provider.
 */
public final MetadataReaderFactory getMetadataReaderFactory() {
   if (this.metadataReaderFactory == null) {
      this.metadataReaderFactory = new CachingMetadataReaderFactory();
   }
   return this.metadataReaderFactory;
}

CachingMetadataReaderFactory是使用无参构造方法创建的。去看看构造方法。

/**
 * Create a new CachingMetadataReaderFactory for the default class loader,
 * using a local resource cache.
 */
public CachingMetadataReaderFactory() {
   super();
   setCacheLimit(DEFAULT_CACHE_LIMIT);
}

可以看到这个构造方法没有做其它的事情,只有一个方法调用。分析代码的时候一定要随时注意参数值,参数类型。这个参数是

public static final int DEFAULT_CACHE_LIMIT = 256;
/**
 * Specify the maximum number of entries for the MetadataReader cache.
 * 

Default is 256 for a local cache, whereas a shared cache is * typically unbounded. This method enforces a local resource cache, * even if the {@link ResourceLoader} supports a shared resource cache. */ public void setCacheLimit(int cacheLimit) { if (cacheLimit <= 0) { this.metadataReaderCache = null; } else if (this.metadataReaderCache instanceof LocalResourceCache) { ((LocalResourceCache) this.metadataReaderCache).setCacheLimit(cacheLimit); } else { //走到这里了 this.metadataReaderCache = new LocalResourceCache(cacheLimit); } }

而LocalResourceCache的代码是

@SuppressWarnings("serial")
private static class LocalResourceCache extends LinkedHashMap {

   private volatile int cacheLimit;

   public LocalResourceCache(int cacheLimit) {
      super(cacheLimit, 0.75f, true);
      this.cacheLimit = cacheLimit;
   }

   public void setCacheLimit(int cacheLimit) {
      this.cacheLimit = cacheLimit;
   }

   public int getCacheLimit() {
      return this.cacheLimit;
   }

   @Override
   protected boolean removeEldestEntry(Map.Entry eldest) {
      return size() > this.cacheLimit;
   }
}

上面看的代码实际上都是为了好分析下面这个方法

@Override
public MetadataReader getMetadataReader(Resource resource) throws IOException {
   if (this.metadataReaderCache instanceof ConcurrentMap) { //不进这里
      // No synchronization necessary...
      MetadataReader metadataReader = this.metadataReaderCache.get(resource);
      if (metadataReader == null) {
         metadataReader = super.getMetadataReader(resource);
         this.metadataReaderCache.put(resource, metadataReader);
      }
      return metadataReader;
   }
   else if (this.metadataReaderCache != null) { //进了这里
      synchronized (this.metadataReaderCache) {
         MetadataReader metadataReader = this.metadataReaderCache.get(resource);
         if (metadataReader == null) { //新的resource
            metadataReader = super.getMetadataReader(resource); //进了这里
            this.metadataReaderCache.put(resource, metadataReader); //缓存起来
         }
         return metadataReader;
      }
   }
   else {
      return super.getMetadataReader(resource);
   }
}

看看super.getMetadataReader

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

继续看SimpleMetadataReader这个类

SimpleMetadataReader(Resource resource, @Nullable ClassLoader classLoader) throws IOException {
   SimpleAnnotationMetadataReadingVisitor visitor = new SimpleAnnotationMetadataReadingVisitor(classLoader);
   getClassReader(resource).accept(visitor, PARSING_OPTIONS);
   this.resource = resource;
   this.annotationMetadata = visitor.getMetadata(); //metaData来自于visitor
}

任务是在SimpleAnnotationMetadataReadingVisitor中完成的。但是class的二进制格式读取是ClassReader完成的,这个类读class的二进制,将二进制分解。分解过程中,使用visitor去转换。

private static ClassReader getClassReader(Resource resource) throws IOException {
   try (InputStream is = new BufferedInputStream(resource.getInputStream())) {
      try {
         return new ClassReader(is); //这个是asm下的ClassReader,解析class二进制
      }
      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);
      }
   }
}

然后看ClassReader.accept,这个方法非常长,感兴趣的可以去看一下java虚拟机里对class文件格式的描述,也有专门的书《深入java虚拟机》,代码我就不一一解释了,主要标注有visitor的地方。


public void accept(
    final ClassVisitor classVisitor, //visitor传入
    final Attribute[] attributePrototypes,
    final int parsingOptions) {
  Context context = new Context();
  context.attributePrototypes = attributePrototypes;
  context.parsingOptions = parsingOptions;
  context.charBuffer = new char[maxStringLength];

  // Read the access_flags, this_class, super_class, interface_count and interfaces fields.
  char[] charBuffer = context.charBuffer;
  int currentOffset = header; //跳过文件头
  int accessFlags = readUnsignedShort(currentOffset);
  String thisClass = readClass(currentOffset + 2, charBuffer); //读自己
  String superClass = readClass(currentOffset + 4, charBuffer); //读父类
  String[] interfaces = new String[readUnsignedShort(currentOffset + 6)];
  currentOffset += 8;
  for (int i = 0; i < interfaces.length; ++i) {
    interfaces[i] = readClass(currentOffset, charBuffer);
    currentOffset += 2; 
  } //读接口

  // Read the class attributes (the variables are ordered as in Section 4.7 of the JVMS).
  // Attribute offsets exclude the attribute_name_index and attribute_length fields.
  // - The offset of the InnerClasses attribute, or 0.
  int innerClassesOffset = 0;
  // - The offset of the EnclosingMethod attribute, or 0.
  int enclosingMethodOffset = 0;
  // - The string corresponding to the Signature attribute, or null.
  String signature = null;
  // - The string corresponding to the SourceFile attribute, or null.
  String sourceFile = null;
  // - The string corresponding to the SourceDebugExtension attribute, or null.
  String sourceDebugExtension = null;
  // - The offset of the RuntimeVisibleAnnotations attribute, or 0.
  int runtimeVisibleAnnotationsOffset = 0;
  // - The offset of the RuntimeInvisibleAnnotations attribute, or 0.
  int runtimeInvisibleAnnotationsOffset = 0;
  // - The offset of the RuntimeVisibleTypeAnnotations attribute, or 0.
  int runtimeVisibleTypeAnnotationsOffset = 0;
  // - The offset of the RuntimeInvisibleTypeAnnotations attribute, or 0.
  int runtimeInvisibleTypeAnnotationsOffset = 0;
  // - The offset of the Module attribute, or 0.
  int moduleOffset = 0;
  // - The offset of the ModulePackages attribute, or 0.
  int modulePackagesOffset = 0;
  // - The string corresponding to the ModuleMainClass attribute, or null.
  String moduleMainClass = null;
  // - The string corresponding to the NestHost attribute, or null.
  String nestHostClass = null;
  // - The offset of the NestMembers attribute, or 0.
  int nestMembersOffset = 0;
  // - The non standard attributes (linked with their {@link Attribute#nextAttribute} field).
  //   This list in the reverse order or their order in the ClassFile structure.
  Attribute attributes = null;

  int currentAttributeOffset = getFirstAttributeOffset();
  for (int i = readUnsignedShort(currentAttributeOffset - 2); i > 0; --i) {
    // Read the attribute_info's attribute_name and attribute_length fields.
    String attributeName = readUTF8(currentAttributeOffset, charBuffer);
    int attributeLength = readInt(currentAttributeOffset + 2);
    currentAttributeOffset += 6;
    // The tests are sorted in decreasing frequency order (based on frequencies observed on
    // typical classes).
    if (Constants.SOURCE_FILE.equals(attributeName)) {
      sourceFile = readUTF8(currentAttributeOffset, charBuffer);
    } else if (Constants.INNER_CLASSES.equals(attributeName)) {
      innerClassesOffset = currentAttributeOffset;
    } else if (Constants.ENCLOSING_METHOD.equals(attributeName)) {
      enclosingMethodOffset = currentAttributeOffset;
    } else if (Constants.NEST_HOST.equals(attributeName)) {
      nestHostClass = readClass(currentAttributeOffset, charBuffer);
    } else if (Constants.NEST_MEMBERS.equals(attributeName)) {
      nestMembersOffset = currentAttributeOffset;
    } else if (Constants.SIGNATURE.equals(attributeName)) {
      signature = readUTF8(currentAttributeOffset, charBuffer);
    } else if (Constants.RUNTIME_VISIBLE_ANNOTATIONS.equals(attributeName)) {
      runtimeVisibleAnnotationsOffset = currentAttributeOffset;
    } else if (Constants.RUNTIME_VISIBLE_TYPE_ANNOTATIONS.equals(attributeName)) {
      runtimeVisibleTypeAnnotationsOffset = currentAttributeOffset;
    } else if (Constants.DEPRECATED.equals(attributeName)) {
      accessFlags |= Opcodes.ACC_DEPRECATED;
    } else if (Constants.SYNTHETIC.equals(attributeName)) {
      accessFlags |= Opcodes.ACC_SYNTHETIC;
    } else if (Constants.SOURCE_DEBUG_EXTENSION.equals(attributeName)) {
      sourceDebugExtension =
          readUtf(currentAttributeOffset, attributeLength, new char[attributeLength]);
    } else if (Constants.RUNTIME_INVISIBLE_ANNOTATIONS.equals(attributeName)) {
      runtimeInvisibleAnnotationsOffset = currentAttributeOffset;
    } else if (Constants.RUNTIME_INVISIBLE_TYPE_ANNOTATIONS.equals(attributeName)) {
      runtimeInvisibleTypeAnnotationsOffset = currentAttributeOffset;
    } else if (Constants.MODULE.equals(attributeName)) {
      moduleOffset = currentAttributeOffset;
    } else if (Constants.MODULE_MAIN_CLASS.equals(attributeName)) {
      moduleMainClass = readClass(currentAttributeOffset, charBuffer);
    } else if (Constants.MODULE_PACKAGES.equals(attributeName)) {
      modulePackagesOffset = currentAttributeOffset;
    } else if (!Constants.BOOTSTRAP_METHODS.equals(attributeName)) {
      // The BootstrapMethods attribute is read in the constructor.
      Attribute attribute =
          readAttribute(
              attributePrototypes,
              attributeName,
              currentAttributeOffset,
              attributeLength,
              charBuffer,
              -1,
              null);
      attribute.nextAttribute = attributes;
      attributes = attribute;
    }
    currentAttributeOffset += attributeLength;
  }

  // Visit the class declaration. The minor_version and major_version fields start 6 bytes before
  // the first constant pool entry, which itself starts at cpInfoOffsets[1] - 1 (by definition).
  classVisitor.visit(
      readInt(cpInfoOffsets[1] - 7), accessFlags, thisClass, signature, superClass, interfaces);

  // Visit the SourceFile and SourceDebugExtenstion attributes.
  if ((parsingOptions & SKIP_DEBUG) == 0
      && (sourceFile != null || sourceDebugExtension != null)) {
    classVisitor.visitSource(sourceFile, sourceDebugExtension);
  }

  // Visit the Module, ModulePackages and ModuleMainClass attributes.
  if (moduleOffset != 0) {
    readModuleAttributes(
        classVisitor, context, moduleOffset, modulePackagesOffset, moduleMainClass);
  }

  // Visit the NestHost attribute.
  if (nestHostClass != null) {
    classVisitor.visitNestHost(nestHostClass);
  }

  // Visit the EnclosingMethod attribute.
  if (enclosingMethodOffset != 0) {
    String className = readClass(enclosingMethodOffset, charBuffer);
    int methodIndex = readUnsignedShort(enclosingMethodOffset + 2);
    String name = methodIndex == 0 ? null : readUTF8(cpInfoOffsets[methodIndex], charBuffer);
    String type = methodIndex == 0 ? null : readUTF8(cpInfoOffsets[methodIndex] + 2, charBuffer);
    classVisitor.visitOuterClass(className, name, type);
  }

  // Visit the RuntimeVisibleAnnotations attribute.
  if (runtimeVisibleAnnotationsOffset != 0) {
    int numAnnotations = readUnsignedShort(runtimeVisibleAnnotationsOffset);
    int currentAnnotationOffset = runtimeVisibleAnnotationsOffset + 2;
    while (numAnnotations-- > 0) {
      // Parse the type_index field.
      String annotationDescriptor = readUTF8(currentAnnotationOffset, charBuffer);
      currentAnnotationOffset += 2;
      // Parse num_element_value_pairs and element_value_pairs and visit these values.
      currentAnnotationOffset =
          readElementValues(
              classVisitor.visitAnnotation(annotationDescriptor, /* visible = */ true),
              currentAnnotationOffset,
              /* named = */ true,
              charBuffer); //读取annotation,注解
    }
  }

  // Visit the RuntimeInvisibleAnnotations attribute.
  if (runtimeInvisibleAnnotationsOffset != 0) {
    int numAnnotations = readUnsignedShort(runtimeInvisibleAnnotationsOffset);
    int currentAnnotationOffset = runtimeInvisibleAnnotationsOffset + 2;
    while (numAnnotations-- > 0) {
      // Parse the type_index field.
      String annotationDescriptor = readUTF8(currentAnnotationOffset, charBuffer);
      currentAnnotationOffset += 2;
      // Parse num_element_value_pairs and element_value_pairs and visit these values.
      currentAnnotationOffset =
          readElementValues(
              classVisitor.visitAnnotation(annotationDescriptor, /* visible = */ false),
              currentAnnotationOffset,
              /* named = */ true,
              charBuffer);
    }
  }

  // Visit the RuntimeVisibleTypeAnnotations attribute.
  if (runtimeVisibleTypeAnnotationsOffset != 0) {
    int numAnnotations = readUnsignedShort(runtimeVisibleTypeAnnotationsOffset);
    int currentAnnotationOffset = runtimeVisibleTypeAnnotationsOffset + 2;
    while (numAnnotations-- > 0) {
      // Parse the target_type, target_info and target_path fields.
      currentAnnotationOffset = readTypeAnnotationTarget(context, currentAnnotationOffset);
      // Parse the type_index field.
      String annotationDescriptor = readUTF8(currentAnnotationOffset, charBuffer);
      currentAnnotationOffset += 2;
      // Parse num_element_value_pairs and element_value_pairs and visit these values.
      currentAnnotationOffset =
          readElementValues(
              classVisitor.visitTypeAnnotation(
                  context.currentTypeAnnotationTarget,
                  context.currentTypeAnnotationTargetPath,
                  annotationDescriptor,
                  /* visible = */ true),
              currentAnnotationOffset,
              /* named = */ true,
              charBuffer);
    }
  }

  // Visit the RuntimeInvisibleTypeAnnotations attribute.
  if (runtimeInvisibleTypeAnnotationsOffset != 0) {
    int numAnnotations = readUnsignedShort(runtimeInvisibleTypeAnnotationsOffset);
    int currentAnnotationOffset = runtimeInvisibleTypeAnnotationsOffset + 2;
    while (numAnnotations-- > 0) {
      // Parse the target_type, target_info and target_path fields.
      currentAnnotationOffset = readTypeAnnotationTarget(context, currentAnnotationOffset);
      // Parse the type_index field.
      String annotationDescriptor = readUTF8(currentAnnotationOffset, charBuffer);
      currentAnnotationOffset += 2;
      // Parse num_element_value_pairs and element_value_pairs and visit these values.
      currentAnnotationOffset =
          readElementValues(
              classVisitor.visitTypeAnnotation(
                  context.currentTypeAnnotationTarget,
                  context.currentTypeAnnotationTargetPath,
                  annotationDescriptor,
                  /* visible = */ false),
              currentAnnotationOffset,
              /* named = */ true,
              charBuffer);
    }
  }

  // Visit the non standard attributes.
  while (attributes != null) {
    // Copy and reset the nextAttribute field so that it can also be used in ClassWriter.
    Attribute nextAttribute = attributes.nextAttribute;
    attributes.nextAttribute = null;
    classVisitor.visitAttribute(attributes);
    attributes = nextAttribute;
  }

  // Visit the NestedMembers attribute.
  if (nestMembersOffset != 0) {
    int numberOfNestMembers = readUnsignedShort(nestMembersOffset);
    int currentNestMemberOffset = nestMembersOffset + 2;
    while (numberOfNestMembers-- > 0) {
      classVisitor.visitNestMember(readClass(currentNestMemberOffset, charBuffer));
      currentNestMemberOffset += 2;
    }
  }

  // Visit the InnerClasses attribute.
  if (innerClassesOffset != 0) {
    int numberOfClasses = readUnsignedShort(innerClassesOffset);
    int currentClassesOffset = innerClassesOffset + 2;
    while (numberOfClasses-- > 0) {
      classVisitor.visitInnerClass(
          readClass(currentClassesOffset, charBuffer),
          readClass(currentClassesOffset + 2, charBuffer),
          readUTF8(currentClassesOffset + 4, charBuffer),
          readUnsignedShort(currentClassesOffset + 6));
      currentClassesOffset += 8;
    }
  }

  // Visit the fields and methods.
  int fieldsCount = readUnsignedShort(currentOffset);
  currentOffset += 2;
  while (fieldsCount-- > 0) {
    currentOffset = readField(classVisitor, context, currentOffset);
  }
  int methodsCount = readUnsignedShort(currentOffset);
  currentOffset += 2;
  while (methodsCount-- > 0) {
    currentOffset = readMethod(classVisitor, context, currentOffset);
  }

  // Visit the end of the class.
  classVisitor.visitEnd();
}

到了这里,可以知道,所有的metadata,其实都是从class二进制流里得来的。看一下metadata到底都有什么内容。

@Override
public void visitEnd() {
   String[] memberClassNames = StringUtils.toStringArray(this.memberClassNames);
   MethodMetadata[] annotatedMethods = this.annotatedMethods.toArray(new MethodMetadata[0]);
   MergedAnnotations annotations = MergedAnnotations.of(this.annotations);
   this.metadata = new SimpleAnnotationMetadata(this.className, this.access,
         this.enclosingClassName, this.superClassName, this.independentInnerClass,
         this.interfaceNames, memberClassNames, annotatedMethods, annotations);
} //类名,access privilege,inner class,interfaces,annotions,annotatedMethos(注意@Bean修饰的方法就是一种)

public SimpleAnnotationMetadata getMetadata() {
   Assert.state(this.metadata != null, "AnnotationMetadata not initialized");
   return this.metadata;
}

到此,一个bean的class读取,注册就分析完了。还遗留了一个问题,如果是扫描一个包下面的所有类,那么spring是怎么过滤掉接口,抽象类,内部类这些它不需要的东西。

/**
 * Determine whether the given bean definition qualifies as candidate.
 * 

The default implementation checks whether the class is not an interface * and not dependent on an enclosing class. *

Can be overridden in subclasses. * @param beanDefinition the bean definition to check * @return whether the bean definition qualifies as a candidate component */ protected boolean isCandidateComponent(AnnotatedBeanDefinition beanDefinition) { AnnotationMetadata metadata = beanDefinition.getMetadata(); return (metadata.isIndependent() && (metadata.isConcrete() || (metadata.isAbstract() && metadata.hasAnnotatedMethods(Lookup.class.getName())))); }

简单分析一下,第一种:不是接口,不是抽象类,还必须是顶层类(比如,不是内部嵌套类)。第二种:是抽象类,但是有注解修饰的方法。到这里,整个流程分析完了,spring对于bean的加载,是扫描式的,先全部扫进来。扫描进来以后,再做过滤。过滤完了以后,再注册bean。

写在最后:接单,有后台活java/cpp/lua/go联系[email protected]。不上班了也要有点收入才行。

你可能感兴趣的:(spring源码分析7----注册@Bean修饰的bean)