(三)Spring框架原理之@Configuration及搭配注解接口源码分析(下)

目录

一、源码分析

1.ConfigurationClassParser解析类

1.1 解析配置类的@Component注解

1.2 processPropertySource解析@PropertySources注解

1.3 ComponentScanAnnotationParser解析@ComponentScan注解

1.4 processImports解析@Import注解

1.5 retrieveBeanMethodMetadata解析获取@Bean注解

2.ConfigurationClassBeanDefinitionReader读取注册配置类

2.1 解析@Bean注解的BeanMethod对象

2.2 解析@ImportSource注入的resource对象


一、源码分析

本篇接着(三)Spring框架原理之@Configuration及搭配注解接口源码分析(上)文章继续分析下半部分。上篇已经说明了读取@Configuration的流程,本篇便分析解析配置类和读取注册配置类的过程。

1.ConfigurationClassParser解析类

这个类便是前面我们分析过的解析@Configuration配置类的地方,其部分关键源码如下:

class ConfigurationClassParser {
    // Spring注册中心
    private final BeanDefinitionRegistry registry;
    // 用来存储配置类
    private final Map<ConfigurationClass, ConfigurationClass> 
            configurationClasses = new LinkedHashMap<>();
    // 用来存储配置类的父类
    private final Map<String, ConfigurationClass> knownSuperclasses =
            new HashMap<>();
    // 解析@Import注解时用来存储执行的@Import栈,用来判断循环引入
    private final ImportStack importStack = new ImportStack();
    public void parse(Set<BeanDefinitionHolder> configCandidates) {
       // 循环遍历解析配置类
       for (BeanDefinitionHolder holder : configCandidates) {
          BeanDefinition bd = holder.getBeanDefinition();
          // 每个都会调用parse方法,这三个parse方法最终都会调用
          // processConfigurationClass方法,因此等下直接看到这个方法即可
          try {
             if (bd instanceof AnnotatedBeanDefinition) {
                parse(((AnnotatedBeanDefinition) bd).getMetadata(), 
                        holder.getBeanName());
             } 
             ...
          } catch (BeanDefinitionStoreException ex) {
             throw ex;
          } catch (Throwable ex) {
             throw new BeanDefinitionStoreException();
          }
       }
       this.deferredImportSelectorHandler.process();
    }
    protected void processConfigurationClass(
            ConfigurationClass configClass) throws IOException {
        // 这个方法是非常重要的,是解析配置类的入口,如果在解析过程中碰到了需要
        // 递归解析的也是调用的这个方法,这个方法也可分为三个部分
        // 一、使用@Conditional判断配置类条件是否满足
        // 这个判断条件用来判断Conditional注解引入的判断条件类,使用时的直观
        // 体验便是使用@ConditionalOnBean和@ConditionalOnClass等注解的使用
        if (this.conditionEvaluator.shouldSkip(configClass.getMetadata(),
                ConfigurationPhase.PARSE_CONFIGURATION)) {
           return;
        }
        // 二、从已有的配置类集合中判断配置类是否解析过或者替换最新的配置类
        ConfigurationClass existingClass = this.configurationClasses
                .get(configClass);
        // 配置类在原来的配置类集合中存在
        if (existingClass != null) {
           if (configClass.isImported()) {
              if (existingClass.isImported()) {
                 existingClass.mergeImportedBy(configClass);
              }
              // 进入到这里说明配置类已经被导入过了,无需再次解析,直接返回
              return;
           }
           else {
              // 如果发现新的且没有解析过,则使用新的配置类替换老的
              this.configurationClasses.remove(configClass);
              this.knownSuperclasses.values()
                      .removeIf(configClass::equals);
           }
        }
        // 三、循环调用doProcessConfigurationClass方法处理配置类
        SourceClass sourceClass = asSourceClass(configClass);
        do {
           // 因为配置类可能存在层级,因此该循环是针对配置类的父类进行的
           // 但是配置类对象是不会变的
           sourceClass = doProcessConfigurationClass(configClass,
                   sourceClass);
        }
        while (sourceClass != null);
        // 处理成功之后将配置类放入配置类集合中
        this.configurationClasses.put(configClass, configClass);
    }
    protected final SourceClass doProcessConfigurationClass(
            ConfigurationClass configClass, SourceClass sourceClass)
            throws IOException {
       // 该方法是解析各个组件的模板方法,可以将其分为八个部分,这八个部分的具体
       // 流程在后面的小节中分析
       // 一、解析配置类中的@Component注解,因为该配置类中被@Component注解的
       // bean可能也是配置类
       if (configClass.getMetadata()
               .isAnnotated(Component.class.getName())) {
          // 这里面会递归处理@Component类中的配置类,再将获取到的配置类递归调用
          // processConfigurationClass方法
          processMemberClasses(configClass, sourceClass);
       }
       // 二、解析@PropertySources注解,该注解的作用便是引入额外的properties
       // 文件解析过后再将文件属性值注入到environment中,如果有相同的则替换新的
       for (AnnotationAttributes propertySource : 
               AnnotationConfigUtils.attributesForRepeatable(
             sourceClass.getMetadata(), PropertySources.class,
             org.springframework.context.annotation.PropertySource.class)){
          if (this.environment instanceof ConfigurableEnvironment) {
             processPropertySource(propertySource);
          }
       }
       // 三、解析@ComponentScan注解
       Set<AnnotationAttributes> componentScans = AnnotationConfigUtils
               .attributesForRepeatable(
             sourceClass.getMetadata(), ComponentScans.class,
                     ComponentScan.class);
       // 如果获取到的@ComponentScan注解对应属性不为空且
       // @Conditional注解判断成功
       if (!componentScans.isEmpty() &&
           !this.conditionEvaluator.shouldSkip(sourceClass.getMetadata(),
                     ConfigurationPhase.REGISTER_BEAN)) {
          // 因为@ComponentScans注解含有多个@ComponentScan,因此这里可能
          // 是个数组,含有多个componentScan注解属性
          for (AnnotationAttributes componentScan : componentScans) {
             // componentScanParser对象类型是ComponentScanAnnotationParser
             // 其具体的parse方法在后面的小姐会分析
             Set<BeanDefinitionHolder> scannedBeanDefinitions =
                   this.componentScanParser.parse(componentScan, 
                           sourceClass.getMetadata().getClassName());
             // 使用解析器获得了对应路径下的所有bean定义候选集合
             for (BeanDefinitionHolder holder : scannedBeanDefinitions) {
                BeanDefinition bdCand = holder.getBeanDefinition()
                        .getOriginatingBeanDefinition();
                if (bdCand == null) {
                   bdCand = holder.getBeanDefinition();
                }
                // 如果是被@Configuration注解的配置类,则再次调用本类中的
                // parse方法进行解析
                if (ConfigurationClassUtils
                        .checkConfigurationClassCandidate(bdCand, 
                            this.metadataReaderFactory)) {
                   parse(bdCand.getBeanClassName(), holder.getBeanName());
                }
             }
          }
       }
       // 四、解析@Import注解,getImports方法在后面的小节也会分析
       processImports(configClass, sourceClass, getImports(sourceClass),
               true);
       // 五、解析@ImportResource注解,该注解的作用便是将一个资源导入到Spring
       AnnotationAttributes importResource =
            AnnotationConfigUtils.attributesFor(sourceClass.getMetadata(),
                     ImportResource.class);
       // 如果获取到@ImportResource注解对应的属性对象不为空
       if (importResource != null) {
          // 获取需要导入的资源位置
          String[] resources = importResource.getStringArray("locations");
          Class<? extends BeanDefinitionReader> readerClass = 
                  importResource.getClass("reader");
          // 循环遍历获取资源对象
          for (String resource : resources) {
             String resolvedResource = this.environment
                     .resolveRequiredPlaceholders(resource);
             // 存放到配置类的importedResources集合中
             configClass.addImportedResource(resolvedResource, 
                     readerClass);
          }
       }
       // 六、解析@Bean注解的方法
       Set<MethodMetadata> beanMethods = 
               retrieveBeanMethodMetadata(sourceClass);
       for (MethodMetadata methodMetadata : beanMethods) {
          // 获取之后依次遍历添加到配置类的beanMethods对象中
          configClass.addBeanMethod(new BeanMethod(methodMetadata, 
                  configClass));
       }
       // 七、处理接口上的默认方法,暂时不知道其具体作用
       processInterfaces(configClass, sourceClass);
       // 八、获取当前类的父类
       if (sourceClass.getMetadata().hasSuperClass()) {
          String superclass = sourceClass.getMetadata()
                  .getSuperClassName();
          // 如果父类不为空,且knownSuperclasses集合中不存在该类
          if (superclass != null && !superclass.startsWith("java") &&
                !this.knownSuperclasses.containsKey(superclass)) {
             // 放入knownSuperclasses对象,并且返回父类
             this.knownSuperclasses.put(superclass, configClass);
             return sourceClass.getSuperClass();
          }
       }
       // 如果没有父类说明这个配置类已经解析完毕,返回null
       return null;
    }
}

1.1 解析配置类的@Component注解

在前面已经说过了是具体调用processMemberClasses方法来完成的,因此我们直接看到其部分关键源码:

class ConfigurationClassParser {
    private void processMemberClasses(ConfigurationClass configClass, 
            SourceClass sourceClass) throws IOException {
       Collection<SourceClass> memberClasses = sourceClass
               .getMemberClasses();
       // 获取配置类所有的@Component对象且集合不为空
       if (!memberClasses.isEmpty()) {
          List<SourceClass> candidates = new ArrayList<>(
                  memberClasses.size());
          for (SourceClass memberClass : memberClasses) {
             // 如果获取到的@Component对象也是配置类则添加到candidates中
             if (ConfigurationClassUtils
                 .isConfigurationCandidate(memberClass.getMetadata()) &&
                 !memberClass.getMetadata().getClassName()
                     .equals(configClass.getMetadata().getClassName())) {
                candidates.add(memberClass);
             }
          }
          // 对候选者集合进行排序
          OrderComparator.sort(candidates);
          for (SourceClass candidate : candidates) {
             // 如果引入的类栈中已经存在则说明有循环引入的问题
             if (this.importStack.contains(configClass)) {
                this.problemReporter.error(
                        new CircularImportProblem(configClass, 
                        this.importStack));
             } else {
                // 将配置类入栈,防止循环引入问题
                this.importStack.push(configClass);
                try {
                   // 如果@Component注解的类刚好是配置类,则需要调用方法解析
                   processConfigurationClass(candidate
                           .asConfigClass(configClass));
                } finally {
                   this.importStack.pop();
                }
             }
          }
       }
    }
}

从其流程可以看出,这个方法的主要作用便是解析被@Component注解的类,因为这个类中也有可能存在被@Configuration注解的配置类。

1.2 processPropertySource解析@PropertySources注解

其部分关键源码如下:

class ConfigurationClassParser {
    private void processPropertySource(AnnotationAttributes propertySource)
            throws IOException {
       // 直接三步走,获取@PropertySources注解的name、encoding和value属性
       String name = propertySource.getString("name");
       if (!StringUtils.hasLength(name)) {
          name = null;
       }
       String encoding = propertySource.getString("encoding");
       if (!StringUtils.hasLength(encoding)) {
          encoding = null;
       }
       String[] locations = propertySource.getStringArray("value");
       boolean ignoreResourceNotFound = 
               propertySource.getBoolean("ignoreResourceNotFound");
       // 获取指定的解析工厂
       Class<? extends PropertySourceFactory> factoryClass = 
               propertySource.getClass("factory");
       // 默认取的是DefaultPropertySourceFactory类型
       PropertySourceFactory factory = 
               (factoryClass == PropertySourceFactory.class ?
               DEFAULT_PROPERTY_SOURCE_FACTORY : 
                       BeanUtils.instantiateClass(factoryClass));
       // 如果指定的位置不为空则依次遍历处理
       for (String location : locations) {
          try {
             String resolvedLocation = this.environment
                     .resolveRequiredPlaceholders(location);
             Resource resource = this.resourceLoader
                     .getResource(resolvedLocation);
             // 添加到environment对象中
             addPropertySource(factory.createPropertySource(name, 
                     new EncodedResource(resource, encoding)));
          }
          // 异常捕捉
          ...
       }
    }
    private void addPropertySource(PropertySource<?> propertySource) {
       // 获取待添加属性的名称
       String name = propertySource.getName();
       // 获取environment对象的属性对象
       MutablePropertySources propertySources = 
               ((ConfigurableEnvironment) this.environment)
                       .getPropertySources();
       // 如果属性对象包含了这个名称,则说明已经存在,需要进行替换操作
       if (this.propertySourceNames.contains(name)) {
          // 获取已经存在的属性对象
          PropertySource<?> existing = propertySources.get(name);
          if (existing != null) {
             // 获取属性对象
             PropertySource<?> newSource = 
                     (propertySource instanceof ResourcePropertySource ?
                     ((ResourcePropertySource) propertySource)
                         .withResourceName() : propertySource);
             // 如果原来已经存在的属性对象是CompositePropertySource类型
             // 则说明可以直接添加到组合属性资源中
             if (existing instanceof CompositePropertySource) {
                ((CompositePropertySource) existing)
                        .addFirstPropertySource(newSource);
             } else {
                if (existing instanceof ResourcePropertySource) {
                   existing = ((ResourcePropertySource) existing)
                           .withResourceName();
                }
                // 如果原来的不是组合属性资源则封装成组合属性资源再添加已存在的
                // 和新增加的,最后替换原本在environment对象中的属性对象
                CompositePropertySource composite = 
                        new CompositePropertySource(name);
                composite.addPropertySource(newSource);
                composite.addPropertySource(existing);
                propertySources.replace(name, composite);
             }
             return;
          }
       }
       // 如果propertySourceNames为空则说明导入的属性对象未存在
       if (this.propertySourceNames.isEmpty()) {
          propertySources.addLast(propertySource);
       } else {
          // 不为空则添加到最后
          String firstProcessed = this.propertySourceNames
                  .get(this.propertySourceNames.size() - 1);
          propertySources.addBefore(firstProcessed, propertySource);
       }
       // 将解析过的属性名称存入propertySourceNames集合
       this.propertySourceNames.add(name);
    }
}

其流程的大致作用便是读取@PropertySources的配置,并且将需要导入的属性文件添加到Spring的Environment对象中。

1.3 ComponentScanAnnotationParser解析@ComponentScan注解

解析@ComponentScan属性的地方并不在ConfigurationClassParser类中,而是在另一个Parser中完成的。接下来看到其部分关键源码:

class ComponentScanAnnotationParser {
    private final BeanDefinitionRegistry registry;
    public Set<BeanDefinitionHolder> parse(
            AnnotationAttributes componentScan, 
            final String declaringClass) {
       // 实例化一个bean定义扫描器,这个扫描器不做过多介绍
       ClassPathBeanDefinitionScanner scanner = 
               new ClassPathBeanDefinitionScanner(this.registry,
               componentScan.getBoolean("useDefaultFilters"), 
               this.environment, this.resourceLoader);
       // 确定扫描到的bean定义名称生成器
       Class<? extends BeanNameGenerator> generatorClass = 
               componentScan.getClass("nameGenerator");
       boolean useInheritedGenerator = 
               (BeanNameGenerator.class == generatorClass);
       scanner.setBeanNameGenerator(useInheritedGenerator ? 
               this.beanNameGenerator :
               BeanUtils.instantiateClass(generatorClass));
       // 确定这些扫描的bean定义代理模式
       ScopedProxyMode scopedProxyMode = componentScan
               .getEnum("scopedProxy");
       if (scopedProxyMode != ScopedProxyMode.DEFAULT) {
          scanner.setScopedProxyMode(scopedProxyMode);
       } else {
          // 如果自定义了代理模式,则需要实现scopeResolver
          Class<? extends ScopeMetadataResolver> resolverClass = 
                  componentScan.getClass("scopeResolver");
          scanner.setScopeMetadataResolver(BeanUtils
                  .instantiateClass(resolverClass));
       }
       // 确定资源路径的解析方式
       scanner.setResourcePattern(componentScan
               .getString("resourcePattern"));
       // 这里和下面都是确定过滤器,用来包括或者去除某种bean定义
       for (AnnotationAttributes filter : componentScan
               .getAnnotationArray("includeFilters")) {
          for (TypeFilter typeFilter : typeFiltersFor(filter)) {
             scanner.addIncludeFilter(typeFilter);
          }
       }
       for (AnnotationAttributes filter : 
               componentScan.getAnnotationArray("excludeFilters")) {
          for (TypeFilter typeFilter : typeFiltersFor(filter)) {
             scanner.addExcludeFilter(typeFilter);
          }
       }
       // @ComponentScan实现延迟加载的属性,被加载的将会被这个属性确定是否
       // 延迟加载
       boolean lazyInit = componentScan.getBoolean("lazyInit");
       if (lazyInit) {
          scanner.getBeanDefinitionDefaults().setLazyInit(true);
       }
       // 接下来便是确定需要查询的路径
       Set<String> basePackages = new LinkedHashSet<>();
       String[] basePackagesArray = componentScan
               .getStringArray("basePackages");
       for (String pkg : basePackagesArray) {
          String[] tokenized = StringUtils
                  .tokenizeToStringArray(this.environment
                          .resolvePlaceholders(pkg),
                  ConfigurableApplicationContext
                      .CONFIG_LOCATION_DELIMITERS);
          Collections.addAll(basePackages, tokenized);
       }
       for (Class<?> clazz : componentScan
               .getClassArray("basePackageClasses")) {
          basePackages.add(ClassUtils.getPackageName(clazz));
       }
       if (basePackages.isEmpty()) {
          basePackages.add(ClassUtils.getPackageName(declaringClass));
       }
       // 再次添加一个排除器,功能是要求类全限定名一致
       scanner.addExcludeFilter(
               new AbstractTypeHierarchyTraversingFilter(false, false) {
          @Override
          protected boolean matchClassName(String className) {
             return declaringClass.equals(className);
          }
       });
       // 开始扫描路径下的bean定义
       return scanner.doScan(StringUtils.toStringArray(basePackages));
    }
}

1.4 processImports解析@Import注解

这个方法便是用来解析@Import以及搭配接口的地方,其部分关键源码如下:

class ConfigurationClassParser {
    private Set<SourceClass> getImports(SourceClass sourceClass) 
            throws IOException {
       Set<SourceClass> imports = new LinkedHashSet<>();
       Set<SourceClass> visited = new LinkedHashSet<>();
       // 收集@Import注解需要导入的类
       collectImports(sourceClass, imports, visited);
       return imports;
    }
    private void collectImports(SourceClass sourceClass, 
            Set<SourceClass> imports, Set<SourceClass> visited)
            throws IOException {
       // 如果添加成功则说明原来没有,添加失败则说明已经存在
       if (visited.add(sourceClass)) {
          // 依次遍历配置类的注解
          for (SourceClass annotation : sourceClass.getAnnotations()) {
             String annName = annotation.getMetadata().getClassName();
             // 如果注解名称不是@Import,则递归调用
             if (!annName.equals(Import.class.getName())) {
                collectImports(annotation, imports, visited);
             }
          }
          // 获取@Import注解的所有元素并放入@Import候选者集合中
          imports.addAll(sourceClass
              .getAnnotationAttributes(Import.class.getName(), "value"));
       }
    }
    private void processImports(ConfigurationClass configClass, 
            SourceClass currentSourceClass, 
            Collection<SourceClass> importCandidates, 
            boolean checkForCircularImports) {
       // importCandidates将包含了@Import引入的候选者类集合
       // 如果为空则说明没有引入,直接返回退出
       if (importCandidates.isEmpty()) {
          return;
       }
       // 正常流程checkForCircularImports 将是true,因此如果存在循环引用
       // 则会抛出异常,isChainedImportOnStack方法判断的则是importStack
       // 栈中是否含有当前配置类
       if (checkForCircularImports && isChainedImportOnStack(configClass)){
          this.problemReporter.error(
          // 添加循环异常错误
          new CircularImportProblem(configClass, this.importStack));
       } else {
          // 将配置类放入@Import栈
          this.importStack.push(configClass);
          try {
             for (SourceClass candidate : importCandidates) {
                // 如果实现了ImportSelector接口
                if (candidate.isAssignable(ImportSelector.class)) {
                   Class<?> candidateClass = candidate.loadClass();
                   // 将其实例化成ImportSelector对象
                   ImportSelector selector = BeanUtils
                           .instantiateClass(candidateClass, 
                                   ImportSelector.class);
                   ParserStrategyUtils.invokeAwareMethods(
                         selector, this.environment, this.resourceLoader,
                         this.registry);
                   if (selector instanceof DeferredImportSelector) {
                      // 延迟ImportSelector对象需要进行额外的处理,这个不经常
                      // 使用,因此暂时略过
                      this.deferredImportSelectorHandler
                              .handle(configClass, 
                              (DeferredImportSelector) selector);
                   }
                   else {
                      // 直接调用ImportSelector接口的方法selectImports获取
                      // 需要导入的类名称
                      String[] importClassNames = selector
                          .selectImports(currentSourceClass.getMetadata());
                      // 将其使用SourceClass封装
                      Collection<SourceClass> importSourceClasses = 
                              asSourceClasses(importClassNames);
                      // 并且再次调用本方法循环,解决嵌套的情况
                      processImports(configClass, currentSourceClass, 
                              importSourceClasses, false);
                   }
                } else if (candidate.isAssignable(
                        ImportBeanDefinitionRegistrar.class)) {
                   // 如果实现的是ImportBeanDefinitionRegistrar接口
                   Class<?> candidateClass = candidate.loadClass();
                   // 实例化成ImportBeanDefinitionRegistrar对象
                   ImportBeanDefinitionRegistrar registrar =
                         BeanUtils.instantiateClass(candidateClass,
                         ImportBeanDefinitionRegistrar.class);
                   ParserStrategyUtils.invokeAwareMethods(
                         registrar, this.environment, this.resourceLoader,
                         this.registry);
                   // 最后将其添加到配置类的importBeanDefinitionRegistrars
                   // 集合中,以方便后续加载bean定义时使用
                   configClass.addImportBeanDefinitionRegistrar(registrar,
                           currentSourceClass.getMetadata());
                } else {
                   // 如果没有实现配套的接口,那么走默认的,@Import引入的类添加
                   // 到imports集合中
                   this.importStack.registerImport(
                         currentSourceClass.getMetadata(), 
                         candidate.getMetadata().getClassName());
                   // 接着把新添加的封装成配置类,再调用一次
                   // processConfigurationClass进行配置类解析
                   processConfigurationClass(
                           candidate.asConfigClass(configClass));
                }
             }
          }
          // 捕获异常
          ...
          finally {
             // 导入栈出栈
             this.importStack.pop();
          }
       }
    }
}

1.5 retrieveBeanMethodMetadata解析获取@Bean注解

其关键部分源码如下:

class ConfigurationClassParser {
    private Set<MethodMetadata> retrieveBeanMethodMetadata(
            SourceClass sourceClass) {
       // 先获取注解元数据
       AnnotationMetadata original = sourceClass.getMetadata();
       // 再使用注解元数据获取存在bean的方法元数据
       Set<MethodMetadata> beanMethods = original
               .getAnnotatedMethods(Bean.class.getName());
       // 如果数量不为零,且注解元数据类型是StandardAnnotationMetadata
       // 但是一般情况下不会为这个类型,一般前面通过parser获取的方式都是通过
       // ClassPathBeanDefinitionScanner类,AnnotatedBeanDefinitionReader
       // 类的读取方式获取到的注解元数据才是StandardAnnotationMetadata
       // 而这个bean定义读取器只在AnnotationConfigApplicationContext中使用
       if (beanMethods.size() > 1 && 
               original instanceof StandardAnnotationMetadata) {
          try 
             // 注解元数据类型StandardAnnotationMetadata需要采取特殊处理
             // 这里再使用metadataReaderFactory获取一次注解元数据是因为
             // JVM的标准反射以任意的方式返回方法顺序,甚至在相同JVM上
             // 相同应用程序的不同运行之间也是如此,所以尝试通过ASM读取
             // 类文件的确定性声明顺序
             AnnotationMetadata asm =
                   this.metadataReaderFactory.getMetadataReader(original
                       .getClassName()).getAnnotationMetadata();
             Set<MethodMetadata> asmMethods = asm
                     .getAnnotatedMethods(Bean.class.getName());
             // 通过asm获取到的bean方法不为0
             if (asmMethods.size() >= beanMethods.size()) {
                Set<MethodMetadata> selectedMethods = 
                        new LinkedHashSet<>(asmMethods.size());
                // 这里做两次循环是确保asm和JVM都读取出来了这个方法
                // 以避免两种不同的读取方法发生差别
                for (MethodMetadata asmMethod : asmMethods) {
                   for (MethodMetadata beanMethod : beanMethods) {
                      // 方法名相同说明两种读取方式都成功了
                      if (beanMethod.getMethodName()
                              .equals(asmMethod.getMethodName())) {
                         // 添加到selectedMethods集合中
                         selectedMethods.add(beanMethod);
                         break;
                      }
                   }
                }
                // 数量相等说明是正常的
                if (selectedMethods.size() == beanMethods.size()) {
                   beanMethods = selectedMethods;
                }
             }
          }
          // 抛异常
          ...
       }
       // 返回对象集合,如果asm判断失败了获取的也是JVM获取到的注解方法
       // 所以无论如何最终这个集合的数据就是通过JVM原生注解读取方法获取的
       return beanMethods;
    }
}

2.ConfigurationClassBeanDefinitionReader读取注册配置类

这个类便是读取注册bean定义的地方,下面将会只说明一下其大致调用的方法,具体实现放到后面的小节分析。其部分关键源码如下:

class ConfigurationClassBeanDefinitionReader {
    // bean注册中心
    private final BeanDefinitionRegistry registry;
    public void loadBeanDefinitions(
            Set<ConfigurationClass> configurationModel) {
       // 在ConfigurationClassPostProcessor类中调用的便是该方法
       TrackedConditionEvaluator trackedConditionEvaluator = 
               new TrackedConditionEvaluator();
       // 对配置类集合进行遍历
       for (ConfigurationClass configClass : configurationModel) {
          loadBeanDefinitionsForConfigurationClass(configClass,
                  trackedConditionEvaluator);
       }
    }
    private void loadBeanDefinitionsForConfigurationClass(
            ConfigurationClass configClass, 
            TrackedConditionEvaluator trackedConditionEvaluator) {
       // 判断配置类是否应该跳过,有导入的配置类最终会使用conditionEvaluator
       // 来判断@Conditional注解来判断是否需要跳过,如果这个配置类中导入的配置
       // 类全部需要跳过则会跳过防止重复加载,如果有一个不需要跳过则不会跳过
       if (trackedConditionEvaluator.shouldSkip(configClass)) {
          // 删除importRegistry注册中心的配置类
          String beanName = configClass.getBeanName();
          if (StringUtils.hasLength(beanName) && 
                  this.registry.containsBeanDefinition(beanName)) {
             this.registry.removeBeanDefinition(beanName);
          }
          this.importRegistry.removeImportingClass(
                  configClass.getMetadata().getClassName());
          return;
       }
       // 导入的配置类不为空则将配置类注册到bean工厂中
       if (configClass.isImported()) {
          // 这个方法的大致作用便是获取配置类的定义和className,然后注册到
          // spring注册中心,没什么看的,略过
          registerBeanDefinitionForImportedConfigurationClass(configClass);
       }
       // 遍历这个配置类的@Bean方法对象
       for (BeanMethod beanMethod : configClass.getBeanMethods()) {
          // 解析@Bean注解的各种属性,并最终注册到Spring工厂中
          loadBeanDefinitionsForBeanMethod(beanMethod);
       }
       // 这个方法是用来处理前面@ImportResource注解引入的资源类
       loadBeanDefinitionsFromImportedResources(
               configClass.getImportedResources());
       // 处理调用和@Import注解搭配使用的ImportBeanDefinitionRegistrar接口
       loadBeanDefinitionsFromRegistrars(
               configClass.getImportBeanDefinitionRegistrars());
    }
    private void loadBeanDefinitionsFromRegistrars(
            Map<ImportBeanDefinitionRegistrar, AnnotationMetadata> 
                    registrars) {
       // 简单粗暴,获取配置类的ImportBeanDefinitionRegistrar实现类集合
       // 直接遍历调用接口方法registerBeanDefinitions
       registrars.forEach((registrar, metadata) ->
             registrar.registerBeanDefinitions(metadata, this.registry));
    }
}

2.1 解析@Bean注解的BeanMethod对象

其部分关键源码如下:

class ConfigurationClassBeanDefinitionReader {
    private void loadBeanDefinitionsForBeanMethod(BeanMethod beanMethod) {
       // 这个方法一共看起来很长,但实际上实际起效的只有四个片段,因此等下分析的
       // 时候会略过逻辑大致重复的部分
       // 一、判断当前的beanMethod是否应该略过
       ConfigurationClass configClass = beanMethod.getConfigurationClass();
       MethodMetadata metadata = beanMethod.getMetadata();
       String methodName = metadata.getMethodName();
       // 判断这个方法是否含有@Conditional注解,且是否满足,如不满足则直接返回
       // 不再处理这个beanMethod对象
       if (this.conditionEvaluator.shouldSkip(metadata,
               ConfigurationPhase.REGISTER_BEAN)) {
          configClass.skippedBeanMethods.add(methodName);
          return;
       }
       // 同一个beanMethod对象无需重复执行两次
       if (configClass.skippedBeanMethods.contains(methodName)) {
          return;
       }
       // 二、读取@Bean注解的name属性,且注册到Spring别名中心
       AnnotationAttributes bean = AnnotationConfigUtils
               .attributesFor(metadata, Bean.class);
       // 获取name属性
       List<String> names = new ArrayList<>(Arrays.asList(
               bean.getStringArray("name")));
       String beanName = (!names.isEmpty() ? names.remove(0) : methodName);
       // 将name依次注册到spring别名中心
       for (String alias : names) {
          this.registry.registerAlias(beanName, alias);
       }
       // 判断是否被有效覆盖
       if (isOverriddenByExistingDefinition(beanMethod, beanName)) {
          if (beanName.equals(beanMethod.getConfigurationClass()
                  .getBeanName())) {
             throw new BeanDefinitionStoreException();
          }
          return;
       }
       // 根据@Bean注解的其它属性设置bean定义成员属性
       // 这里创建之后会先设置bean定义的默认值,如resource、source
       // beanClassName、factoryMethodName和AutowiredMode等属性
       ConfigurationClassBeanDefinition beanDef = 
               new ConfigurationClassBeanDefinition(configClass, metadata);
       beanDef.setResource(configClass.getResource());
       beanDef.setSource(this.sourceExtractor.extractSource(metadata,
               configClass.getResource()));
       if (metadata.isStatic()) {
          beanDef.setBeanClassName(configClass.getMetadata()
                  .getClassName());
          beanDef.setFactoryMethodName(methodName);
       }
       else {
          beanDef.setFactoryBeanName(configClass.getBeanName());
          beanDef.setUniqueFactoryMethodName(methodName);
       }
       beanDef.setAutowireMode(AbstractBeanDefinition
               .AUTOWIRE_CONSTRUCTOR);
       beanDef.setAttribute(org.springframework.beans.factory
               .annotation.RequiredAnnotationBeanPostProcessor.
             SKIP_REQUIRED_CHECK_ATTRIBUTE, Boolean.TRUE);
       AnnotationConfigUtils.processCommonDefinitionAnnotations(beanDef,
               metadata);
       // 后面则是读取@Bean注解的相应值且对bean定义进行赋值,略过
       // 涉及的属性有autowire,autowireCandidate,initMethod,destroyMethod
       ...
       // 三、读取@Scope注解值来设置Scope属性(如果有的话)
       ScopedProxyMode proxyMode = ScopedProxyMode.NO;
       AnnotationAttributes attributes = AnnotationConfigUtils
               .attributesFor(metadata, Scope.class);
       if (attributes != null) {
          beanDef.setScope(attributes.getString("value"));
          proxyMode = attributes.getEnum("proxyMode");
          if (proxyMode == ScopedProxyMode.DEFAULT) {
             proxyMode = ScopedProxyMode.NO;
          }
       }
       // 四、将bean定义注册到spring的注册中心
       BeanDefinition beanDefToRegister = beanDef;
       if (proxyMode != ScopedProxyMode.NO) {
          // 处理前面的代理属性
          BeanDefinitionHolder proxyDef = ScopedProxyCreator
                  .createScopedProxy(
                  new BeanDefinitionHolder(beanDef, beanName), 
                  this.registry, proxyMode==ScopedProxyMode.TARGET_CLASS);
          beanDefToRegister = new ConfigurationClassBeanDefinition(
                (RootBeanDefinition) proxyDef.getBeanDefinition(),
                        configClass, metadata);
       }
       // 调用注册方法
       this.registry.registerBeanDefinition(beanName, beanDefToRegister);
    }
}

2.2 解析@ImportSource注入的resource对象

其部分关键源码如下:

class ConfigurationClassBeanDefinitionReader {
    private void loadBeanDefinitionsFromImportedResources(
            Map<String, Class<? extends BeanDefinitionReader>> 
                    importedResources) {
       // 缓存实例化的读取器
       Map<Class<?>, BeanDefinitionReader> readerInstanceCache = 
               new HashMap<>();
       // 遍历传进来的importedResources资源集合
       importedResources.forEach((resource, readerClass) -> {
          if (BeanDefinitionReader.class == readerClass) {
             if (StringUtils.endsWithIgnoreCase(resource, ".groovy")) {
                // 如果资源是groovy文件则初始化GroovyBeanDefinitionReader
                readerClass = GroovyBeanDefinitionReader.class;
             }
             else {
                // 如果资源是XML文件则初始化XmlBeanDefinitionReader
                readerClass = XmlBeanDefinitionReader.class;
             }
          }
          // 先从缓存中获取读取器
          BeanDefinitionReader reader = readerInstanceCache
                  .get(readerClass);
          if (reader == null) {
             try {
                // 如果获取为空则调用构造函数初始化对象
                reader = readerClass.getConstructor(BeanDefinitionRegistry
                        .class).newInstance(this.registry);
                // 对AbstractBeanDefinitionReader进行特殊处理,实际上
                // 实例化的一定是这个抽象类的子类
                if (reader instanceof AbstractBeanDefinitionReader) {
                   AbstractBeanDefinitionReader abdr = 
                           ((AbstractBeanDefinitionReader) reader);
                   abdr.setResourceLoader(this.resourceLoader);
                   abdr.setEnvironment(this.environment);
                }
                // 将实例化的对象放入缓存
                readerInstanceCache.put(readerClass, reader);
             } catch (Throwable ex) {
                throw new IllegalStateException();
             }
          }
          // 调用reader来读取加载读取到的bean定义,略过
          reader.loadBeanDefinitions(resource);
       });
    }
}

到此读取@Configuration配置类及相关的注解接口便告一段落。

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值