likes
comments
collection
share

Spring5源码10-注解版配置文件解析(上)

作者站长头像
站长
· 阅读数 52

欢迎大家关注 github.com/hsfxuebao ,希望对大家有所帮助,要是觉得可以的话麻烦给点一下Star哈

注解版获取ApplicationContext:

AnnotationConfigApplicationContext context =
      new AnnotationConfigApplicationContext(MainConfig.class);

AnnotationConfigApplicationContext的构造器:

public AnnotationConfigApplicationContext(Class<?>... componentClasses) {
   // todo
   this();
   // todo
   register(componentClasses);
   // 容器完整刷新,创建所有组件并组织好功能
   refresh();
}

接下里分别分析这三个方法。

1. this()

public AnnotationConfigApplicationContext() {
   StartupStep createAnnotatedBeanDefReader = this.getApplicationStartup().start("spring.context.annotated-bean-reader.create");
   // todo
   this.reader = new AnnotatedBeanDefinitionReader(this);
   createAnnotatedBeanDefReader.end();
   // todo
   this.scanner = new ClassPathBeanDefinitionScanner(this);
}

1.1 AnnotatedBeanDefinitionReader

public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry, Environment environment) {
   Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
   Assert.notNull(environment, "Environment must not be null");
   this.registry = registry;
   this.conditionEvaluator = new ConditionEvaluator(registry, environment, null);
   // todo 注册注解配置的处理器
   AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);
}

核心方法AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);

public static Set<BeanDefinitionHolder> registerAnnotationConfigProcessors(
      BeanDefinitionRegistry registry, @Nullable Object source) {

   DefaultListableBeanFactory beanFactory = unwrapDefaultListableBeanFactory(registry);
   if (beanFactory != null) {
      if (!(beanFactory.getDependencyComparator() instanceof AnnotationAwareOrderComparator)) {
         beanFactory.setDependencyComparator(AnnotationAwareOrderComparator.INSTANCE);
      }
      if (!(beanFactory.getAutowireCandidateResolver() instanceof ContextAnnotationAutowireCandidateResolver)) {
         beanFactory.setAutowireCandidateResolver(new ContextAnnotationAutowireCandidateResolver());
      }
   }

   Set<BeanDefinitionHolder> beanDefs = new LinkedHashSet<>(8);

   // 注册 配置类
   if (!registry.containsBeanDefinition(CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)) {
      RootBeanDefinition def = new RootBeanDefinition(ConfigurationClassPostProcessor.class);
      def.setSource(source);
      beanDefs.add(registerPostProcessor(registry, def, CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME));
   }

   // 注册底层的自动装配处理器
   if (!registry.containsBeanDefinition(AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME)) {
      RootBeanDefinition def = new RootBeanDefinition(AutowiredAnnotationBeanPostProcessor.class);
      def.setSource(source);
      beanDefs.add(registerPostProcessor(registry, def, AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME));
   }

   // Check for JSR-250 support, and if present add the CommonAnnotationBeanPostProcessor.
   // 注册支持JSR-250 的处理器
   if (jsr250Present && !registry.containsBeanDefinition(COMMON_ANNOTATION_PROCESSOR_BEAN_NAME)) {
      RootBeanDefinition def = new RootBeanDefinition(CommonAnnotationBeanPostProcessor.class);
      def.setSource(source);
      beanDefs.add(registerPostProcessor(registry, def, COMMON_ANNOTATION_PROCESSOR_BEAN_NAME));
   }

   // Check for JPA support, and if present add the PersistenceAnnotationBeanPostProcessor.
   // 注册 JPA的处理器
   if (jpaPresent && !registry.containsBeanDefinition(PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME)) {
      RootBeanDefinition def = new RootBeanDefinition();
      try {
         def.setBeanClass(ClassUtils.forName(PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME,
               AnnotationConfigUtils.class.getClassLoader()));
      }
      catch (ClassNotFoundException ex) {
         throw new IllegalStateException(
               "Cannot load optional framework class: " + PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME, ex);
      }
      def.setSource(source);
      beanDefs.add(registerPostProcessor(registry, def, PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME));
   }

   // 注册 事件功能 (事件方法)的后置处理器
   if (!registry.containsBeanDefinition(EVENT_LISTENER_PROCESSOR_BEAN_NAME)) {
      RootBeanDefinition def = new RootBeanDefinition(EventListenerMethodProcessor.class);
      def.setSource(source);
      beanDefs.add(registerPostProcessor(registry, def, EVENT_LISTENER_PROCESSOR_BEAN_NAME));
   }
   // 注册 事件功能 (事件工厂)的后置处理器
   if (!registry.containsBeanDefinition(EVENT_LISTENER_FACTORY_BEAN_NAME)) {
      RootBeanDefinition def = new RootBeanDefinition(DefaultEventListenerFactory.class);
      def.setSource(source);
      beanDefs.add(registerPostProcessor(registry, def, EVENT_LISTENER_FACTORY_BEAN_NAME));
   }

   return beanDefs;
}

给工厂中注册核心组件:

  • ConfigurationClassPostProcessor:(BeanDefinitionRegistryPostProcessor)处理配置类
  • AutowiredAnnotationBeanPostProcessor:(SmartInstantiationAwareBeanPostProcessor)自动装配能力
  • CommonAnnotationBeanPostProcessorInstantiationAwareBeanPostProcessor):注册支持JSR-250 的处理器,处理@PostConstrut、@PreDestroy、@Resource注解
  • PersistenceAnnotationBeanPostProcessorInstantiationAwareBeanPostProcessor):处理jpa功能
  • EventListenerMethodProcessor:事件功能(事件方法)的后置处理器
  • DefaultEventListenerFactory:事件工厂

1.2 ClassPathBeanDefinitionScanner

scanner扫描需要导入的所有bean信息。

public ClassPathBeanDefinitionScanner(BeanDefinitionRegistry registry, boolean useDefaultFilters,
      Environment environment, @Nullable ResourceLoader resourceLoader) {

   Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
   this.registry = registry;

   // todo
   if (useDefaultFilters) {
      registerDefaultFilters();
   }
   setEnvironment(environment);
   setResourceLoader(resourceLoader);
}
protected void registerDefaultFilters() {
   // Component注解
   //过滤器中添加需要扫描的注解类型,把@Component注解添加进来
   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.
   }
}

2. register(componentClasses);

通过reader注册所有的主配置类。

public void register(Class<?>... componentClasses) {
   Assert.notEmpty(componentClasses, "At least one component class must be specified");
   StartupStep registerComponentClass = this.getApplicationStartup().start("spring.context.component-classes.register")
         .tag("classes", () -> Arrays.toString(componentClasses));
   // todo
   this.reader.register(componentClasses);
   registerComponentClass.end();
}

public void register(Class<?>... componentClasses) {
   for (Class<?> componentClass : componentClasses) {
      // 注册bean
      registerBean(componentClass);
   }
}

registerBean的实际执行方法为doRegisterBean:

private <T> void doRegisterBean(Class<T> beanClass, @Nullable String name,
      @Nullable Class<? extends Annotation>[] qualifiers, @Nullable Supplier<T> supplier,
      @Nullable BeanDefinitionCustomizer[] customizers) {

   AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(beanClass);
   if (this.conditionEvaluator.shouldSkip(abd.getMetadata())) {
      return;
   }

   abd.setInstanceSupplier(supplier);
   ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(abd);
   abd.setScope(scopeMetadata.getScopeName());
   String beanName = (name != null ? name : this.beanNameGenerator.generateBeanName(abd, this.registry));

   // todo 完善主配置类的BeanDefinition,解读所有bean定义信息需要感知的注解
   AnnotationConfigUtils.processCommonDefinitionAnnotations(abd);
   if (qualifiers != null) {
      for (Class<? extends Annotation> qualifier : qualifiers) {
         if (Primary.class == qualifier) {
            abd.setPrimary(true);
         }
         else if (Lazy.class == qualifier) {
            abd.setLazyInit(true);
         }
         else {
            abd.addQualifier(new AutowireCandidateQualifier(qualifier));
         }
      }
   }
   if (customizers != null) {
      for (BeanDefinitionCustomizer customizer : customizers) {
         customizer.customize(abd);
      }
   }

   BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(abd, beanName);
   definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
   BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry);
}
// 解读所有bean定义信息需要感知的注解
static void processCommonDefinitionAnnotations(AnnotatedBeanDefinition abd, AnnotatedTypeMetadata metadata) {
   AnnotationAttributes lazy = attributesFor(metadata, Lazy.class);
   if (lazy != null) {
      abd.setLazyInit(lazy.getBoolean("value"));
   }
   else if (abd.getMetadata() != metadata) {
      lazy = attributesFor(abd.getMetadata(), Lazy.class);
      if (lazy != null) {
         abd.setLazyInit(lazy.getBoolean("value"));
      }
   }

   if (metadata.isAnnotated(Primary.class.getName())) {
      abd.setPrimary(true);
   }
   AnnotationAttributes dependsOn = attributesFor(metadata, DependsOn.class);
   if (dependsOn != null) {
      abd.setDependsOn(dependsOn.getStringArray("value"));
   }

   AnnotationAttributes role = attributesFor(metadata, Role.class);
   if (role != null) {
      abd.setRole(role.getNumber("value").intValue());
   }
   AnnotationAttributes description = attributesFor(metadata, Description.class);
   if (description != null) {
      abd.setDescription(description.getString("value"));
   }
}

完善主配置类的定义信息,解析@Lazy、@Primary、@DependOn、@Description参数,但是在这 主配置类中的配置并没有生效。 是在ConfigurationClassPostProcessor中执行生效的。

接下里我们着重分析ConfigurationClassPostProcessorAutowiredAnnotationBeanPostProcessor这两个后置处理器。

3. ConfigurationClassPostProcessor后置处理器

ConfigurationClassPostProcessor 是非常重要的一个 后处理器。 ConfigurationClassPostProcessor 完成了 配置类的解析和保存以及@Component 注解、@Import 等注解的解析工作 。将所有需要注入的bean解析成 BeanDefinition保存到 BeanFactory 中

3.1. ConfigurationClassPostProcessor

其结构图如下。

Spring5源码10-注解版配置文件解析(上)

可见ConfigurationClassPostProcessor 接口实现了BeanDefinitionRegistryPostProcessor(BeanFactory 的后处理器) PriorityOrdered(设置自己的优先级为最高) 和各种 Aware 接口。

我们这里重点看的是 BeanDefinitionRegistryPostProcessor 接口的两个方法:

// 完成对 @Bean 方法的代理
void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException;
// 允许在Spring容器启动后,在下一个阶段开始前,添加BeanDefinition的定义
void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException;

关于这两个方法的调用时机和作用,我们在之前的文章Spring5源码5-Bean生命周期后置处理器已经讲过,调用过程主要是在 Spring容器刷新的过程中,其中 postProcessBeanDefinitionRegistry 方法先于 postProcessBeanFactory 方法被调用。

本小节 分析了 ConfigurationClassPostProcessor#postProcessBeanDefinitionRegistry 方法。得知了ConfigurationClassPostProcessor解析配置类(这里的配置类不仅仅局限于@Configuration 注解,还包括 @Import、 @ImportResource 等注解),将解析到的需要注入到Spring容器中的bean的BeanDefinition保存起来。在后面的bean 初始化都需要BeanDefinition。

3.2 postProcessBeanDefinitionRegistry方法

public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
        .... 省略部分代码
        // 关键方法,解析 配置类的定义
        processConfigBeanDefinitions(registry);
}

可以看到 postProcessBeanDefinitionRegistry 方法中并没有处理什么逻辑,真正逻辑在其调用的 processConfigBeanDefinitions 方法中。

processConfigBeanDefinitions 方法完成了关于配置类的所有解析。需要注意的是,到达这一步的时候, Spring 启动类已经被解析成BeanDefinition 注册到容器中。详细代码如下:

public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
   List<BeanDefinitionHolder> configCandidates = new ArrayList<>();
   // 获取所有BeanDefinitionNames
   String[] candidateNames = registry.getBeanDefinitionNames();

   for (String beanName : candidateNames) {
      // 获取BeanDefinition
      BeanDefinition beanDef = registry.getBeanDefinition(beanName);
      // 如果bean被解析过(Bean 被解析后会在beanDef 中设置属性 CONFIGURATION_CLASS_ATTRIBUTE ),if 属性成立,这里是为了防止重复解析
      if (beanDef.getAttribute(ConfigurationClassUtils.CONFIGURATION_CLASS_ATTRIBUTE) != null) {
         if (logger.isDebugEnabled()) {
            logger.debug("Bean definition has already been processed as a configuration class: " + beanDef);
         }
      }
      // todo 1. ConfigurationClassUtils.checkConfigurationClassCandidate 解析了当前bean是否是配置类,
      //  需要注意的是,本文所说的配置类即使满足 full 或 lite 条件的类,而不仅仅是被 @Configuration 修饰的类。
      else if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) {
         // 将配置类加到候选集合里面,等待处理
         configCandidates.add(new BeanDefinitionHolder(beanDef, beanName));
      }
   }

   // Return immediately if no @Configuration classes were found
   // 如果没有找到配置类,则直接返回,不需要下面的解析
   if (configCandidates.isEmpty()) {
      return;
   }

   // Sort by previously determined @Order value, if applicable
   // 对 所有的配置类进行排序
   // 按照@Order 注解进行排序(如果使用了 @Order 注解的话)
   configCandidates.sort((bd1, bd2) -> {
      int i1 = ConfigurationClassUtils.getOrder(bd1.getBeanDefinition());
      int i2 = ConfigurationClassUtils.getOrder(bd2.getBeanDefinition());
      return Integer.compare(i1, i2);
   });

   // Detect any custom bean name generation strategy supplied through the enclosing application context
   // 判断如果是 registry  是 SingletonBeanRegistry 类型,则从中获取 beanName 生成器(BeanNameGenerator )。
   // 实际上这里是 register 类型是 DefaultListableBeanFactory。是 SingletonBeanRegistry  的子类
   SingletonBeanRegistry sbr = null;
   if (registry instanceof SingletonBeanRegistry) {
      sbr = (SingletonBeanRegistry) registry;
      if (!this.localBeanNameGeneratorSet) {
         // getBean -> getSingleton 获取创建一个internalConfigurationBeanNameGenerator 来用来生成配置类的名字
         BeanNameGenerator generator = (BeanNameGenerator) sbr.getSingleton(
               AnnotationConfigUtils.CONFIGURATION_BEAN_NAME_GENERATOR);
         if (generator != null) {
            this.componentScanBeanNameGenerator = generator;
            this.importBeanNameGenerator = generator;
         }
      }
   }

   // 如果环境变量为空则指定一个标准环境,这里是 StandardServletEnvironment 类型
   if (this.environment == null) {
      this.environment = new StandardEnvironment();
   }

   // Parse each @Configuration class
   // 由ConfigurationClassParser 解析每一个配置类
   ConfigurationClassParser parser = new ConfigurationClassParser(
         this.metadataReaderFactory, this.problemReporter, this.environment,
         this.resourceLoader, this.componentScanBeanNameGenerator, registry);

   // 用来保存尚未解析的配置类
   Set<BeanDefinitionHolder> candidates = new LinkedHashSet<>(configCandidates);
   // 用来保存已经解析的配置类
   Set<ConfigurationClass> alreadyParsed = new HashSet<>(configCandidates.size());
   // do..while 循环解析。因为一个配置类可能引入另一个配置类,需要循环解析,直至没有其他需要解析的类。
   do {
      StartupStep processConfig = this.applicationStartup.start("spring.context.config-classes.parse");
      // 2. 开始解析。后面详细分析
      // todo 解析配置类,所有需要扫描进来的组件Bean定义信息都已经完成
      parser.parse(candidates);
      // 3. 这里的校验规则是如果是被 @Configuration修饰且proxyBeanMethods属性为true,则类不能为final。如果@Bean修饰的方法,则必须是可覆盖的.
      // todo 因为@Configuration(proxyBeanMethods = true) 是需要cglib代理的,所以不能为终态, @Bean所修饰的方法也有一套约束规则,下面详细讲
      // 是否需要代理是根据 类或方法上的 @Scope 注解指定的,默认都是不代理
      parser.validate();

      // configClasses  保存这次解析出的配置类。此时这些ConfigurationClass 中保存了解析出来的各种属性值,等待最后构建 BeanDefinition
      Set<ConfigurationClass> configClasses = new LinkedHashSet<>(parser.getConfigurationClasses());
      // 去除已经解析过的配置类
      configClasses.removeAll(alreadyParsed);

      // Read the model and create bean definitions based on its content
      // 每一个组件都可以当成配置类,@Import之类都能进行处理
      if (this.reader == null) {
         this.reader = new ConfigurationClassBeanDefinitionReader(
               registry, this.sourceExtractor, this.resourceLoader, this.environment,
               this.importBeanNameGenerator, parser.getImportRegistry());
      }
      // todo 4. 注册bean
      this.reader.loadBeanDefinitions(configClasses);
      alreadyParsed.addAll(configClasses);
      processConfig.tag("classCount", () -> String.valueOf(configClasses.size())).end();

      candidates.clear();
      // if 如果成立,说明有新的bean注册了,则需要解析新的bean
      if (registry.getBeanDefinitionCount() > candidateNames.length) {
         // 获取新的beanName
         String[] newCandidateNames = registry.getBeanDefinitionNames();
         Set<String> oldCandidateNames = new HashSet<>(Arrays.asList(candidateNames));
         Set<String> alreadyParsedClasses = new HashSet<>();
         for (ConfigurationClass configurationClass : alreadyParsed) {
            alreadyParsedClasses.add(configurationClass.getMetadata().getClassName());
         }
         for (String candidateName : newCandidateNames) {
            if (!oldCandidateNames.contains(candidateName)) {
               // 过滤出未解析的bean检测是否是未解析过的配置类
               BeanDefinition bd = registry.getBeanDefinition(candidateName);
               // todo
               if (ConfigurationClassUtils.checkConfigurationClassCandidate(bd, this.metadataReaderFactory) &&
                     !alreadyParsedClasses.contains(bd.getBeanClassName())) {
                  // 如果是未解析的配置类,则保存到candidates中
                  candidates.add(new BeanDefinitionHolder(bd, candidateName));
               }
            }
         }
         candidateNames = newCandidateNames;
      }
   }
   // 如果 candidates 不为空,则说明有未被解析的配置类,循环解析。
   while (!candidates.isEmpty());

   // Register the ImportRegistry as a bean in order to support ImportAware @Configuration classes
   // 到这里已经把配置类解析完毕了。
   // 将ImportRegistry  注册为 bean,以支持ImportAware @Configuration 类
   if (sbr != null && !sbr.containsSingleton(IMPORT_REGISTRY_BEAN_NAME)) {
      sbr.registerSingleton(IMPORT_REGISTRY_BEAN_NAME, parser.getImportRegistry());
   }

   // 清除缓存
   if (this.metadataReaderFactory instanceof CachingMetadataReaderFactory) {
      // Clear cache in externally provided MetadataReaderFactory; this is a no-op
      // for a shared cache since it'll be cleared by the ApplicationContext.
      ((CachingMetadataReaderFactory) this.metadataReaderFactory).clearCache();
   }
}

这里简单总结一下流程;

  1. 获取已经注册的Bean, 并筛选出配置类,按照@Order 进行排序,得到配置类集合 configCandidates
  2. 调用 parser.parse(candidates); 对配置类进行解析
  3. 调用 this.reader.loadBeanDefinitions(configClasses); 进行配置类的注册
  4. 检验 registry.getBeanDefinitionCount() > candidateNames.length 是否成立。这里由于第三步会将新解析出来的bean进行注册,如果这里成立,则说明有新的配置类完成了注册,获取到新注册的配置类candidateNames。循环从第二步重新解析,直到没有新注入的配置类。 上面解释的可能比较乱,因为我们下面详细去分析几个方法。

3.2.1 checkConfigurationClassCandidate

processConfigBeanDefinitions 方法中。判断一个类是否是配置类就是通过 checkConfigurationClassCandidate 方法来判断的,那么我们需要看看这个方法中是怎么实现的。

在这个方法里,关键的部分是 给 BeanDefinition 设置了CONFIGURATION_CLASS_ATTRIBUTE 为 full 或者 lite 设置这两个属性标识,如果一个类满足full或 lite的条件,则会被认为是配置类。需要注意的是,本文所说的配置类即使满足 full 或 lite 条件的类,而不仅仅是被 @Configuration 修饰的类。

首先需要注意的是,在 checkConfigurationClassCandidate 中,配置类的类型分为两种,Full 和 Lite,即完整的配置类和精简的配置类。设置的规则如下:

  • Full : 即类被 @Configuration 注解修饰 && proxyBeanMethods属性为true (默认为 true)
  • Lite : 被@Component、@ComponentScan、@Import、@ImportResource 修饰的类或者 类中有被@Bean修饰的方法。

Full 配置类就是我们常规使用的配置类,Lite 配置类就是一些需要其他操作引入一些bean 的类

下面我们来看具体代码:

public static boolean checkConfigurationClassCandidate(
      BeanDefinition beanDef, MetadataReaderFactory metadataReaderFactory) {
   // 获取className
   String className = beanDef.getBeanClassName();
   if (className == null || beanDef.getFactoryMethodName() != null) {
      return false;
   }

   // 解析关于当前被解析类的 注解元数据
   AnnotationMetadata metadata;
   // 如果当前BeanDefinition  是 AnnotatedBeanDefinition(相较于一般的 BeanDefinition,他多了一些注解信息的解析) 类型。直接获取注解元数据即可
   if (beanDef instanceof AnnotatedBeanDefinition &&
         className.equals(((AnnotatedBeanDefinition) beanDef).getMetadata().getClassName())) {
      // Can reuse the pre-parsed metadata from the given BeanDefinition...
      metadata = ((AnnotatedBeanDefinition) beanDef).getMetadata();
   }
   else if (beanDef instanceof AbstractBeanDefinition && ((AbstractBeanDefinition) beanDef).hasBeanClass()) {
      // Check already loaded Class if present...
      // since we possibly can't even load the class file for this Class.
      Class<?> beanClass = ((AbstractBeanDefinition) beanDef).getBeanClass();
      // 如果当前类是 BeanFactoryPostProcessor、BeanPostProcessor、AopInfrastructureBean、
      // EventListenerFactory 类型不当做配置类处理,返回false
      if (BeanFactoryPostProcessor.class.isAssignableFrom(beanClass) ||
            BeanPostProcessor.class.isAssignableFrom(beanClass) ||
            AopInfrastructureBean.class.isAssignableFrom(beanClass) ||
            EventListenerFactory.class.isAssignableFrom(beanClass)) {
         return false;
      }
      // 获取数据
      metadata = AnnotationMetadata.introspect(beanClass);
   }
   else {
      try {
         // 按照默认规则解析
         MetadataReader metadataReader = metadataReaderFactory.getMetadataReader(className);
         metadata = metadataReader.getAnnotationMetadata();
      }
      catch (IOException ex) {
         if (logger.isDebugEnabled()) {
            logger.debug("Could not find class file for introspecting configuration annotations: " +
                  className, ex);
         }
         return false;
      }
   }

   // 获取bean上的Configuration 注解的属性。如果没有被 @Configuration 修饰 config 则为null
   Map<String, Object> config = metadata.getAnnotationAttributes(Configuration.class.getName());
   // 如果被 @Configuration 修饰 &&  proxyBeanMethods 属性为 true。 @Configuration 的 proxyBeanMethods
   if (config != null && !Boolean.FALSE.equals(config.get("proxyBeanMethods"))) {
      // 设置 CONFIGURATION_CLASS_ATTRIBUTE 为 full
      beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, CONFIGURATION_CLASS_FULL);
   }
   // 如果被 @Configuration 修饰 &&  isConfigurationCandidate(metadata) = true
   // todo 关于  isConfigurationCandidate(metadata) 的解析在下面
   else if (config != null || isConfigurationCandidate(metadata)) {
      // 设置 CONFIGURATION_CLASS_ATTRIBUTE 为 lite
      beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, CONFIGURATION_CLASS_LITE);
   }
   else {
      return false;
   }

   // It's a full or lite configuration candidate... Let's determine the order value, if any.
   // 按照@Order 注解排序
   Integer order = getOrder(metadata);
   if (order != null) {
      beanDef.setAttribute(ORDER_ATTRIBUTE, order);
   }

   return true;
}

3.2.1.1. isConfigurationCandidate

在上面的代码中,我们看到 判断是否是 Lite 的关键方法是 isConfigurationCandidate。其代码如下:

// candidateIndicators  的定义
private static final Set<String> candidateIndicators = new HashSet<>(8);

static {
        candidateIndicators.add(Component.class.getName());
        candidateIndicators.add(ComponentScan.class.getName());
        candidateIndicators.add(Import.class.getName());
        candidateIndicators.add(ImportResource.class.getName());
}	

public static boolean isConfigurationCandidate(AnnotationMetadata metadata) {
        // Do not consider an interface or an annotation...
        // 不能是接口
        if (metadata.isInterface()) {
                return false;
        }

        // Any of the typical annotations found?
        // 被 candidateIndicators 中的注解修饰。其中 candidateIndicators  注解在静态代码块中加载了
        for (String indicator : candidateIndicators) {
                if (metadata.isAnnotated(indicator)) {
                        return true;
                }
        }

        // Finally, let's look for @Bean methods...
        try {
                // 类中包含被 @Bean 注解修饰的方法
                return metadata.hasAnnotatedMethods(Bean.class.getName());
        }
        catch (Throwable ex) {
                if (logger.isDebugEnabled()) {
                        logger.debug("Failed to introspect @Bean methods on class [" + metadata.getClassName() + "]: " + ex);
                }
                return false;
        }
}

3.2.2 parser.parse(candidates);

上面解析了如何判断一个类是否是配置类。也完成了配置类的筛选。那么开始进行配置类的解析,在 processConfigBeanDefinitions 方法中,对配置类的解析也只是一句话完成:

parser.parse(candidates);

它的作用是:将所有的配置类保存到 ConfigurationClassParser#configurationClasses 集合中

private final Map<ConfigurationClass, ConfigurationClass> configurationClasses = new LinkedHashMap<>();

解析注解并赋值给每个 ConfigurationClass 对应的属性。如解析 @Import 注解,并通过如下语句将结果保存到 ConfigurationClass.importBeanDefinitionRegistrars 集合中。

configClass.addImportBeanDefinitionRegistrar(registrar, currentSourceClass.getMetadata());

同样的还有 将@ ImportResource 注解保存到ConfigurationClass.importedResources中,将@Bean 修饰的方法 和接口静态方法保存到ConfigurationClass.beanMethods 中。 而在之后的 this.reader.loadBeanDefinitions(configClasses); 中才进行了这些属性的进一步处理

下面我们来具体看代码,其代码如下:

public void parse(Set<BeanDefinitionHolder> configCandidates) {
        for (BeanDefinitionHolder holder : configCandidates) {
                BeanDefinition bd = holder.getBeanDefinition();
                try {
                        // 针对不同类型的 BeanDefinition 做一些处理
                        if (bd instanceof AnnotatedBeanDefinition) {
                                parse(((AnnotatedBeanDefinition) bd).getMetadata(), holder.getBeanName());
                        }
                        else if (bd instanceof AbstractBeanDefinition && ((AbstractBeanDefinition) bd).hasBeanClass()) {
                                parse(((AbstractBeanDefinition) bd).getBeanClass(), holder.getBeanName());
                        }
                        else {
                                parse(bd.getBeanClassName(), holder.getBeanName());
                        }
                }
                catch (BeanDefinitionStoreException ex) {
                        throw ex;
                }
                catch (Throwable ex) {
                        throw new BeanDefinitionStoreException(
                                        "Failed to parse configuration class [" + bd.getBeanClassName() + "]", ex);
                }
        }
        // 在这里调用了 AutoConfigurationImportSelector 完成了Springboot的自动化装配
        this.deferredImportSelectorHandler.process();
}

里面的 parse 方法殊途同归,最终都会调用 processConfigurationClass 方法,所以我们直接进入 processConfigurationClass 方法:

protected void processConfigurationClass(ConfigurationClass configClass, Predicate<String> filter) throws IOException {
        // 判断是否应该跳过当前类的解析。这里面解析了 @Conditional 注解
        if (this.conditionEvaluator.shouldSkip(configClass.getMetadata(), ConfigurationPhase.PARSE_CONFIGURATION)) {
                return;
        }
        // 判断是否已经解析过。configurationClasses 中保存着已经解析过的配置类。在下面解析过的类都会被保存到 configurationClasses 中
        // 这里应该是 注入的配置类优先级高于引入的配置类
        // 如果配置类被多次引入则合并属性
        ConfigurationClass existingClass = this.configurationClasses.get(configClass);
        if (existingClass != null) {
                // 一个类被重复解析,那么可能被重复引入了,可能是通过 @Import 注解或者嵌套在其他配置类中被引入。如果这两者都是通过这种方式被引入,那么则进行引入合并
                // 如果当前配置类和之前解析过的配置类都是引入的,则直接合并
                if (configClass.isImported()) {
                        if (existingClass.isImported()) {
                                existingClass.mergeImportedBy(configClass);
                        }
                        // Otherwise ignore new imported config class; existing non-imported class overrides it.
                        // 否则,忽略新导入的配置类;现有的非导入类将覆盖它
                        return;
                }
                else {
                        // Explicit bean definition found, probably replacing an import.
                        // Let's remove the old one and go with the new one.
                        // 如果当前的配置类不是引入的,则移除之前的配置类,重新解析
                        this.configurationClasses.remove(configClass);
                        this.knownSuperclasses.values().removeIf(configClass::equals);
                }
        }

        // Recursively process the configuration class and its superclass hierarchy.
        SourceClass sourceClass = asSourceClass(configClass, filter);
        do {
                sourceClass = doProcessConfigurationClass(configClass, sourceClass, filter);
        }
        while (sourceClass != null);
        // 保存解析过的 配置类
        this.configurationClasses.put(configClass, configClass);
}

注:

  • this.conditionEvaluator.shouldSkip 中对 @Conditional 注解 注解进行了处理,由于篇幅所限(写太长了),这里不再展开叙述。
  • this.deferredImportSelectorHandler.process(); 通过对AutoConfigurationImportSelector 的处理,完成了Springboot 的自动化装配。这个等SpringBoot的时候在分析。

这里需要注意的是配置类的重复引入优先级的问题 : 一般来说,Spring有一个自己的规则 :自身注入方式 优先于 引入方式。这里的引入方式指的被 @Import 或者其他配置类引入。当一个类被多次引入时,会使用自身注入的方式的bean 替代 被引入方式的bean。如果二者都是引入方式,则进行合并(在 ConfigurationClass 类中有一个importedBy 集合,将新引入的来源保存到 importedBy 中)

void mergeImportedBy(ConfigurationClass otherConfigClass) {
   this.importedBy.addAll(otherConfigClass.importedBy);
}

看了这么久的源码,也知道了Spring的套路,方法名以do开头的才是真正做事的方法, 所以我们来看 doProcessConfigurationClass 方法。

protected final SourceClass doProcessConfigurationClass(
      ConfigurationClass configClass, SourceClass sourceClass, Predicate<String> filter)
      throws IOException {

   // 1. 处理 @Component 注解
   // 首先判断如果配置类被@Component 修饰,则调用processMemberClasses 方法处理
   if (configClass.getMetadata().isAnnotated(Component.class.getName())) {
      // todo Recursively process any member (nested) classes first
      processMemberClasses(configClass, sourceClass, filter);
   }

   // Process any @PropertySource annotations
   // 2. 处理 @PropertySource 注解
   // 去重后遍历 PropertySource 注解所指向的属性。注意这里有两个注解@PropertySources 和 @PropertySource。
   for (AnnotationAttributes propertySource : AnnotationConfigUtils.attributesForRepeatable(
         sourceClass.getMetadata(), PropertySources.class,
         org.springframework.context.annotation.PropertySource.class)) {
      if (this.environment instanceof ConfigurableEnvironment) {
         // todo 解析PropertySource  注解
         processPropertySource(propertySource);
      }
      else {
         logger.info("Ignoring @PropertySource annotation on [" + sourceClass.getMetadata().getClassName() +
               "]. Reason: Environment must implement ConfigurableEnvironment");
      }
   }

   // Process any @ComponentScan annotations
   // 3. 处理 @ComponentScan注解
   // 这里会将 @ComponentScans 中的多个 @ComponentScan 也解析出来封装成一个个AnnotationAttributes对象
   Set<AnnotationAttributes> componentScans = AnnotationConfigUtils.attributesForRepeatable(
         sourceClass.getMetadata(), ComponentScans.class, ComponentScan.class);
   // 如果当前配置类被 @componentScans 或 @componentScan 注解修饰 && 不应跳过
   if (!componentScans.isEmpty() &&
         !this.conditionEvaluator.shouldSkip(sourceClass.getMetadata(), ConfigurationPhase.REGISTER_BEAN)) {
      // 遍历 @ComponentScans、 @ComponentScan
      for (AnnotationAttributes componentScan : componentScans) {
         // The config class is annotated with @ComponentScan -> perform the scan immediately
         // 使用Scanner 把ComponentScan 指定的包下的所有组件都扫描进来
         // 直接执行扫描,根据指定路径扫描出来bean。
         Set<BeanDefinitionHolder> scannedBeanDefinitions =
               this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName());
         // Check the set of scanned definitions for any further config classes and parse recursively if needed
         // 遍历扫描出来的bean
         for (BeanDefinitionHolder holder : scannedBeanDefinitions) {
            // 获取原始的bean的定义
            BeanDefinition bdCand = holder.getBeanDefinition().getOriginatingBeanDefinition();
            if (bdCand == null) {
               bdCand = holder.getBeanDefinition();
            }
            // 检测如果是配置类,则递归调用 parse 解析。
            if (ConfigurationClassUtils.checkConfigurationClassCandidate(bdCand, this.metadataReaderFactory)) {
               parse(bdCand.getBeanClassName(), holder.getBeanName());
            }
         }
      }
   }

   // Process any @Import annotations
   // 4. 处理 @Import 注解
   // 处理@Import 注解的地方【AOP就是利用这个地方导入一个后置处理器】
   processImports(configClass, sourceClass, getImports(sourceClass), filter, true);

   // Process any @ImportResource annotations
   // 5. 处理 @ImportResource 注解
   // 处理@ImportResource
   AnnotationAttributes importResource =
         AnnotationConfigUtils.attributesFor(sourceClass.getMetadata(), ImportResource.class);
   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);
         // todo
         configClass.addImportedResource(resolvedResource, readerClass);
      }
   }

   // Process individual @Bean methods
   // 6. 处理 @Bean修饰的方法
   // 处理 @Bean
   Set<MethodMetadata> beanMethods = retrieveBeanMethodMetadata(sourceClass);
   for (MethodMetadata methodMetadata : beanMethods) {
      // todo
      configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));
   }

   // Process default methods on interfaces
   // 7. 处理其他默认接口方法
   processInterfaces(configClass, sourceClass);

   // Process superclass, if any
   // 处理父类,如果存在
   if (sourceClass.getMetadata().hasSuperClass()) {
      String superclass = sourceClass.getMetadata().getSuperClassName();
      if (superclass != null && !superclass.startsWith("java") &&
            !this.knownSuperclasses.containsKey(superclass)) {
         this.knownSuperclasses.put(superclass, configClass);
         // Superclass found, return its annotation metadata and recurse
         return sourceClass.getSuperClass();
      }
   }

   // No superclass -> processing is complete
   return null;
}

doProcessConfigurationClass 方法中的逻辑很清楚,因为他把大部分的逻辑直接封装成了方法。下面我们就来一个一个分析。

3.2.2.1 处理 @Component 注解

这里对 @Component 的处理其实是处理配置类的内部类,即如果当前类是被 @Component 修饰,则需要判断其内部类是否需要解析。

// 首先判断如果配置类被@Component 修饰,则调用processMemberClasses 方法处理
if (configClass.getMetadata().isAnnotated(Component.class.getName())) {
        // Recursively process any member (nested) classes first
        processMemberClasses(configClass, sourceClass, filter);
}

processMemberClasses 方法的代码如下: 代码逻辑也很简单。即如果配置类中有内部类,则判断其内部类是否是配置类,如果是则递归去解析新发现的内部配置类。

private void processMemberClasses(ConfigurationClass configClass, SourceClass sourceClass,
                Predicate<String> filter) throws IOException {
        // 获取内部类
        Collection<SourceClass> memberClasses = sourceClass.getMemberClasses();
        if (!memberClasses.isEmpty()) {
                // 如果有内部类,则遍历内部类,判断内部类是否是配置类,如果是,则添加到 candidates 集合中。
                List<SourceClass> candidates = new ArrayList<>(memberClasses.size());
                for (SourceClass memberClass : memberClasses) {
                        // 这里判断的是是否是lite 类型的配置类
                        if (ConfigurationClassUtils.isConfigurationCandidate(memberClass.getMetadata()) &&
                                        !memberClass.getMetadata().getClassName().equals(configClass.getMetadata().getClassName())) {
                                candidates.add(memberClass);
                        }
                }
                // 进行排序
                OrderComparator.sort(candidates);
                for (SourceClass candidate : candidates) {
                        // importStack 用来缓存已经解析过的内部类,这里处理循环引入问题。
                        if (this.importStack.contains(configClass)) {
                                // 打印循环引用异常
                                this.problemReporter.error(new CircularImportProblem(configClass, this.importStack));
                        }
                        else {
                                // 解析前入栈,防止循环引入
                                this.importStack.push(configClass);
                                try {
                                        // 递归去解析新发现的配置类
                                        processConfigurationClass(candidate.asConfigClass(configClass), filter);
                                }
                                finally {
                                        // 解析完毕出栈
                                        this.importStack.pop();
                                }
                        }
                }
        }
}

说明:

  • 判断内部类是否是配置类,使用的方法是 ConfigurationClassUtils.isConfigurationCandidate,这里是检测内部类是否满足lite 的配置类规则,并未校验 full的规则。
  • 代码中使用了this.importStack 来防止递归引入。避免了A引入B,B又引入A这种无限循环的情况。

3.2.2.2 处理 @PropertySource 注解

@PropertySource 注解可以引入配置文件使用。在这里进行 @PropertySource 注解的解析,将引入的配置文件加载到环境变量中:

// 去重后遍历 PropertySource 注解所指向的属性。注意这里有两个注解@PropertySources 和 @PropertySource。
for (AnnotationAttributes propertySource : AnnotationConfigUtils.attributesForRepeatable(
                sourceClass.getMetadata(), PropertySources.class,
                org.springframework.context.annotation.PropertySource.class)) {
        if (this.environment instanceof ConfigurableEnvironment) {
                // 解析PropertySource  注解
                processPropertySource(propertySource);
        }
        else {
                logger.info("Ignoring @PropertySource annotation on [" + sourceClass.getMetadata().getClassName() +
                                "]. Reason: Environment must implement ConfigurableEnvironment");
        }
}

processPropertySource 代码如下,在这里解析每一个@PropertySource 注解属性 :

private void processPropertySource(AnnotationAttributes propertySource) throws IOException {
        // 获取 @PropertySource 注解的各个属性
        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");
        Assert.isTrue(locations.length > 0, "At least one @PropertySource(value) location is required");
        boolean ignoreResourceNotFound = propertySource.getBoolean("ignoreResourceNotFound");

        Class<? extends PropertySourceFactory> factoryClass = propertySource.getClass("factory");
        PropertySourceFactory factory = (factoryClass == PropertySourceFactory.class ?
                        DEFAULT_PROPERTY_SOURCE_FACTORY : BeanUtils.instantiateClass(factoryClass));
        // 遍历文件路径
        for (String location : locations) {
                try {
                        //  根据路径获取到资源文件并保存到environment 中
                        // 解决占位符,获取真正路径
                        String resolvedLocation = this.environment.resolveRequiredPlaceholders(location);
                        Resource resource = this.resourceLoader.getResource(resolvedLocation);
                        //保存 PropertySource 到 environment 中
                        addPropertySource(factory.createPropertySource(name, new EncodedResource(resource, encoding)));
                }
                catch (IllegalArgumentException | FileNotFoundException | UnknownHostException ex) {
                        // Placeholders not resolvable or resource not found when trying to open it
                        if (ignoreResourceNotFound) {
                                if (logger.isInfoEnabled()) {
                                        logger.info("Properties location [" + location + "] not resolvable: " + ex.getMessage());
                                }
                        }
                        else {
                                throw ex;
                        }
                }
        }
}

3.2.2.3 处理 @ComponentScan、@ComponentScans 注解

@componentScans 指定自动扫描的路径。

// 这里会将 @ComponentScans 中的多个 @ComponentScan 也解析出来封装成一个个AnnotationAttributes对象
Set<AnnotationAttributes> componentScans = AnnotationConfigUtils.attributesForRepeatable(
                sourceClass.getMetadata(), ComponentScans.class, ComponentScan.class);
// 如果当前配置类被 @componentScans 或 @componentScan 注解修饰 && 不应跳过
if (!componentScans.isEmpty() &&
                !this.conditionEvaluator.shouldSkip(sourceClass.getMetadata(), ConfigurationPhase.REGISTER_BEAN)) {
                // 遍历 @ComponentScans、 @ComponentScan
        for (AnnotationAttributes componentScan : componentScans) {
                // The config class is annotated with @ComponentScan -> perform the scan immediately
                // 直接执行扫描,根据指定路径扫描出来bean。
                Set<BeanDefinitionHolder> scannedBeanDefinitions =
                                this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName());
                // Check the set of scanned definitions for any further config classes and parse recursively if needed
                // 遍历扫描出来的bean
                for (BeanDefinitionHolder holder : scannedBeanDefinitions) {
                // 获取原始的bean的定义
                        BeanDefinition bdCand = holder.getBeanDefinition().getOriginatingBeanDefinition();
                        if (bdCand == null) {
                                bdCand = holder.getBeanDefinition();
                        }
                        // 检测如果是配置类,则递归调用 parse 解析。
                        if (ConfigurationClassUtils.checkConfigurationClassCandidate(bdCand, this.metadataReaderFactory)) {
                                parse(bdCand.getBeanClassName(), holder.getBeanName());
                        }
                }
        }
}

这里需要注意 :

  • this.componentScanParser.parse 方法完成了指定路径下的bean的扫描。

  • 这里校验是否是配置类调用的是 checkConfigurationClassCandidate 方法,即校验了 full或lite的规则,和 处理 @Component 中的内部类的规则并不相同。

  • 没错,又是递归,如果扫描到的bean中发现了新的配置类,则递归去解析。

3.2.2.4 处理 @Import、ImportSelector、ImportBeanDefinitionRegistrar

  • processImports(configClass, sourceClass, getImports(sourceClass), filter, true); 该方法处理的包括 @Import、ImportSelector、 ImportBeanDefinitionRegistrar。这三个注解或接口都可以完成Bean的引入功能。

    • @Import : 可以通过 @Import(XXX.class) 的方式,将指定的类注册到容器中
    • ImportSelector : Spring会将 ImportSelector#selectImports 方法返回的内容通过反射加载到容器中
    • ImportBeanDefinitionRegistrar : 可以通过 registerBeanDefinitions 方法声明BeanDefinition 并自己注册到Spring容器中 比如 : MyBatis 中的 AutoConfiguredMapperScannerRegistrar@Mapper 修饰类的注册过程。

需要注意的是,这里解析的ImportSelector、ImportBeanDefinitionRegistrar 都是通过 @Import 注解引入的。如果不是通过 @Import 引入(比如直接通过@Component 将ImportSelector、ImportBeanDefinitionRegistrar 注入)的类则不会被解析。

注意 getImports(sourceClass) 方法的作用是解析 @Import 注解。我们直接来看 processImports 方法,注释都比较清楚 :

private void processImports(ConfigurationClass configClass, SourceClass currentSourceClass,
                Collection<SourceClass> importCandidates, Predicate<String> exclusionFilter,
                boolean checkForCircularImports) {
        // importCandidates 是通过getImports() 方法解析 @Import 注解而来, 如果为空则说明没有需要引入的直接返回
        if (importCandidates.isEmpty()) {
                return;
        }
        // 检测是否是循环引用。
        if (checkForCircularImports && isChainedImportOnStack(configClass)) {
                this.problemReporter.error(new CircularImportProblem(configClass, this.importStack));
        }
        else {
                // 解析前先入栈,防止循环引用
                this.importStack.push(configClass);
                try {
                        for (SourceClass candidate : importCandidates) {
                                // 判断是否是ImportSelector类型。ImportSelector 则需要调用selectImports 方法来获取需要注入的类。
                                if (candidate.isAssignable(ImportSelector.class)) {
                                        // Candidate class is an ImportSelector -> delegate to it to determine imports
                                        Class<?> candidateClass = candidate.loadClass();
                                        ImportSelector selector = ParserStrategyUtils.instantiateClass(candidateClass, ImportSelector.class,
                                                        this.environment, this.resourceLoader, this.registry);
                                        Predicate<String> selectorFilter = selector.getExclusionFilter();
                                        if (selectorFilter != null) {
                                                exclusionFilter = exclusionFilter.or(selectorFilter);
                                        }
                                        if (selector instanceof DeferredImportSelector) {
                                                this.deferredImportSelectorHandler.handle(configClass, (DeferredImportSelector) selector);
                                        }
                                        else {
                                        // 调用 selectImports 方法获取需要引入的类,并递归再次处理。
                                                String[] importClassNames = selector.selectImports(currentSourceClass.getMetadata());
                                                Collection<SourceClass> importSourceClasses = asSourceClasses(importClassNames, exclusionFilter);
                                                // 递归解析
                                                processImports(configClass, currentSourceClass, importSourceClasses, exclusionFilter, false);
                                        }
                                }
                                // 如果是 ImportBeanDefinitionRegistrar 类型,则委托它注册其他bean定义
                                else if (candidate.isAssignable(ImportBeanDefinitionRegistrar.class)) {
                                        // Candidate class is an ImportBeanDefinitionRegistrar ->
                                        // delegate to it to register additional bean definitions
                                        Class<?> candidateClass = candidate.loadClass();
                                        ImportBeanDefinitionRegistrar registrar =
                                                        ParserStrategyUtils.instantiateClass(candidateClass, ImportBeanDefinitionRegistrar.class,
                                                                        this.environment, this.resourceLoader, this.registry);
                                        configClass.addImportBeanDefinitionRegistrar(registrar, currentSourceClass.getMetadata());
                                }
                                else {
                                        // Candidate class not an ImportSelector or ImportBeanDefinitionRegistrar ->
                                        // process it as an @Configuration class
                                        this.importStack.registerImport(
                                                        currentSourceClass.getMetadata(), candidate.getMetadata().getClassName());
                                        // 否则递归处理需要引入的类。
                                        processConfigurationClass(candidate.asConfigClass(configClass), exclusionFilter);
                                }
                        }
                }
                catch (BeanDefinitionStoreException ex) {
                        throw ex;
                }
                catch (Throwable ex) {
                        throw new BeanDefinitionStoreException(
                                        "Failed to process import candidates for configuration class [" +
                                        configClass.getMetadata().getClassName() + "]", ex);
                }
                finally {
                        this.importStack.pop();
                }
        }
}

3.2.2.5 处理 @ImportResource 注解

@ImportResource 就显得很简单了,直接保存到 configClass 中

// Process any @ImportResource annotations
        AnnotationAttributes importResource =
                        AnnotationConfigUtils.attributesFor(sourceClass.getMetadata(), ImportResource.class);
        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);
                        configClass.addImportedResource(resolvedResource, readerClass);
                }
        }

3.2.2.6 处理 @Bean修饰的方法

@Bean 也很简单了,直接保存到 configClass 的中

// Process individual @Bean methods
Set<MethodMetadata> beanMethods = retrieveBeanMethodMetadata(sourceClass);
for (MethodMetadata methodMetadata : beanMethods) {
        configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));
}

3.2.2.7 处理接口默认方法

这里是 检测 配置类实现的接口中的默认方法是否被@Bean修饰,如果被修饰则也需要保存到 configClass 中

/**
 * Register default methods on interfaces implemented by the configuration class.
 */
private void processInterfaces(ConfigurationClass configClass, SourceClass sourceClass) throws IOException {
        for (SourceClass ifc : sourceClass.getInterfaces()) {
                Set<MethodMetadata> beanMethods = retrieveBeanMethodMetadata(ifc);
                for (MethodMetadata methodMetadata : beanMethods) {
                        if (!methodMetadata.isAbstract()) {
                                // A default method or other concrete method on a Java 8+ interface...
                                configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));
                        }
                }
                processInterfaces(configClass, ifc);
        }
}

3.2.2.8 处理父类

如果存在父类,则将父类返回,对父类进行解析。

// Process superclass, if any
if (sourceClass.getMetadata().hasSuperClass()) {
        String superclass = sourceClass.getMetadata().getSuperClassName();
        if (superclass != null && !superclass.startsWith("java") &&
                        !this.knownSuperclasses.containsKey(superclass)) {
                this.knownSuperclasses.put(superclass, configClass);
                // Superclass found, return its annotation metadata and recurse
                return sourceClass.getSuperClass();
        }
}

这里这么处理是解析到最上层的父类。这里理一下调用顺序:parse -> processConfigurationClass -> doProcessConfigurationClass 。而 doProcessConfigurationClass 有如下一个循环,只有sourceClass = null 才会跳出循环。当 configClass 没有满足上面判断条件的父类时,才会返回null

SourceClass sourceClass = asSourceClass(configClass, filter);
        do {
                sourceClass = doProcessConfigurationClass(configClass, sourceClass, filter);
        }
        while (sourceClass != null);
this.configurationClasses.put(configClass, configClass);

3.2.3 parser.validate();

到了 这一步,是对解析出来的配置类进行进一步的校验,确保没有问题

这里我们看看其代码如下:

public void validate() {
        for (ConfigurationClass configClass : this.configurationClasses.keySet()) {
                configClass.validate(this.problemReporter);
        }
}

这里可以看到是调用每个 ConfigurationClass 类的 validate 方法进行校验,我们进去看看 ConfigurationClass#validate 的代码 :

public void validate(ProblemReporter problemReporter) {
        // A configuration class may not be final (CGLIB limitation) unless it declares proxyBeanMethods=false
        // 获取 @Configuration 注解的属性信心
        Map<String, Object> attributes = this.metadata.getAnnotationAttributes(Configuration.class.getName());
        // 如果 @Configuration 存在(attributes != null)  && attributes.get("proxyBeanMethods") == true 才进行进一步的校验
        if (attributes != null && (Boolean) attributes.get("proxyBeanMethods")) {
                // 如果配置类 是  final 修饰,即终态类,则是错误,因为无法动态代理
                if (this.metadata.isFinal()) {
                        problemReporter.error(new FinalConfigurationProblem());
                }
                // 对配置类中的 @Bean 注解修饰的方法进行校验
                for (BeanMethod beanMethod : this.beanMethods) {
                        beanMethod.validate(problemReporter);
                }
        }
}

这里我们再来看看 @Bean方法的校验 BeanMethod#validate如下:

@Override
public void validate(ProblemReporter problemReporter) {
        // 如果是静态方法没有约束规则,直接返回。
        if (getMetadata().isStatic()) {
                // static @Bean methods have no constraints to validate -> return immediately
                return;
        }
        // 校验该方法所属的类是否被 @Configuration 修饰。
        if (this.configurationClass.getMetadata().isAnnotated(Configuration.class.getName())) {
                // 判断是否可重写。cglib代理需要方法可重写。不可重写则错误
                if (!getMetadata().isOverridable()) {
                        // instance @Bean methods within @Configuration classes must be overridable to accommodate CGLIB
                        problemReporter.error(new NonOverridableMethodError());
                }
        }
}

3.2.4 this.reader.loadBeanDefinitions(configClasses);

上面也说了,在parser.parse(candidates); 方法中,将各种注解的属性值都解析了出来,并保存到了 configClass的各种属性中。而在 this.reader.loadBeanDefinitions(configClasses); 中才真正处理了这些属性。所以我们接下来看看loadBeanDefinitions 的处理流程。

loadBeanDefinitions 遍历了每一个ConfigurationClass ,通过loadBeanDefinitionsForConfigurationClass 方法处理。

public void loadBeanDefinitions(Set<ConfigurationClass> configurationModel) {
        TrackedConditionEvaluator trackedConditionEvaluator = new TrackedConditionEvaluator();
        for (ConfigurationClass configClass : configurationModel) {
                loadBeanDefinitionsForConfigurationClass(configClass, trackedConditionEvaluator);
        }
}

所以我们来看看 loadBeanDefinitionsForConfigurationClass 的实现。 可很清楚的看到,每个部分的解析都封装到了不同的方法中。

private void loadBeanDefinitionsForConfigurationClass(
                ConfigurationClass configClass, TrackedConditionEvaluator trackedConditionEvaluator) {
        // 判断是否应该跳过
        if (trackedConditionEvaluator.shouldSkip(configClass)) {
                String beanName = configClass.getBeanName();
                if (StringUtils.hasLength(beanName) && this.registry.containsBeanDefinition(beanName)) {
                        this.registry.removeBeanDefinition(beanName);
                }
                this.importRegistry.removeImportingClass(configClass.getMetadata().getClassName());
                return;
        }
        // 1. 如果配置是被引入的(被 @Import 或者其他配置类内部引入)
        if (configClass.isImported()) {
                registerBeanDefinitionForImportedConfigurationClass(configClass);
        }
        // 2. 遍历配置类中的所有 BeanMethod方法
        for (BeanMethod beanMethod : configClass.getBeanMethods()) {
                loadBeanDefinitionsForBeanMethod(beanMethod);
        }
        // 3. 加载 通过 @ImportResource 的 获取的bean
        loadBeanDefinitionsFromImportedResources(configClass.getImportedResources());
        // 4. 加载 通过 @Import 的 获取的bean
        loadBeanDefinitionsFromRegistrars(configClass.getImportBeanDefinitionRegistrars());
}

下面 我们来详细看看每个方法。

3.2.4.1 registerBeanDefinitionForImportedConfigurationClass

这一步的工作很简单,就是将引入的配置类注册为 BeanDefinition。

private void registerBeanDefinitionForImportedConfigurationClass(ConfigurationClass configClass) {
        AnnotationMetadata metadata = configClass.getMetadata();
        AnnotatedGenericBeanDefinition configBeanDef = new AnnotatedGenericBeanDefinition(metadata);

        ScopeMetadata scopeMetadata = scopeMetadataResolver.resolveScopeMetadata(configBeanDef);
        configBeanDef.setScope(scopeMetadata.getScopeName());
        String configBeanName = this.importBeanNameGenerator.generateBeanName(configBeanDef, this.registry);
        AnnotationConfigUtils.processCommonDefinitionAnnotations(configBeanDef, metadata);

        BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(configBeanDef, configBeanName);
        // 创建代理,根据 scopeMetadata 的代理模式。默认不创建代理。
        definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
        // 注册了BeanBeanDefinition 。这里将BeanDefinition保存到了 DefaultListableBeanFactory#beanDefinitionMap 中
        this.registry.registerBeanDefinition(definitionHolder.getBeanName(), definitionHolder.getBeanDefinition());
        configClass.setBeanName(configBeanName);

        if (logger.isTraceEnabled()) {
                logger.trace("Registered bean definition for imported class '" + configBeanName + "'");
        }
}

这里需要注意的是 AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry); 根据scopeMetadata 的代理模式创建了代理。代理模式有四种,分别为

  • DEFAULT : 默认模式。默认等同于NO -NO: 不使用代理
  • INTERFACES : Jdk 动态代理
  • TARGET_CLASS : Cglib代理

applyScopedProxyMode 方法中 通过获取ScopeMetadata.getScopedProxyMode() 来判断使用什么代理方式。而ScopeMetadata 的代理方式 是在创建 scopeMetadata 的过程中,获取类上面的@ScopeproxyMode 属性来指定的。

ScopeMetadata scopeMetadata =  scopeMetadataResolver.resolveScopeMetadata(configBeanDef);

resolveScopeMetadata 方法如下

protected Class<? extends Annotation> scopeAnnotationType = Scope.class;
@Override
public ScopeMetadata resolveScopeMetadata(BeanDefinition definition) {
        ScopeMetadata metadata = new ScopeMetadata();
        if (definition instanceof AnnotatedBeanDefinition) {
                AnnotatedBeanDefinition annDef = (AnnotatedBeanDefinition) definition;
                // 获取 @Scope 注解
                AnnotationAttributes attributes = AnnotationConfigUtils.attributesFor(
                                annDef.getMetadata(), this.scopeAnnotationType);
                if (attributes != null) {

                        metadata.setScopeName(attributes.getString("value"));
                        // 获取 @Scope 的proxyMode属性
                        ScopedProxyMode proxyMode = attributes.getEnum("proxyMode");
                        if (proxyMode == ScopedProxyMode.DEFAULT) {
                                proxyMode = this.defaultProxyMode;
                        }
                        // 设置 scopedProxyMode 属性,后面根据此属性判断使用什么代理方式
                        metadata.setScopedProxyMode(proxyMode);
                }
        }
        return metadata;
}

3.2.4.2 loadBeanDefinitionsForBeanMethod

具体代码如下,基本上就是解析各种注解,创建对应的 BeanDefinition 并注册。

private void loadBeanDefinitionsForBeanMethod(BeanMethod beanMethod) {
        ConfigurationClass configClass = beanMethod.getConfigurationClass();
        MethodMetadata metadata = beanMethod.getMetadata();
        String methodName = metadata.getMethodName();

        // Do we need to mark the bean as skipped by its condition?
        // 是否应该跳过
        if (this.conditionEvaluator.shouldSkip(metadata, ConfigurationPhase.REGISTER_BEAN)) {
                configClass.skippedBeanMethods.add(methodName);
                return;
        }
        if (configClass.skippedBeanMethods.contains(methodName)) {
                return;
        }
        // 获取被 @Bean修饰的方法
        AnnotationAttributes bean = AnnotationConfigUtils.attributesFor(metadata, Bean.class);
        Assert.state(bean != null, "No @Bean annotation attributes");

        // Consider name and any aliases
        // 获取别名
        List<String> names = new ArrayList<>(Arrays.asList(bean.getStringArray("name")));
        String beanName = (!names.isEmpty() ? names.remove(0) : methodName);

        // Register aliases even when overridden
        // 注册别名
        for (String alias : names) {
                this.registry.registerAlias(beanName, alias);
        }

        // Has this effectively been overridden before (e.g. via XML)?
        // 判断是否已经被定义过
        if (isOverriddenByExistingDefinition(beanMethod, beanName)) {
                if (beanName.equals(beanMethod.getConfigurationClass().getBeanName())) {
                        throw new BeanDefinitionStoreException(beanMethod.getConfigurationClass().getResource().getDescription(),
                                        beanName, "Bean name derived from @Bean method '" + beanMethod.getMetadata().getMethodName() +
                                        "' clashes with bean name for containing configuration class; please make those names unique!");
                }
                return;
        }
        // 定义配置类的  BeanDefinition
        ConfigurationClassBeanDefinition beanDef = new ConfigurationClassBeanDefinition(configClass, metadata);
        beanDef.setResource(configClass.getResource());
        beanDef.setSource(this.sourceExtractor.extractSource(metadata, configClass.getResource()));
        // 处理静态 @Bean 方法和 非静态 @Bean 方法
        if (metadata.isStatic()) {
                // static @Bean method
                if (configClass.getMetadata() instanceof StandardAnnotationMetadata) {
                        beanDef.setBeanClass(((StandardAnnotationMetadata) configClass.getMetadata()).getIntrospectedClass());
                }
                else {
                        beanDef.setBeanClassName(configClass.getMetadata().getClassName());
                }
                // 设置唯一工厂方法名称
                beanDef.setUniqueFactoryMethodName(methodName);
        }
        else {
                // instance @Bean method
                // 指定要使用的工厂bean(如果有)。这是用于调用指定工厂方法的bean的名称
                beanDef.setFactoryBeanName(configClass.getBeanName());
                // 设置唯一工厂方法名称,内部调用了 setFactoryMethodName(name); 保存 FactoryMethodName
                beanDef.setUniqueFactoryMethodName(methodName);
        }

        if (metadata instanceof StandardMethodMetadata) {
                beanDef.setResolvedFactoryMethod(((StandardMethodMetadata) metadata).getIntrospectedMethod());
        }
        // 设置构造模式 构造注入
        beanDef.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_CONSTRUCTOR);
        // 设置跳过属性检查
        beanDef.setAttribute(org.springframework.beans.factory.annotation.RequiredAnnotationBeanPostProcessor.
                        SKIP_REQUIRED_CHECK_ATTRIBUTE, Boolean.TRUE);
        // 处理通用的注解: @Lazy、@Primary、@DependsOn、@Role、@Description。设置到 BeanDefinition 中
        AnnotationConfigUtils.processCommonDefinitionAnnotations(beanDef, metadata);
        // 获取注解的其他属性并设置到 BeanDefinition
        Autowire autowire = bean.getEnum("autowire");
        if (autowire.isAutowire()) {
                beanDef.setAutowireMode(autowire.value());
        }

        boolean autowireCandidate = bean.getBoolean("autowireCandidate");
        if (!autowireCandidate) {
                beanDef.setAutowireCandidate(false);
        }

        String initMethodName = bean.getString("initMethod");
        if (StringUtils.hasText(initMethodName)) {
                beanDef.setInitMethodName(initMethodName);
        }

        String destroyMethodName = bean.getString("destroyMethod");
        beanDef.setDestroyMethodName(destroyMethodName);

        // Consider scoping
        ScopedProxyMode proxyMode = ScopedProxyMode.NO;
        // 处理方法上的 @Scope 注解
        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;
                }
        }

        // Replace the original bean definition with the target one, if necessary
        // 如果有必要(代理模式不同),替换掉旧的BeanDefinition
        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);
        }

        if (logger.isTraceEnabled()) {
                logger.trace(String.format("Registering bean definition for @Bean method %s.%s()",
                                configClass.getMetadata().getClassName(), beanName));
        }
        // 注册BeanDefinition
        this.registry.registerBeanDefinition(beanName, beanDefToRegister);
}

这里特意提一下下面几句的功能

// 设置引入该bean 的配置类的类名
beanDef.setFactoryBeanName(configClass.getBeanName());
// 设置 引入bean 的类名
beanDef.setBeanClassName(configClass.getMetadata().getClassName());
// 设置在配置类中引入该bean 的方法名
beanDef.setUniqueFactoryMethodName(methodName);

这里会为 @Bean修饰的方法创建出一个 ConfigurationClassBeanDefinition注册到 Spring容器中,ConfigurationClassBeanDefinition特指用于表示从配置类(而不是其他任何配置源)创建了Bean定义。在需要确定是否在外部创建bean定义的bean覆盖情况下使用。在后面的Bean实例化过程中,会有多次使用。比如在 AbstractAutowireCapableBeanFactory#resolveBeforeInstantiation

        // 在 determineTargetType 方法中根据  factoryMethodName 是否为空,判断bean注入方式,来获取注入的 Class类型
        Class<?> targetType = determineTargetType(beanName, mbd);

以及会在 AbstractAutowireCapableBeanFactory#createBeanInstance 方法中有如下两句。

        if (mbd.getFactoryMethodName() != null) {
                return instantiateUsingFactoryMethod(beanName, mbd, args);
        }

@Bean的修饰的方法会调用instantiateUsingFactoryMethod 方法,通过反射调用方法,并将反射结果注入到Spring容器中,完成 @Bean注解的功能。

3.2.4.3 loadBeanDefinitionsFromImportedResources

loadBeanDefinitionsFromImportedResources 从导入的资源加载Bean定义。即通过解析 @ImportResource 注解引入的资源文件,获取到BeanDefinition 并注册。

private void loadBeanDefinitionsFromImportedResources(
			Map<String, Class<? extends BeanDefinitionReader>> importedResources) {

        Map<Class<?>, BeanDefinitionReader> readerInstanceCache = new HashMap<>();
        // 遍历引入的资源文件
        importedResources.forEach((resource, readerClass) -> {
                // Default reader selection necessary?
                if (BeanDefinitionReader.class == readerClass) {
                        // 处理 .groovy 类型文件
                        if (StringUtils.endsWithIgnoreCase(resource, ".groovy")) {
                                // When clearly asking for Groovy, that's what they'll get...
                                readerClass = GroovyBeanDefinitionReader.class;
                        }
                        else {
                                // Primarily ".xml" files but for any other extension as well
                                // 这里使用 XmlBeanDefinitionReader 类型来解析
                                readerClass = XmlBeanDefinitionReader.class;
                        }
                }
                // 从缓冲中获取
                BeanDefinitionReader reader = readerInstanceCache.get(readerClass);
                // 如果缓存中没有,则创建一个 reader 用于 resource 的解析。
                if (reader == null) {
                        try {
                                // Instantiate the specified BeanDefinitionReader
                                reader = readerClass.getConstructor(BeanDefinitionRegistry.class).newInstance(this.registry);
                                // Delegate the current ResourceLoader to it if possible
                                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(
                                                "Could not instantiate BeanDefinitionReader class [" + readerClass.getName() + "]");
                        }
                }

                // TODO SPR-6310: qualify relative path locations as done in AbstractContextLoader.modifyLocations
                // 解析resource资源中的内容
                reader.loadBeanDefinitions(resource);
        });
}

3.2.4.4 loadBeanDefinitionsFromRegistrars

loadBeanDefinitionsFromRegistrars 方法注册了了@Import 注解引入的内容。这里很简单,将@Import 引入的内容注入到容器中。

private void loadBeanDefinitionsFromRegistrars(Map<ImportBeanDefinitionRegistrar, AnnotationMetadata> registrars) {
        registrars.forEach((registrar, metadata) ->
                        registrar.registerBeanDefinitions(metadata, this.registry, this.importBeanNameGenerator));
}

3.2 总结

从目前我看到的来说(虽然也没看过几个),有两个后处理器非常重要:

  • ConfigurationClassPostProcessor : 即本文解析的这个后处理器。虽然仅仅是上篇,但是其作用已经非常清楚了。ConfigurationClassPostProcessor 解析配置类(这里的配置类不仅仅局限于@Configuration 注解,还包括 @Import、 @ImportResource 等注解),将解析到的需要注入到Spring容器中的bean的BeanDefinition保存起来。在后面的bean 初始化都需要BeanDefinition。

  • AutowiredAnnotationBeanPostProcessor : 完成了 Bean所依赖的属性的注入。 解析bean中的 需要自动注入的bean @Autowired 和 @Inject @Value注解。后面具体分析

简单来说 ConfigurationClassPostProcessor 完成了 Bean的扫描与解析, AutowiredAnnotationBeanPostProcessor 完成了Bean 属性的注入。

3.3 postProcessBeanFactory 方法

本小节需要分析 ConfigurationClassPostProcessor#postProcessBeanFactory 方法通过cglib代理配置类,来拦截 @Bean修饰的方法。这么做的目的是为了在配置类中多次调用 @Bean 方法返回的是同一个结果。即在下面的代码中 demoController() 和 demoController2() 方法中调用的demoService() 方法返回的结果是同一个值。避免了单例模式下的多例创建。我们可以通过下面一个例子来看一看

3.3.1 案例

@Configuration
public class DemoConfig {
    @Bean
    public DemoService demoService(){
        return new DemoServiceImpl();
    }
    @Bean
    public DemoController demoController(){
        System.out.println("demoController : " +  demoService());
        return new DemoController();
    }
    @Bean("demoController2")
    public DemoController demoController2(){
        System.out.println("demoController2222 : " +  demoService());
        return new DemoController();
    }
}

Spring5源码10-注解版配置文件解析(上) 上面的代码输出结果是什么?

我们看到两个方法里调用 demoService() 方法返回的是同一个实例,但是按照我们传统的逻辑,这里调用 demoService() 应该是重新创建了 一个 DemoServiceImpl 实例,应该不一样的。这里就是因为ConfigurationClassPostProcessor#postProcessBeanFactory 方法通过代理实现了该效果,以保证正确语义。

如果使用 @Component 注解修饰 DemoConfig 。则两次 demoService() 方法返回的结果则不相同。因为被 @Component 注解修饰的bean并不会调用 ConfigurationClassPostProcessor#postProcessBeanFactory 方法来进行方法代理。

具体原因,即使因为在 postProcessBeanFactory 方法中对 Full 类型(即被 @Configuration 修饰的配置类)的配置类进行了动态代理

postProcessBeanFactory 方法代码如下(相较于 postProcessBeanDefinitionRegistry 方法真是简单太多了):

@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
        int factoryId = System.identityHashCode(beanFactory);
        // 判断是否已经在处理
        if (this.factoriesPostProcessed.contains(factoryId)) {
                throw new IllegalStateException(
                                "postProcessBeanFactory already called on this post-processor against " + beanFactory);
        }
        this.factoriesPostProcessed.add(factoryId);
        if (!this.registriesPostProcessed.contains(factoryId)) {
                // BeanDefinitionRegistryPostProcessor hook apparently not supported...
                // Simply call processConfigurationClasses lazily at this point then.
                processConfigBeanDefinitions((BeanDefinitionRegistry) beanFactory);
        }

        enhanceConfigurationClasses(beanFactory);
        beanFactory.addBeanPostProcessor(new ImportAwareBeanPostProcessor(beanFactory));
}

可以看到关键代码为 enhanceConfigurationClasses(beanFactory);。下面开始就来看看enhanceConfigurationClasses 方法

3.3.2 enhanceConfigurationClasses

enhanceConfigurationClasses 方法用于增强配置类。Spring会对 Full Configuration (即被 @Configuration 修饰的配置类)进行代理,拦截@Bean方法以确保正确处理@Bean语义。这个增强的代理类就是在enhanceConfigurationClasses(beanFactory)方法中产生的。

由于篇幅所限,这里等后续有机会再详细解析。这一部分的解析可以参考 : segmentfault.com/a/119000002…

public void enhanceConfigurationClasses(ConfigurableListableBeanFactory beanFactory) {
    Map<String, AbstractBeanDefinition> configBeanDefs = new LinkedHashMap<>();
    for (String beanName : beanFactory.getBeanDefinitionNames()) {
            BeanDefinition beanDef = beanFactory.getBeanDefinition(beanName);
            // 获取 CONFIGURATION_CLASS_ATTRIBUTE属性,如果不为null,则是配置类,在上篇中有过交代(可能是full或者lite类型)
            Object configClassAttr = beanDef.getAttribute(ConfigurationClassUtils.CONFIGURATION_CLASS_ATTRIBUTE);
            MethodMetadata methodMetadata = null;
            if (beanDef instanceof AnnotatedBeanDefinition) {
                    methodMetadata = ((AnnotatedBeanDefinition) beanDef).getFactoryMethodMetadata();
            }
            // 如果是配置类(configClassAttr  != null) || @Bean注解派生的方法(methodMetadata != null 不为空表示 FactoryMethod不为空,则可以说明是 @Bean 生成的 BeanDefinition)
            if ((configClassAttr != null || methodMetadata != null) && beanDef instanceof AbstractBeanDefinition) {
                    // Configuration class (full or lite) or a configuration-derived @Bean method
                    // -> resolve bean class at this point...
                    AbstractBeanDefinition abd = (AbstractBeanDefinition) beanDef;
                    // 这里判断如果指定的 bean(注意并非这里的abd,而是abd所要生成的bean) 如果不是 Class类型则进入 if里面
                    if (!abd.hasBeanClass()) {
                            try {
                                    // 解析 beanClass,即获取这个 Bean 的Class 并保存到 abd中
                                    abd.resolveBeanClass(this.beanClassLoader);
                            }
                            catch (Throwable ex) {
                                    throw new IllegalStateException(
                                                    "Cannot load configuration class: " + beanDef.getBeanClassName(), ex);
                            }
                    }
            }
            // 对 FUll的 配置类进行处理!!!
            if (ConfigurationClassUtils.CONFIGURATION_CLASS_FULL.equals(configClassAttr)) {
                    // 对非AbstractBeanDefinition子类的情况直接抛出异常
                    if (!(beanDef instanceof AbstractBeanDefinition)) {
                            throw new BeanDefinitionStoreException("Cannot enhance @Configuration bean definition '" +
                                            beanName + "' since it is not stored in an AbstractBeanDefinition subclass");
                    }
                    else if (logger.isInfoEnabled() && beanFactory.containsSingleton(beanName)) {
                            logger.info("Cannot enhance @Configuration bean definition '" + beanName +
                                            "' since its singleton instance has been created too early. The typical cause " +
                                            "is a non-static @Bean method with a BeanDefinitionRegistryPostProcessor " +
                                            "return type: Consider declaring such methods as 'static'.");
                    }
                    // 保存下来,准备代理
                    configBeanDefs.put(beanName, (AbstractBeanDefinition) beanDef);
            }
    }
    // 如果没有找到 full 配置类,则说明不需要代理增强,则直接返回。
    if (configBeanDefs.isEmpty()) {
            // nothing to enhance -> return immediately
            return;
    }
    // 创建增强对象
    ConfigurationClassEnhancer enhancer = new ConfigurationClassEnhancer();
    // 进行配置类增强。这里的增强实际上是通过cglib对配置类进行了代理。
    for (Map.Entry<String, AbstractBeanDefinition> entry : configBeanDefs.entrySet()) {
            AbstractBeanDefinition beanDef = entry.getValue();
            // If a @Configuration class gets proxied, always proxy the target class
            // 设置 :如果配置类被代理,则该 bean也需要一直代理
            beanDef.setAttribute(AutoProxyUtils.PRESERVE_TARGET_CLASS_ATTRIBUTE, Boolean.TRUE);
            // Set enhanced subclass of the user-specified bean class
            // 获取bean的 Class 类
            Class<?> configClass = beanDef.getBeanClass();
            // 生成代理类
            Class<?> enhancedClass = enhancer.enhance(configClass, this.beanClassLoader);
            if (configClass != enhancedClass) {
                    if (logger.isTraceEnabled()) {
                            logger.trace(String.format("Replacing bean definition '%s' existing class '%s' with " +
                                            "enhanced class '%s'", entry.getKey(), configClass.getName(), enhancedClass.getName()));
                    }
                     //将BeanClass设置为增强后的类
                    beanDef.setBeanClass(enhancedClass);
            }
    }
}

我们可以看到关键代码在于

Class<?> enhancedClass = enhancer.enhance(configClass, this.beanClassLoader);

首先我们来看

// 加载指定的类并为其生成一个CGLIB子类,该子类配备了能够识别作用域和其他bean语义的容器感知回调。
public Class<?> enhance(Class<?> configClass, @Nullable ClassLoader classLoader) {
        // 如果是 EnhancedConfiguration子类,则说明已经被增强(代理),直接返回
        if (EnhancedConfiguration.class.isAssignableFrom(configClass)) {
                ... 忽略日志打印
                return configClass;
        }
        // 创建代理类
        Class<?> enhancedClass = createClass(newEnhancer(configClass, classLoader));
        if (logger.isTraceEnabled()) {
                logger.trace(String.format("Successfully enhanced %s; enhanced class name is: %s",
                                configClass.getName(), enhancedClass.getName()));
        }
        return enhancedClass;
}

接下来我们需要看 Class<?> enhancedClass = createClass(newEnhancer(configClass, classLoader));。我们先来看其中的 newEnhancer(configClass, classLoader) 方法

3.3.2.1 newEnhancer(configClass, classLoader)

动态代理参考segmentfault.com/a/119000002… 回调过滤器部分: blog.csdn.net/iteye_13303…

这里创建了一个 Cglib 代理的实例:

private static final ConditionalCallbackFilter CALLBACK_FILTER = new ConditionalCallbackFilter(CALLBACKS);

private Enhancer newEnhancer(Class<?> configSuperClass, @Nullable ClassLoader classLoader) {
    // Spring重新打包了CGLIB(使用Spring专用补丁;仅供内部使用)
    // 这样可避免在应用程序级别或第三方库和框架上与CGLIB的依赖性发生任何潜在冲突
    // https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/cglib/package-summary.html
    Enhancer enhancer = new Enhancer();
    enhancer.setSuperclass(configSuperClass);
    // 设置需要实现的接口,也就是说,我们的配置类的cglib代理还实现的 EnhancedConfiguration 接口
    enhancer.setInterfaces(new Class<?>[]{EnhancedConfiguration.class});
    enhancer.setUseFactory(false);
    // 设置命名策略
    enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE);
    // 设置生成器创建字节码策略
    // BeanFactoryAwareGeneratorStrategy 是 CGLIB的DefaultGeneratorStrategy的自定义扩展,主要为了引入BeanFactory字段
    enhancer.setStrategy(new BeanFactoryAwareGeneratorStrategy(classLoader));
    // 设置回调过滤器。通过其,可以设置对不同方法执行不同的回调逻辑,或者根本不执行回调。
    enhancer.setCallbackFilter(CALLBACK_FILTER);
    enhancer.setCallbackTypes(CALLBACK_FILTER.getCallbackTypes());
    return enhancer;
}

这里的Enhancer对象是org.springframework.cglib.proxy.Enhancer,那它和cglib是什么关系呢? 大致就是说,Spring重新打包了CGLIB(使用Spring专用补丁,仅供内部使用) ,这样可避免在应用程序级别或第三方库和框架上与CGLIB的依赖性发生任何潜在冲突。

那具体做了哪些增强呢?

  • 实现EnhancedConfiguration接口。这是一个空的标志接口,仅由Spring框架内部使用,并且由所有@Configuration CGLIB子类实现,该接口继承了BeanFactoryAware接口。
  • 设置了命名策略
  • 设置生成器创建字节码的策略。BeanFactoryAwareGeneratorStrategy继承了cglib的DefaultGeneratorStrategy,其主要作用是为了让子类引入BeanFactory字段和设置ClassLoader。
  • 设置增强Callback:

3.3.2.2 createClass(newEnhancer(configClass, classLoader));

这里是真正创建了一个代理对象了。

private Class<?> createClass(Enhancer enhancer) {
        Class<?> subclass = enhancer.createClass();
        // Registering callbacks statically (as opposed to thread-local)
        // is critical for usage in an OSGi environment (SPR-5932)...
        // 指定代理回调 为 CALLBACKS
        Enhancer.registerStaticCallbacks(subclass, CALLBACKS);
        return subclass;
}

Enhancer.registerStaticCallbacks(subclass, CALLBACKS); 调用了 setCallbacksHelper 方法。

private static void setCallbacksHelper(Class type, Callback[] callbacks, String methodName) {
        // TODO: optimize
        try {
                // 反射调用方法,并将回调函数传入。
                Method setter = getCallbacksSetter(type, methodName);
                setter.invoke(null, new Object[]{callbacks});
        }
        catch (NoSuchMethodException e) {
                throw new IllegalArgumentException(type + " is not an enhanced class");
        }
        catch (IllegalAccessException e) {
                throw new CodeGenerationException(e);
        }
        catch (InvocationTargetException e) {
                throw new CodeGenerationException(e);
        }
}

这里我们可以知道,这里创建了一个 @Bean 生成的 对象 的增强代理,同时通过 ConditionalCallbackFilter 的回调过滤器和指定的回调函数CALLBACKS,完成了增强的过程。

但是对于我们,我们还需要看一下回调函数 CALLBACKS中完成了什么操作。

3.3.3 回调函数

CALLBACKS 定义如下。

private static final Callback[] CALLBACKS = new Callback[] {
        // 拦截@Bean方法的调用,以确保正确处理@Bean语义
        new BeanMethodInterceptor(),
        // BeanFactoryAware#setBeanFactory的调用,用于获取BeanFactory对象
        new BeanFactoryAwareMethodInterceptor(),
        NoOp.INSTANCE
};

下面我们来看看两个拦截器的拦截方法

3.3.3.1 BeanMethodInterceptor#intercept

public Object intercept(Object enhancedConfigInstance, Method beanMethod, Object[] beanMethodArgs,
                        MethodProxy cglibMethodProxy) throws Throwable {
        // 获取beanFactory
        ConfigurableBeanFactory beanFactory = getBeanFactory(enhancedConfigInstance);
        // 根据从配置类中的方法获取beanName
        String beanName = BeanAnnotationHelper.determineBeanNameFor(beanMethod);

        // Determine whether this bean is a scoped-proxy
        // 确定此bean是否为作用域代理。即判断是否包含 @Scope注解,并且其属性 proxyMode 不为  ScopedProxyMode.NO。
        if (BeanAnnotationHelper.isScopedProxy(beanMethod)) {
                String scopedBeanName = ScopedProxyCreator.getTargetBeanName(beanName);
                if (beanFactory.isCurrentlyInCreation(scopedBeanName)) {
                        beanName = scopedBeanName;
                }
        }
        // 官方注释 : 要处理Bean间方法引用,我们必须显式检查容器中是否已缓存实例。首先,检查所请求的bean是否为FactoryBean。
        //如果是这样,则创建一个子类代理,以拦截对getObject()的调用并返回所有缓存的Bean实例。
        //这样可以确保从@Bean方法中调用FactoryBean的语义与在XML中引用FactoryBean的语义相同

        // 判断当前BeanFactory 中是否 存在当前bean的FactoryBean实例 && 包含bean实例 。说白了就是检查容器中是否已经存在该bean 的缓存实例,如果存在需要进行代理
        if (factoryContainsBean(beanFactory, BeanFactory.FACTORY_BEAN_PREFIX + beanName) &&
                        factoryContainsBean(beanFactory, beanName)) {
                // 获取bean对应 FactoryBean 实例。对FactoryBean进行代理
                Object factoryBean = beanFactory.getBean(BeanFactory.FACTORY_BEAN_PREFIX + beanName);
                if (factoryBean instanceof ScopedProxyFactoryBean) {
                        // Scoped proxy factory beans are a special case and should not be further proxied
                        //范围限定的代理工厂bean是一种特殊情况,不应进一步进行代理
                }
                else {
                        // It is a candidate FactoryBean - go ahead with enhancement
                        // 它是候选FactoryBean-继续进行增强
                        return enhanceFactoryBean(factoryBean, beanMethod.getReturnType(), beanFactory, beanName);
                }
        }
        // 这里是我们一般的逻辑,
        // isCurrentlyInvokedFactoryMethod 判断的是,是否是Spring容器自己调用@Bean 方法而并非我们自己编写代码调用。如果是Spring直接调用真正的@Bean方法,这时候多次调用返回的并非同一实例
        if (isCurrentlyInvokedFactoryMethod(beanMethod)) {
                // 工厂正在调用bean方法以便实例化和注册bean(即通过getBean()调用)->调用该方法的超级实现以实际创建bean实例。
                // 这里调用的就是未被增强的 @Bean 方法
                return cglibMethodProxy.invokeSuper(enhancedConfigInstance, beanMethodArgs);
        }
        // 返回cglib 代理后的实例。如果没有创建则创建
        return resolveBeanReference(beanMethod, beanMethodArgs, beanFactory, beanName);
}
3.3.3.1.1 enhanceFactoryBean

该方法是对 FactoryBean 进行动态代理。

这里注意:对于 FactoryBean 的类型的处理,首先判断了类或者getObject 方法是否是终态(被final 修饰),因为cglib 代理是通过继承代理类来实现的代理,所以这里如果是终态则无法代理。如果方法返回类型是接口,则说明是多态,可以使用实现接口的方式来进行代理。也就说在这个方法里面根据是否@Bean 方法是否是接口方法来选择使用 Cglib代理和 Jdk动态代理两种方式

关于 FactoryBean 的介绍,参考

private Object enhanceFactoryBean(final Object factoryBean, Class<?> exposedType,
                final ConfigurableBeanFactory beanFactory, final String beanName) {

        try {
                Class<?> clazz = factoryBean.getClass();
                boolean finalClass = Modifier.isFinal(clazz.getModifiers());
                boolean finalMethod = Modifier.isFinal(clazz.getMethod("getObject").getModifiers());
                // 判断,如果类是 final修饰 ||  getObject 方法被final 修饰
                // 因为 cglib 代理是通过创建一个类继承代理类实现,所以这里如果被final修饰就要另谋处理
                if (finalClass || finalMethod) {
                        // 如果方法的返回类型是接口,则说明使用了多态
                        // 则可以创建一个接口的实现类来代理FactoryBean
                        if (exposedType.isInterface()) {

                                return createInterfaceProxyForFactoryBean(factoryBean, exposedType, beanFactory, beanName);
                        }
                        else {
                                // 如果不是,则没办法进行代理,直接返回FactoryBean。
                                return factoryBean;
                        }
                }
        }
        catch (NoSuchMethodException ex) {
                // No getObject() method -> shouldn't happen, but as long as nobody is trying to call it...
        }
        // 直接进行代理
        return createCglibProxyForFactoryBean(factoryBean, beanFactory, beanName);
}

...
// 创建 JDK动态代理
private Object createInterfaceProxyForFactoryBean(final Object factoryBean, Class<?> interfaceType,
                final ConfigurableBeanFactory beanFactory, final String beanName) {
        // 可以看到,实际上代理的是 FactoryBean 的 getObject 方法
        return Proxy.newProxyInstance(
                        factoryBean.getClass().getClassLoader(), new Class<?>[] {interfaceType},
                        (proxy, method, args) -> {
                                if (method.getName().equals("getObject") && args == null) {
                                        return beanFactory.getBean(beanName);
                                }
                                return ReflectionUtils.invokeMethod(method, factoryBean, args);
                        });
}

3.3.3.2 BeanFactoryAwareMethodInterceptor#intercept

BeanFactoryAwareMethodInterceptor#intercept 代码很简单,如下

@Override
@Nullable
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
        // 获取 obj中的 “$$beanFactory” 属性(BEAN_FACTORY_FIELD 即为 "$$beanFactory")
        Field field = ReflectionUtils.findField(obj.getClass(), BEAN_FACTORY_FIELD);
        Assert.state(field != null, "Unable to find generated BeanFactory field");
        // 将参数 arg[0] 设置给 Obj 的 "$$beanFactory" 属性
        field.set(obj, args[0]);

        // Does the actual (non-CGLIB) superclass implement BeanFactoryAware?
        // If so, call its setBeanFactory() method. If not, just exit.
        if (BeanFactoryAware.class.isAssignableFrom(ClassUtils.getUserClass(obj.getClass().getSuperclass()))) {
                return proxy.invokeSuper(obj, args);
        }
        return null;
}

3.3.4 总结

@Bean@Component 中 是多例的原因?

  • 因为 ConfigurationClassPostProcessor 方法中 只对 full 类型的配置类(即被 @Configuration 注解修饰)进行了代理,因此被 @Component 修饰的类并不会被代理,自然也就不会保持单例

  • ConfigurationClassPostProcessor#postProcessBeanFactory 方法完成了对 full 类型的配置类(即被 @Configuration 注解修饰)进行了代理 保证了语义的正确性。

参考文章

Spring5源码注释github地址 Spring源码深度解析(第2版) spring源码解析 Spring源码深度解析笔记 Spring注解与源码分析 Spring注解驱动开发B站教程

转载自:https://juejin.cn/post/7135414891627675661
评论
请登录