spring--6--spring之ConfigurationClassPostProcessor源码

spring之ConfigurationClassPostProcessor源码解析

文章目录

  • spring之`ConfigurationClassPostProcessor`源码解析
    • 1 用途
    • 2 `postProcessBeanDefinitionRegistry`
      • 2.1 检查`beanDef`是否是一个配置类(`full`或`lite`)
        • 2.1.1判断`BeanDefinition`对应的类是否已经被加载
        • 2.1.2使用`metadataReaderFactory`获取对应类的`MetadataReader`,然后得到`AnnotationMetadata`
        • 2.1.3检测当前类中是否包含其他配置注解
        • 2.1.4获取当前类中`@Order`注解的信息
      • 2.2 创建`ConfigurationClassParser`用来解析配置类
      • 2.3 解析所有配置类
        • 2.3.1递归处理内部类
        • 2.3.2处理`@PropertySource`注解
          • 2.3.2.1获取到`@PropertySource`注解属性键值对
          • 2.3.2.2解析`properties`文件,并将内容加载到环境中
        • 2.3.3处理`@ComponentScan`注解
          • 2.3.3.1`ClassPathBeanDefinitionScanner`构造方法
          • 2.3.3.2判断扫描到的类是否需要使用代理
          • 2.3.3.3添加自定义的过滤规则
          • 2.3.3.4设置扫描到的类是否为懒加载
          • 2.3.3.5开始扫描
            • (5-1)核心方法,扫描包,创建对应类的`BeanDefinition`
            • (5-2)解析组件中的`@Scope`注解,获取`ScopeMetadata`
            • (5-3)使用`BeanNameGenerate`生成对应bean的名字
            • (5-4)向`BeanDefinition`设置一些默认属性
            • (5-5)解析bean中的一些公共的注解
            • (5-6)判断当前`BeanDefinition`是否可以被注册到容器中(不是实例化)
            • (5-7)应用`@Scope`注解指定的代理模式(是否创建代理的`BeanDefinition`)
        • 2.3.4处理`@Import`注解
          • 2.3.4.1`SourceClass`类
          • 2.3.4.2解析`@Import`注解,获取需要导入的类的`SourceClass`
          • 2.3.4.3 导入`@Import`注解指定的类(解析为`BeanDefinition`,等待统一实例化)
            • (3-1)实例化`ImportSelector`或`ImportBeanDefinitionRegistrar`
            • (3-2)合并两个`exclusionFilter`过滤器
            • (3-3)保存`ImportBeanDefinitionRegistrar`到当前标注`@Import`注解配置类的`ConfigurationClass`上
            • (3-4)`DeferredImportSelector`,延迟导入
        • 2.3.5处理`@ImportResource`注解
        • 2.3.6处理`@Bean`注解
          • 2.3.6.1获取配置类中有`@Bean`注解的方法元数据
          • 2.3.6.2对标准反射获取的`MethodMetadata`(方法元数据)进行排序
          • 2.3.6.3保存到配置类的`ConfigurationClass`中等候统一处理
          • 2.3.6.4处理配置类接口有默认实现的`@Bean`方法
        • 2.3.7如果有父类,返回当前配置类的父类重复处理流程
        • 2.3.8延迟处理`@Import`注解导入的`DeferredImportSelector`
          • 2.3.8.1延迟导入所涉及的类
          • 2.3.8.2延迟导入处理流程
      • 2.4校验所有解析好的配置类
      • 2.5使用`ConfigurationClassBeanDefinitionReader`加载`ConfigurationClass`中的`BeanDefinition`
        • 2.5.1当前配置类是被别的配置类导入的(内部类或`@Import`注解)
          • 2.5.1.1根据配置类的`AnnotationMetadata`创建一个`BeanDefinition`
          • 2.5.1.2解析配置类上的`@Scope`注解
          • 2.5.1.3生成当前配置类的`BeanName`
          • 2.5.1.4处理一些公共的注解
          • 2.5.1.5应用`@Scope`注解指定的代理模式(是否创建代理的`BeanDefinition`)
          • 2.5.1.6将`beanName`和`BeanDefinition`注册到容器中
        • 2.5.2处理`@Bean`方法
          • 2.5.2.1判断容器中是否已经存在该`beanName`对应的`BeanDefinition`
          • 2.5.2.2构造`ConfigurationClassBeanDefinition`
        • 2.5.3处理`@ImportResource`注解导入的资源
        • 2.5.4处理`@Import`注解导入的`ImportBeanDefinitionRegistrar`
    • 3`postProcessBeanFactory`
      • 3.1代理容器中所有为`full`的配置类(`CGLIB`)
      • 3.2向容器中添加`ImportAwareBeanPostProcessor`

1 用途

解析配置类

我们先来看一下这个类的类图

spring--6--spring之ConfigurationClassPostProcessor源码_第1张图片

很明显,这个类是一个BeanFactoryPostProcessor(BeanFactory增强器),它会在容器中其它bean(普通bean,所有的BeanPostProcessor等)创建之前实例化并执行。

2 postProcessBeanDefinitionRegistry

这个BeanFactoryPostProcessor实例化后,首先会执行BeanDefinitionRegistryPostProcessor接口的postProcessBeanDefinitionRegistry,我们来看一下这个方法做了啥

/**
 * Derive further bean definitions from the configuration classes in the registry.
 * 从registry的配置类中获得更多的BeanDefinition
 * 实际上就是解析registry中所有的配置类
 */
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {

    /*********************检查是否处理过这个BeanDefinitionRegistry******************/    
    int registryId = System.identityHashCode(registry);
    if (this.registriesPostProcessed.contains(registryId)) {
        throw new IllegalStateException(
            "postProcessBeanDefinitionRegistry already called on this post-processor against " + registry);
    }
    if (this.factoriesPostProcessed.contains(registryId)) {
        throw new IllegalStateException(
            "postProcessBeanFactory already called on this post-processor against " + registry);
    }
    this.registriesPostProcessed.add(registryId);

    /*********************************************************************/   
    //解析BeanDefinitionRegistry中配置类
    processConfigBeanDefinitions(registry);
}

解析BeanDefinitionRegistry中配置类

/**
 * Build and validate a configuration model based on the registry of
 * {@link Configuration} classes.
 */
public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
    List<BeanDefinitionHolder> configCandidates = new ArrayList<>();
    //获取当前BeanDefinitionRegistry中所有bean的名字
    String[] candidateNames = registry.getBeanDefinitionNames();

    /*********************************************************************/
    /**
     * 遍历,找出BeanDefinitionRegistry中所有且未被解析过配置类
	 */
    for (String beanName : candidateNames) {
        //根据名字获取对应的BeanDefinition
        BeanDefinition beanDef = registry.getBeanDefinition(beanName);
        /**
         * 已经解析过的BeanDefinition中会有这么一个Attribute(就是一个字符串,
         * 作为标记,表示该类是一个配置类)
         * String CONFIGURATION_CLASS_ATTRIBUTE =Conventions.getQualifiedAttributeName(ConfigurationClassPostProcessor.class, "configurationClass");
		 */
        if (beanDef.getAttribute(ConfigurationClassUtils.CONFIGURATION_CLASS_ATTRIBUTE) != null) {
            if (logger.isDebugEnabled()) {
                logger.debug("Bean definition has already been processed as a configuration class: " + beanDef);
            }
        }
        //2.1检查beanDef是否是一个配置类(full或lite)
        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
    //排序
    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
    SingletonBeanRegistry sbr = null;
    if (registry instanceof SingletonBeanRegistry) {
        sbr = (SingletonBeanRegistry) registry;
        /**
         * 判断BeanName的生成策略,默认为false
         * 默认情况下,componentScan生成BeanName是短类名
         * 而@Import注解导入的类是完全限定名
         */
        if (!this.localBeanNameGeneratorSet) {
            /**
             * AnnotationConfigUtils.CONFIGURATION_BEAN_NAME_GENERATOR=
             * "org.springframework.context.annotation.
             * internalConfigurationBeanNameGenerator"
             * 调用getSingleton方法从spring三级缓存中拿
             * ,现在当然是拿不到的,对象还没创建呢,generator为null
             */
            BeanNameGenerator generator = (BeanNameGenerator) sbr.getSingleton(
                AnnotationConfigUtils.CONFIGURATION_BEAN_NAME_GENERATOR);
            if (generator != null) {
                //private BeanNameGenerator componentScanBeanNameGenerator = AnnotationBeanNameGenerator.INSTANCE;
                //private BeanNameGenerator importBeanNameGenerator = IMPORT_BEAN_NAME_GENERATOR;
                this.componentScanBeanNameGenerator = generator;
                this.importBeanNameGenerator = generator;
            }
        }
    }

    //环境不存在就创建一个标准环境
    if (this.environment == null) {
        this.environment = new StandardEnvironment();
    }

    /*******************************解析配置类******************************/    
    // Parse each @Configuration class
    //2.2创建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 {
        //2.3解析所有配置类
        parser.parse(candidates);
        //2.4校验所有解析好的配置类
        parser.validate();

        Set<ConfigurationClass> configClasses = new LinkedHashSet<>(parser.getConfigurationClasses());
        configClasses.removeAll(alreadyParsed);

        // Read the model and create bean definitions based on its content
        if (this.reader == null) {
            this.reader = new ConfigurationClassBeanDefinitionReader(
                registry, this.sourceExtractor, this.resourceLoader, this.environment,
                this.importBeanNameGenerator, parser.getImportRegistry());
        }
        //2.5使用ConfigurationClassBeanDefinitionReader加载ConfigurationClass中的BeanDefinition
        this.reader.loadBeanDefinitions(configClasses);
        alreadyParsed.addAll(configClasses);

        candidates.clear();
        if (registry.getBeanDefinitionCount() > candidateNames.length) {
            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)) {
                    BeanDefinition bd = registry.getBeanDefinition(candidateName);
                    if (ConfigurationClassUtils.checkConfigurationClassCandidate(bd, this.metadataReaderFactory) &&
                        !alreadyParsedClasses.contains(bd.getBeanClassName())) {
                        candidates.add(new BeanDefinitionHolder(bd, candidateName));
                    }
                }
            }
            candidateNames = newCandidateNames;
        }
    }
    while (!candidates.isEmpty());

    // Register the ImportRegistry as a bean in order to support ImportAware @Configuration classes
    /**
     * registerSingleton()将一个对象保存到spring的单例对象池中
     * parser.getImportRegistry()就是获取ConfigurationClassParser中importStack属性对象
     * importStack中保存了@Import注解导入的类的完全限定名和来源类的AnnotationMetadata,见2.3.4.3
     */
    if (sbr != null && !sbr.containsSingleton(IMPORT_REGISTRY_BEAN_NAME)) {
        sbr.registerSingleton(IMPORT_REGISTRY_BEAN_NAME, parser.getImportRegistry());
    }

    //清空工厂缓存,里面缓存了很多类的MetadataReader
    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();
    }
}

2.1 检查beanDef是否是一个配置类(fulllite

/**
 * Check whether the given bean definition is a candidate for a configuration class
 * (or a nested component class declared within a configuration/component class,
 * to be auto-registered as well), and mark it accordingly.
 * @param beanDef the bean definition to check
 * @param metadataReaderFactory the current factory in use by the caller
 * @return whether the candidate qualifies as (any kind of) configuration class
 */
public static boolean checkConfigurationClassCandidate(
    BeanDefinition beanDef, MetadataReaderFactory metadataReaderFactory) {

    //bean的完全限定名
    String className = beanDef.getBeanClassName();
    //工厂类肯定不是配置类
    if (className == null || beanDef.getFactoryMethodName() != null) {
        return false;
    }

    AnnotationMetadata metadata;
    /**
     * spring中component-scan扫描@Component、@Configuration等类
     * 形成ScannedGenericBeanDefinition,实现了AnnotatedBeanDefinition接口,
     * 代表注解配置的bean
     * 而xml配置文件配置的普通的bean标签形成的是GenericBeanDefinition
     */
    if (beanDef instanceof AnnotatedBeanDefinition &&
        className.equals(((AnnotatedBeanDefinition) beanDef).getMetadata().getClassName())) {
        // Can reuse the pre-parsed metadata from the given BeanDefinition...
        /**
         * className.equals(((AnnotatedBeanDefinition)beanDef).getMetadata().getClassName())
         * 判定成功表明此时BeanDefinition中的metadata和BeanDefinition是匹配的,可以重用
         * 
         * ScannedGenericBeanDefinition的metadata类型为SimpleAnnotationMetadata
         */ 
        metadata = ((AnnotatedBeanDefinition) beanDef).getMetadata();
    }
    /**
     * 2.1.1判断这个BeanDefinition对应的类是否已经被加载到jvm
     * hasBeanClass()主要就是这个方法, 
     * 它判断BeanDefinition中beanClass属性是类名(未加载到jvm)还是clazz对象(已加载到jvm)
     */
    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.
        /**
         * BeanFactoryPostProcessor
         * BeanPostProcessor
         * AopInfrastructureBean
         * EventListenerFactory
         * 这四种类型的bean也不是配置类
         */
        Class<?> beanClass = ((AbstractBeanDefinition) beanDef).getBeanClass();
        if (BeanFactoryPostProcessor.class.isAssignableFrom(beanClass) ||
            BeanPostProcessor.class.isAssignableFrom(beanClass) ||
            AopInfrastructureBean.class.isAssignableFrom(beanClass) ||
            EventListenerFactory.class.isAssignableFrom(beanClass)) {
            return false;
        }
        //创建StandardAnnotationMetadata,实际上就是使用简单反射来获取AnnotationMetadata
        metadata = AnnotationMetadata.introspect(beanClass);
    }
    else {
        try {
            /**
             * 2.1.2使用metadataReaderFactory获取对应类的MetadataReader
             * 再通过MetadataReader得到AnnotationMetadata
             *
             * 通过ASM来获取AnnotationMetadata
             */
            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;
        }
    }

    //获取@Configuration注解的所有属性
    Map<String, Object> config = metadata.getAnnotationAttributes(Configuration.class.getName());
    /**
     * proxyBeanMethods是@Configuration注解的一个属性
     * 默认值为true,表示创建当前类的代理类,这样做的好处就是:可以拦截@Bean注解的方法,
     * 当你在当前类中使用@Bean注解的方法获取对象的时候,不管调用多少次,返回的都是同一个对象
     */
    if (config != null && !Boolean.FALSE.equals(config.get("proxyBeanMethods"))) {
        //将配置类标识设置为full
        beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, CONFIGURATION_CLASS_FULL);
    }
    /**
     * 2.1.3检测当前类中是否包含其他配置注解
     * Component
     * ComponentScan
     * Import
     * ImportResource
     * Bean
     */
    else if (config != null || isConfigurationCandidate(metadata)) {
        //将配置类标识设置为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.
    /**
     * 2.1.4获取当前类中@Order注解的信息
     * 主要是为了获取配置类的执行顺序
     * 也是设置到BeanDefinition中
     */
    Integer order = getOrder(metadata);
    if (order != null) {
        beanDef.setAttribute(ORDER_ATTRIBUTE, order);
    }

    return true;
}

2.1.1判断BeanDefinition对应的类是否已经被加载

/**
 * Return whether this definition specifies a bean class.
 * @see #getBeanClass()
 * @see #setBeanClass(Class)
 * @see #resolveBeanClass(ClassLoader)
 */
public boolean hasBeanClass() {
    return (this.beanClass instanceof Class);
}

这个方法比较简单,就是判断beanClass是不是一个clazz,如果是clazz,就代表BeanDefinition对应的类是否已经被加载到jvm了,那么此时就直接使用简单反射了,否则的话,beanClass就是对应类的类名,此时要获取类注解的信息就只有两种方法:

(1)通过ClassUtils.forName("完全限定名"),将该类加载到虚拟机, 然后使用简单反射获取类中的注解信息。

(2)第二种方式就复杂了,通过ioASM直接操作字节码文件而不需要加载到jvm中,与之对应的就是2.1.2的内容了。

2.1.2使用metadataReaderFactory获取对应类的MetadataReader,然后得到AnnotationMetadata

metadataReaderFactoryConfigurationClassPostProcessor类的属性,有默认值

private MetadataReaderFactory metadataReaderFactory = new CachingMetadataReaderFactory();

但是你不要受这个迷惑,实际上用的并不是这个,而是aware接口方法调用创建的那个

public void setResourceLoader(ResourceLoader resourceLoader) {
   Assert.notNull(resourceLoader, "ResourceLoader must not be null");
   this.resourceLoader = resourceLoader;
   if (!this.setMetadataReaderFactoryCalled) {
       //这里重新new了一个MetadataReaderFactory,并传入了当前的resourceLoader
       //而resourceLoader就是ApplicationContext
       this.metadataReaderFactory = new CachingMetadataReaderFactory(resourceLoader);
   }
}

我们看一下CachingMetadataReaderFactorygetMetadataReader方法

public MetadataReader getMetadataReader(String className) throws IOException {
   try {
       /**
        * 拼接前类似于cn.lx.spring.v1.Config
        * ResourceLoader.CLASSPATH_URL_PREFIX="classpath:"
        * ClassUtils.CLASS_FILE_SUFFIX=".class"
        * 就是当前类的字节码文件路径
        */
       String resourcePath = ResourceLoader.CLASSPATH_URL_PREFIX +
           ClassUtils.convertClassNameToResourcePath(className) + ClassUtils.CLASS_FILE_SUFFIX;
       //通过路径获取字节码文件的统一资源描述
       Resource resource = this.resourceLoader.getResource(resourcePath);
       //获取MetadataReader
       return getMetadataReader(resource);
   }
   catch (FileNotFoundException ex) {
       // Maybe an inner class name using the dot name syntax? Need to use the dollar syntax here...
       // ClassUtils.forName has an equivalent check for resolution into Class references later on.
       int lastDotIndex = className.lastIndexOf('.');
       if (lastDotIndex != -1) {
           String innerClassName =
               className.substring(0, lastDotIndex) + '$' + className.substring(lastDotIndex + 1);
           String innerClassResourcePath = ResourceLoader.CLASSPATH_URL_PREFIX +
               ClassUtils.convertClassNameToResourcePath(innerClassName) + ClassUtils.CLASS_FILE_SUFFIX;
           Resource innerClassResource = this.resourceLoader.getResource(innerClassResourcePath);
           if (innerClassResource.exists()) {
               return getMetadataReader(innerClassResource);
           }
       }
       throw ex;
   }
}

/**
* 获取MetadataReader
* @param resource	统一资源描述
*/
public MetadataReader getMetadataReader(Resource resource) throws IOException {

   //判断当前这个MetadataReader缓存是不是一个线程安全的map
   if (this.metadataReaderCache instanceof ConcurrentMap) {
       // No synchronization necessary...
       MetadataReader metadataReader = this.metadataReaderCache.get(resource);
       if (metadataReader == null) {
           //父类getMetadataReader方法创建一个MetadataReader
           metadataReader = super.getMetadataReader(resource);
           this.metadataReaderCache.put(resource, metadataReader);
       }
       return metadataReader;
   }
   //非线程安全的map就上锁,流程都差不多
   else if (this.metadataReaderCache != null) {
       synchronized (this.metadataReaderCache) {
           MetadataReader metadataReader = this.metadataReaderCache.get(resource);
           if (metadataReader == null) {
               metadataReader = super.getMetadataReader(resource);
               this.metadataReaderCache.put(resource, metadataReader);
           }
           return metadataReader;
       }
   }
   else {
       return super.getMetadataReader(resource);
   }
}

CachingMetadataReaderFactory父类的getMetadataReader方法

public MetadataReader getMetadataReader(Resource resource) throws IOException {
   //使用统一资源描述和类加载器初始化一个SimpleMetadataReader
   return new SimpleMetadataReader(resource, this.resourceLoader.getClassLoader());
}

至于说由SimpleMetadataReader得到AnnotationMetadata的原理,这里就不在看了,你只需要知道它使用了ASM就行了(ASM框架可以直接操作(修改,添加方法和属性等)字节码文件)。

2.1.3检测当前类中是否包含其他配置注解

/**
 * Check the given metadata for a configuration class candidate
 * (or nested component class declared within a configuration/component class).
 * @param metadata the metadata of the annotated class
 * @return {@code true} if the given class is to be registered for
 * configuration class processing; {@code false} otherwise
 */
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.add(Component.class.getName());
	 * candidateIndicators.add(ComponentScan.class.getName());
	 * candidateIndicators.add(Import.class.getName());
	 * candidateIndicators.add(ImportResource.class.getName());
	 * 有这4个注解,表明是一个lite配置类
     */
    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;
    }
}

总结:只要类中有这5个注解(@Component@ComponentScan@ImportResource@Import@Configuration@Bean)之一,就表明该类是一个配置类。

2.1.4获取当前类中@Order注解的信息

/**
 * Determine the order for the given configuration class metadata.
 * @param metadata the metadata of the annotated class
 * @return the {@code @Order} annotation value on the configuration class,
 * or {@code Ordered.LOWEST_PRECEDENCE} if none declared
 * @since 5.0
 */
@Nullable
public static Integer getOrder(AnnotationMetadata metadata) {
    //获取@Order注解的信息
    Map<String, Object> orderAttributes = metadata.getAnnotationAttributes(Order.class.getName());
    //AnnotationUtils.VALUE="value"
    return (orderAttributes != null ? ((Integer) orderAttributes.get(AnnotationUtils.VALUE)) : null);
}

2.2 创建ConfigurationClassParser用来解析配置类

/**
 * Create a new {@link ConfigurationClassParser} instance that will be used
 * to populate the set of configuration classes.
 */
public ConfigurationClassParser(MetadataReaderFactory metadataReaderFactory,
                                ProblemReporter problemReporter, Environment environment, ResourceLoader resourceLoader,
                                BeanNameGenerator componentScanBeanNameGenerator, BeanDefinitionRegistry registry) {

    //上面用到过的MetadataReaderFactory,可以用来获取某个类的MetadataReader,最终获取到该类的注解信息
    this.metadataReaderFactory = metadataReaderFactory;

    this.problemReporter = problemReporter;
    this.environment = environment;
    this.resourceLoader = resourceLoader;
    this.registry = registry;

    /**
     * 创建了一个ComponentScanAnnotationParser(解析@ComponentScan注解)
     * componentScanBeanNameGenerator:默认短类名
     */
    this.componentScanParser = new ComponentScanAnnotationParser(
        environment, resourceLoader, componentScanBeanNameGenerator, registry);
    //处理@Conditional注解
    this.conditionEvaluator = new ConditionEvaluator(registry, environment, resourceLoader);
}

2.3 解析所有配置类

public void parse(Set<BeanDefinitionHolder> configCandidates) {
    //遍历
    for (BeanDefinitionHolder holder : configCandidates) {
        BeanDefinition bd = holder.getBeanDefinition();
        try {
            //已经解析过了,直接获取AnnotationMetadata
            if (bd instanceof AnnotatedBeanDefinition) {
                //解析某一个配置类
                parse(((AnnotatedBeanDefinition) bd).getMetadata(), holder.getBeanName());
            }
            /**
             * 简单反射获取AnnotationMetadata
             * hasBeanClass()判断是否被加载到jvm中
             */
            else if (bd instanceof AbstractBeanDefinition && ((AbstractBeanDefinition) bd).hasBeanClass()) {
                //解析某一个配置类
                parse(((AbstractBeanDefinition) bd).getBeanClass(), holder.getBeanName());
            }
            //ASM获取AnnotationMetadata
            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);
        }
    }

    //2.3.8延迟处理@Import注解导入的DeferredImportSelector
    this.deferredImportSelectorHandler.process();
}

解析某一个配置类parse方法,有两个重载版本

protected final void parse(AnnotationMetadata metadata, String beanName) throws IOException {
  processConfigurationClass(new ConfigurationClass(metadata, beanName), DEFAULT_EXCLUSION_FILTER);
}


protected final void parse(Class<?> clazz, String beanName) throws IOException {
  processConfigurationClass(new ConfigurationClass(clazz, beanName), DEFAULT_EXCLUSION_FILTER);
}


protected final void parse(@Nullable String className, String beanName) throws IOException {
  Assert.notNull(className, "No bean class name for configuration class bean definition");
  MetadataReader reader = this.metadataReaderFactory.getMetadataReader(className);
  processConfigurationClass(new ConfigurationClass(reader, beanName), DEFAULT_EXCLUSION_FILTER);
}

再来看看ConfigurationClass的三个构造方法

/**
 * Create a new {@link ConfigurationClass} with the given name.
 * @param metadata the metadata for the underlying class to represent
 * @param beanName name of the {@code @Configuration} class bean
 * @see ConfigurationClass#ConfigurationClass(Class, ConfigurationClass)
 */
public ConfigurationClass(AnnotationMetadata metadata, String beanName) {
    Assert.notNull(beanName, "Bean name must not be null");
    //已经有了直接赋值
    this.metadata = metadata;
    //根据类名获取Resource(spring统一资源描述)
    this.resource = new DescriptiveResource(metadata.getClassName());
    this.beanName = beanName;
}


/**
 * Create a new {@link ConfigurationClass} with the given name.
 * @param clazz the underlying {@link Class} to represent
 * @param beanName name of the {@code @Configuration} class bean
 * @see ConfigurationClass#ConfigurationClass(Class, ConfigurationClass)
 */
public ConfigurationClass(Class<?> clazz, String beanName) {
    Assert.notNull(beanName, "Bean name must not be null");
    /**
     * 使用该方法获取clazz的AnnotationMetadata
     * StandardAnnotationMetadata.from(clazz)
     *
     * 简单反射获取AnnotationMetadata
     */
    this.metadata = AnnotationMetadata.introspect(clazz);
    //根据类名获取Resource(spring统一资源描述)
    this.resource = new DescriptiveResource(clazz.getName());
    this.beanName = beanName;
}


/**
 * Create a new {@link ConfigurationClass} with the given name.
 * @param metadataReader reader used to parse the underlying {@link Class}
 * @param beanName must not be {@code null}
 * @see ConfigurationClass#ConfigurationClass(Class, ConfigurationClass)
 */
public ConfigurationClass(MetadataReader metadataReader, String beanName) {
    Assert.notNull(beanName, "Bean name must not be null");
    //ASM获取AnnotationMetadata
    //使用MetadataReader获取AnnotationMetadata(注解元数据)
    this.metadata = metadataReader.getAnnotationMetadata();
    //使用MetadataReader获取Resource(spring统一资源描述)
    this.resource = metadataReader.getResource();
    this.beanName = beanName;
}

从上面我们可以看到,三个构造方法最终都是为了计算出ConfigurationClass对象中AnnotationMetadataresourcebeanName,而不同的是:对于AnnotatedBeanDefinition类型的BeanDefinition,它的AnnotationMetadata是已经被解析过的,可以直接拿出来使用,而另外两种则是根据对应类是否被加载到jvm中来分别进行处理的。

三个parse方法都是先生成ConfigurationClass对象(就代表了一个配置类,里面包含配置类的注解信息、统一资源描述和完全限定名),然后以它为参数调用processConfigurationClass方法

protected void processConfigurationClass(ConfigurationClass configClass, Predicate<String> filter) throws IOException {
   //@Conditional注解条件判断
   if (this.conditionEvaluator.shouldSkip(configClass.getMetadata(), ConfigurationPhase.PARSE_CONFIGURATION)) {
       return;
   }
   //已经解析过的配置类会放入缓存中
   ConfigurationClass existingClass = this.configurationClasses.get(configClass);
   if (existingClass != null) {
       /**
        * 当前类是被另一个配置类导入的
        * ConfigurationClass中有一个属性Set importedBy
        * 该属性记录了当前类是被哪个配置类导入的,见2.3.1
        *
        */
       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);
}

处理配置类

/**
 * Apply processing and build a complete {@link ConfigurationClass} by reading the
 * annotations, members and methods from the source class. This method can be called
 * multiple times as relevant sources are discovered.
 * @param configClass the configuration class being build
 * @param sourceClass a source class
 * @return the superclass, or {@code null} if none found or previously processed
 */
@Nullable
protected final SourceClass doProcessConfigurationClass(
    ConfigurationClass configClass, SourceClass sourceClass, Predicate<String> filter)
    throws IOException {
    /*************************处理内部类配置类***********************************/
    //判断该类是否包含@Component注解
    if (configClass.getMetadata().isAnnotated(Component.class.getName())) {
        // Recursively process any member (nested) classes first
        //2.3.1递归处理内部类
        processMemberClasses(configClass, sourceClass, filter);
    }

    /*************************处理@PropertySource注解*********************************/    
    // Process any @PropertySource annotations
    //2.3.2处理@PropertySource注解
    for (AnnotationAttributes propertySource : AnnotationConfigUtils.attributesForRepeatable(
        sourceClass.getMetadata(), PropertySources.class,
        org.springframework.context.annotation.PropertySource.class)) {
        if (this.environment instanceof ConfigurableEnvironment) {
            processPropertySource(propertySource);
        }
        else {
            logger.info("Ignoring @PropertySource annotation on [" + sourceClass.getMetadata().getClassName() +
                        "]. Reason: Environment must implement ConfigurableEnvironment");
        }
    }

    /*************************处理@ComponentScan***********************************/    
    // Process any @ComponentScan annotations
    //2.3.3处理@ComponentScan注解
    //这个方法和@PropertySource完全一样
    Set<AnnotationAttributes> componentScans = AnnotationConfigUtils.attributesForRepeatable(
        sourceClass.getMetadata(), ComponentScans.class, ComponentScan.class);
    if (!componentScans.isEmpty() &&
        !this.conditionEvaluator.shouldSkip(sourceClass.getMetadata(), ConfigurationPhase.REGISTER_BEAN)) {
        for (AnnotationAttributes componentScan : componentScans) {
            // The config class is annotated with @ComponentScan -> perform the scan immediately
            //这个方法将扫描到的类转化为BeanDefinition,核心方法
            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
            //检查扫描到的类中有没有配置类,如果有,就调用parse方法进行解析(递归)
            for (BeanDefinitionHolder holder : scannedBeanDefinitions) {
                BeanDefinition bdCand = holder.getBeanDefinition().getOriginatingBeanDefinition();
                if (bdCand == null) {
                    bdCand = holder.getBeanDefinition();
                }
                if (ConfigurationClassUtils.checkConfigurationClassCandidate(bdCand, this.metadataReaderFactory)) {
                    //只要类中有这5个注解(@Component,@ComponentScan,@ImportResource,@Import,@Bean)之一,就会执行下面方法
                    parse(bdCand.getBeanClassName(), holder.getBeanName());
                }
            }
        }
    }

    /*************************处理@Import***********************************/    
    // Process any @Import annotations
    //2.3.4处理@Import注解
    processImports(configClass, sourceClass, getImports(sourceClass), filter, true);

    /*************************处理@ImportResource***********************************/ 
    //2.3.5处理@ImportResource注解
    // 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);
        }
    }

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

    /***********************处理接口的默认@Bean方法******************************/    
    // Process default methods on interfaces
    processInterfaces(configClass, sourceClass);

    /*************************返回当前配置类的父类*********************************/    
    // Process superclass, if any
    //2.3.7如果有父类,返回当前配置类的父类
    if (sourceClass.getMetadata().hasSuperClass()) {
        //获取父类的完全限定名
        String superclass = sourceClass.getMetadata().getSuperClassName();
        //父类不能为jdk中的类
        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;
}

2.3.1递归处理内部类

/**
* Register member (nested) classes that happen to be configuration classes themselves.
*/
private void processMemberClasses(ConfigurationClass configClass, SourceClass sourceClass,
                                Predicate<String> filter) throws IOException {

  //使用ASM获取该配置类的内部类的SourceClass集合
  Collection<SourceClass> memberClasses = sourceClass.getMemberClasses();
  if (!memberClasses.isEmpty()) {
      List<SourceClass> candidates = new ArrayList<>(memberClasses.size());
      //遍历所有的内部类
      for (SourceClass memberClass : memberClasses) {
          /**
           * isConfigurationCandidate()该方法见2.1.3
           * 就是判断该类是不是一个配置类
           * 第二个判断条件就是两个类的名字不能一样
           */
          if (ConfigurationClassUtils.isConfigurationCandidate(memberClass.getMetadata()) &&
              !memberClass.getMetadata().getClassName().equals(configClass.getMetadata().getClassName())) {
              candidates.add(memberClass);
          }
      }
      //排序
      OrderComparator.sort(candidates);
      for (SourceClass candidate : candidates) {
          /**
           * 主要是为了避免循环嵌套问题
           * 因为有的人可能会在内部类上使用@Import注解导入主类,见2.3.4.3
           * 在处理内部类的时候,将主类记录到队列中,并且每次处理内部类是先去队列中判断
           * 是否包含了该内部类的主类
           */
          if (this.importStack.contains(configClass)) {
              this.problemReporter.error(new CircularImportProblem(configClass, this.importStack));
          }
          else {
              //主类压栈
              this.importStack.push(configClass);
              try {
                  /**
                   * 递归处理内部类
                   * 这里必须得说一下asConfigClass()方法
                   * 它构造了一个当前内部类的ConfigurationClass对象
                   */
                  processConfigurationClass(candidate.asConfigClass(configClass), filter);
              }
              finally {
                  //内部类处理完成后,将该内部类对应的主类弹栈
                  this.importStack.pop();
              }
          }
      }
  }
}

asConfigClass()方法非常重要,它为什么要传一个主类的ConfigurationClass对象?废话不多说,直接看源码你就明白了

//又是两套流程,简单反射和ASM
public ConfigurationClass asConfigClass(ConfigurationClass importedBy) {
    //this.source不就是当前内部类的clazz或MetadataReader
    //简单反射
    if (this.source instanceof Class) {
        return new ConfigurationClass((Class<?>) this.source, importedBy);
    }
    //ASM
    return new ConfigurationClass((MetadataReader) this.source, importedBy);
}

与之对应的ConfigurationClass的两个构造方法

//记录当前配置类是来源于那个配置类的,初始大小为1
private final Set<ConfigurationClass> importedBy = new LinkedHashSet<>(1);

/**
 * Create a new {@link ConfigurationClass} representing a class that was imported
 * using the {@link Import} annotation or automatically processed as a nested
 * configuration class (if imported is {@code true}).
 * @param clazz the underlying {@link Class} to represent
 * @param importedBy the configuration class importing this one (or {@code null})
 * @since 3.1.1
 */
public ConfigurationClass(Class<?> clazz, @Nullable ConfigurationClass importedBy) {
    //StandardAnnotationMetadata.from(clazz)
    //简单反射获取AnnotationMetadata
    this.metadata = AnnotationMetadata.introspect(clazz);
    this.resource = new DescriptiveResource(clazz.getName());
    //记录当前配置类是来源于那个配置类的
    this.importedBy.add(importedBy);
}


/**
 * Create a new {@link ConfigurationClass} representing a class that was imported
 * using the {@link Import} annotation or automatically processed as a nested
 * configuration class (if importedBy is not {@code null}).
 * @param metadataReader reader used to parse the underlying {@link Class}
 * @param importedBy the configuration class importing this one or {@code null}
 * @since 3.1.1
 */
public ConfigurationClass(MetadataReader metadataReader, @Nullable ConfigurationClass importedBy) {
    //ASM
    this.metadata = metadataReader.getAnnotationMetadata();
    this.resource = metadataReader.getResource();
    //记录当前配置类是来源于那个配置类的
    this.importedBy.add(importedBy);
}

2.3.2处理@PropertySource注解

//2.3.2.1获取到`@PropertySource`注解属性键值对
for (AnnotationAttributes propertySource : AnnotationConfigUtils.attributesForRepeatable(
    sourceClass.getMetadata(), PropertySources.class,
    org.springframework.context.annotation.PropertySource.class)) {
    if (this.environment instanceof ConfigurableEnvironment) {
        //2.3.2.2解析properties文件,并将内容加载到环境中
        processPropertySource(propertySource);
    }
    else {
        logger.info("Ignoring @PropertySource annotation on [" + sourceClass.getMetadata().getClassName() +
                    "]. Reason: Environment must implement ConfigurableEnvironment");
    }
}
2.3.2.1获取到@PropertySource注解属性键值对

首先我们先来看看这个attributesForRepeatable方法,它的返回值是Set,这个AnnotationAttributes是个什么东西呢?看源码我们发现它继承了LinkedHashMap,就是一个map集合,我们可以猜测,这个里面保存了注解属性的key-value键值对。

进入这个方法的源码

static Set<AnnotationAttributes> attributesForRepeatable(AnnotationMetadata metadata,
                                                        Class<?> containerClass, Class<?> annotationClass) {

   //调用下面方法进行真正的处理
   return attributesForRepeatable(metadata, containerClass.getName(), annotationClass.getName());
}

@SuppressWarnings("unchecked")
static Set<AnnotationAttributes> attributesForRepeatable(
   AnnotationMetadata metadata, String containerClassName, String annotationClassName) {

   Set<AnnotationAttributes> result = new LinkedHashSet<>();

   // Direct annotation present?
   /**
    * @PropertySource注解
    * getAnnotationAttributes() 获取对应注解所有属性键值对
    */
   addAttributesIfNotNull(result, metadata.getAnnotationAttributes(annotationClassName, false));

   // Container annotation present?
   /**
    * @PropertySources注解
    * 需要注意,这是两个注解,它们的属性键值对是不一样的
    *
    * getAnnotationAttributes(containerClassName, false)
    * 也会解析value属性(@PropertySource注解),形成一个嵌套map
    * 也就是说AnnotationAttributes中最终都是@PropertySource注解的属性键值对
    */
   Map<String, Object> container = metadata.getAnnotationAttributes(containerClassName, false);
   if (container != null && container.containsKey("value")) {
       for (Map<String, Object> containedAttributes : (Map<String, Object>[]) container.get("value")) { 
           addAttributesIfNotNull(result, containedAttributes);
       }
   }

   // Return merged result
   return Collections.unmodifiableSet(result);
}
2.3.2.2解析properties文件,并将内容加载到环境中

接下来我们看看processPropertySource(propertySource);这个方法,进入源码

/**
 * Process the given @PropertySource annotation metadata.
 * @param propertySource metadata for the @PropertySource annotation found
 * @throws IOException if loading a property source failed
 */
private void processPropertySource(AnnotationAttributes propertySource) throws IOException {
    //@PropertySource注解的name属性值
    String name = propertySource.getString("name");
    if (!StringUtils.hasLength(name)) {
        name = null;
    }
    //@PropertySource注解的encoding属性值
    String encoding = propertySource.getString("encoding");
    if (!StringUtils.hasLength(encoding)) {
        encoding = null;
    }
    //@PropertySource注解的value属性值
    String[] locations = propertySource.getStringArray("value");
    Assert.isTrue(locations.length > 0, "At least one @PropertySource(value) location is required");
    //@PropertySource注解的ignoreResourceNotFound属性值
    boolean ignoreResourceNotFound = propertySource.getBoolean("ignoreResourceNotFound");

    //创建一个PropertySourceFactory,它可以将properties文件的内容添加到环境中
    //factory属性可以指定用户自定义的工厂
    //默认工厂为DefaultPropertySourceFactory
    Class<? extends PropertySourceFactory> factoryClass = propertySource.getClass("factory");
    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);
            //使用工厂将properties文件的内容添加到环境中
            addPropertySource(factory.createPropertySource(name, new EncodedResource(resource, encoding)));
        }
        catch (IllegalArgumentException | FileNotFoundException | UnknownHostException | SocketException 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;
            }
        }
    }
}

总结

(1)注解中可以写SpEL表达式

(2)只能加载项目路径下的properties文件

2.3.3处理@ComponentScan注解

//这个方法将扫描到的类转化为BeanDefinition,核心方法
Set<BeanDefinitionHolder> scannedBeanDefinitions =
    this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName());

//componentScanParser是在ConfigurationClassParser构造方法初始化的,见2.2
//类型为ComponentScanAnnotationParser

我们看一下这个 parse方法是如何扫描并解析类的

public Set<BeanDefinitionHolder> parse(AnnotationAttributes componentScan, final String declaringClass) {
    /**
     * ClassPathBeanDefinitionScanner是一个很重要的类
     * 能扫描到有@Repository,@Service,@Controller,@Component注解
     * Java EE 6's @ManagedBean 和JSR-330's @Named的类,
     * 将其转化为BeanDefinition
     * 
     * 2.3.3.1ClassPathBeanDefinitionScanner构造方法
     */
    ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(this.registry,
                                                                                componentScan.getBoolean("useDefaultFilters"), this.environment, this.resourceLoader);

    //判断在注解中是否指定扫描到的类的beanName生成器
    Class<? extends BeanNameGenerator> generatorClass = componentScan.getClass("nameGenerator");
    boolean useInheritedGenerator = (BeanNameGenerator.class == generatorClass);
    scanner.setBeanNameGenerator(useInheritedGenerator ? this.beanNameGenerator :
                                 BeanUtils.instantiateClass(generatorClass));

    //2.3.3.2判断扫描到的类是否使用代理
    ScopedProxyMode scopedProxyMode = componentScan.getEnum("scopedProxy");
    if (scopedProxyMode != ScopedProxyMode.DEFAULT) {
        scanner.setScopedProxyMode(scopedProxyMode);
    }
    else {
        Class<? extends ScopeMetadataResolver> resolverClass = componentScan.getClass("scopeResolver");
        scanner.setScopeMetadataResolver(BeanUtils.instantiateClass(resolverClass));
    }

    //设置扫描类路径是的资源模式,默认为"**/*.class",会添加到指定的包名后面
    scanner.setResourcePattern(componentScan.getString("resourcePattern"));

    /**
     * AnnotationAttributes中有一个getAnnotationArray()方法
     * 它可以获取当前注解属性中包含的另一个注解信息数组
     * 
     * scanner.addIncludeFilter(typeFilter)实际上就是添加过滤规则,
     * 和ClassPathBeanDefinitionScanner构造方法中registerDefaultFilters()方法一样
     * 只不过registerDefaultFilters()方法添加的是对@Component注解的过滤,
     * 这个是我们定制的注解过滤
     * 2.3.3.3添加自定义的过滤规则
     */
    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);
        }
    }

    //2.3.3.4设置扫描到的类是否为懒加载
    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) {
        /**
        * 从这里可以看到,basePackages还可以使用占位符(SpEL表达式),从环境中解析值
        * ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS=",; \t\n"
        */
        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,就扫描当前注解所在类的包的所有类
        basePackages.add(ClassUtils.getPackageName(declaringClass));
    }

    //不扫描当前注解所在类
    scanner.addExcludeFilter(new AbstractTypeHierarchyTraversingFilter(false, false) {
        @Override
        protected boolean matchClassName(String className) {
            return declaringClass.equals(className);
        }
    });
    //2.3.3.5开始扫描
    return scanner.doScan(StringUtils.toStringArray(basePackages));
}
2.3.3.1ClassPathBeanDefinitionScanner构造方法

这个构造方法里面其实也没做啥,就是初始化一些属性,但是我们需要看一下registerDefaultFilters()方法。

/**
 * Create a new {@code ClassPathBeanDefinitionScanner} for the given bean factory and
 * using the given {@link Environment} when evaluating bean definition profile metadata.
 * @param registry the {@code BeanFactory} to load bean definitions into, in the form
 * of a {@code BeanDefinitionRegistry}
 * @param useDefaultFilters whether to include the default filters for the
 * {@link org.springframework.stereotype.Component @Component},
 * {@link org.springframework.stereotype.Repository @Repository},
 * {@link org.springframework.stereotype.Service @Service}, and
 * {@link org.springframework.stereotype.Controller @Controller} stereotype annotations
 * @param environment the Spring {@link Environment} to use when evaluating bean
 * definition profile metadata
 * @param resourceLoader the {@link ResourceLoader} to use
 * @since 4.3.6
 */
public ClassPathBeanDefinitionScanner(BeanDefinitionRegistry registry, boolean useDefaultFilters,
                                      Environment environment, @Nullable ResourceLoader resourceLoader) {

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

    if (useDefaultFilters) {
        //我们看一下这个方法
        registerDefaultFilters();
    }
    setEnvironment(environment);
    //这个方法也很重要,涉及到后面要说的组件索引
    setResourceLoader(resourceLoader);
}


/**
 * Register the default filter for {@link Component @Component}.
 * 

This will implicitly register all annotations that have the * {@link Component @Component} meta-annotation including the * {@link Repository @Repository}, {@link Service @Service}, and * {@link Controller @Controller} stereotype annotations. *

Also supports Java EE 6's {@link javax.annotation.ManagedBean} and * JSR-330's {@link javax.inject.Named} annotations, if available. * 添加过滤规则(@Component,@ManagedBean,@Named) * 把有这三个注解的类过滤下来 */ @SuppressWarnings("unchecked") protected void registerDefaultFilters() { //@Component this.includeFilters.add(new AnnotationTypeFilter(Component.class)); ClassLoader cl = ClassPathScanningCandidateComponentProvider.class.getClassLoader(); try { //@ManagedBean 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 { //@Named 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. } } /** * Set the {@link ResourceLoader} to use for resource locations. * This will typically be a {@link ResourcePatternResolver} implementation. *

Default is a {@code PathMatchingResourcePatternResolver}, also capable of * resource pattern resolving through the {@code ResourcePatternResolver} interface. * @see org.springframework.core.io.support.ResourcePatternResolver * @see org.springframework.core.io.support.PathMatchingResourcePatternResolver */ @Override public void setResourceLoader(@Nullable ResourceLoader resourceLoader) { //这里初始化的两个属性很重要,在后面都有用到 //resourcePatternResolver就是当前上下文 this.resourcePatternResolver = ResourcePatternUtils.getResourcePatternResolver(resourceLoader); this.metadataReaderFactory = new CachingMetadataReaderFactory(resourceLoader); /** * 在这里会去加载META-INF/spring.compononts文件 * 将文件内容封装到componentsIndex中, * 以便后面直接根据索引找到对应类,加快扫描速度 * * 如果不存在对应的文件,那个返回的对象就是空的 */ this.componentsIndex = CandidateComponentsIndexLoader.loadIndex(this.resourcePatternResolver.getClassLoader()); }

2.3.3.2判断扫描到的类是否需要使用代理

这个是非默认情况下

/**
* Specify the proxy behavior for non-singleton scoped beans.
* Note that this will override any custom "scopeMetadataResolver" setting.
* 

The default is {@link ScopedProxyMode#NO}. * @see #setScopeMetadataResolver */ public void setScopedProxyMode(ScopedProxyMode scopedProxyMode) { //这里我们自己new this.scopeMetadataResolver = new AnnotationScopeMetadataResolver(scopedProxyMode); }

/**
* Construct a new {@code AnnotationScopeMetadataResolver} using the
* supplied default {@link ScopedProxyMode}.
* @param defaultProxyMode the default scoped-proxy mode
*/
public AnnotationScopeMetadataResolver(ScopedProxyMode defaultProxyMode) {
   Assert.notNull(defaultProxyMode, "'defaultProxyMode' must not be null");
   this.defaultProxyMode = defaultProxyMode;
}

这个是默认情况下

Class<? extends ScopeMetadataResolver> resolverClass = componentScan.getClass("scopeResolver");
//反射实例化resolverClass,使用的是默认构造方法
scanner.setScopeMetadataResolver(BeanUtils.instantiateClass(resolverClass));
/**
* Construct a new {@code AnnotationScopeMetadataResolver}.
* @see #AnnotationScopeMetadataResolver(ScopedProxyMode)
* @see ScopedProxyMode#NO
*/
public AnnotationScopeMetadataResolver() {
   //默认情况下就是为No,不使用代理
   this.defaultProxyMode = ScopedProxyMode.NO;
}

总结:这里我们可以看到,@ComponentScan设置的scopedProxy属性值会被保存到AnnotationScopeMetadataResolverdefaultProxyMode属性中,后续处理见2.3.3.5(5-2)

2.3.3.3添加自定义的过滤规则

我们重点看一下这个typeFiltersFor(filter)方法

private List<TypeFilter> typeFiltersFor(AnnotationAttributes filterAttributes) {
   List<TypeFilter> typeFilters = new ArrayList<>();
   //获取@ComponentScan中内部注解@Filter注解的属性
   FilterType filterType = filterAttributes.getEnum("type");

   for (Class<?> filterClass : filterAttributes.getClassArray("classes")) {
       switch (filterType) {
               //过滤注解,可过滤@Component注解就是用的这种方式,见构造方法
           case ANNOTATION:
               Assert.isAssignable(Annotation.class, filterClass,
                                   "@ComponentScan ANNOTATION type filter requires an annotation type");
               @SuppressWarnings("unchecked")
               Class<Annotation> annotationType = (Class<Annotation>) filterClass;
               //也就是说我们可以自定义注解,然后将该注解添加到过滤规则里面
               typeFilters.add(new AnnotationTypeFilter(annotationType));
               break;

               //下面的几种我们目前用不到,等用到的时候在说   
           case ASSIGNABLE_TYPE:
               typeFilters.add(new AssignableTypeFilter(filterClass));
               break;
           case CUSTOM:
               Assert.isAssignable(TypeFilter.class, filterClass,
                                   "@ComponentScan CUSTOM type filter requires a TypeFilter implementation");

               TypeFilter filter = ParserStrategyUtils.instantiateClass(filterClass, TypeFilter.class,
                                                                        this.environment, this.resourceLoader, this.registry);
               typeFilters.add(filter);
               break;
           default:
               throw new IllegalArgumentException("Filter type not supported with Class value: " + filterType);
       }
   }

   //下面这两种过滤规则也不常用
   for (String expression : filterAttributes.getStringArray("pattern")) {
       switch (filterType) {
           case ASPECTJ:
               typeFilters.add(new AspectJTypeFilter(expression, this.resourceLoader.getClassLoader()));
               break;
               //这个应该是根据指定的完全限定类名过滤    
           case REGEX:
               typeFilters.add(new RegexPatternTypeFilter(Pattern.compile(expression)));
               break;
           default:
               throw new IllegalArgumentException("Filter type not supported with String pattern: " + filterType);
       }
   }

   return typeFilters;
}
2.3.3.4设置扫描到的类是否为懒加载
//获取@ComponentScan注解lazyInit属性值
boolean lazyInit = componentScan.getBoolean("lazyInit");
if (lazyInit) {
    /**
     * 核心的代码这个这个
     * 为什么在@ComponentScan注解中设置懒加载,然后它扫描到的组件默认就是懒加载的
     * 功能就是在此处完成的
     */
    scanner.getBeanDefinitionDefaults().setLazyInit(true);
}

ClassPathBeanDefinitionScanner初始化的时候有 private BeanDefinitionDefaults beanDefinitionDefaults = new BeanDefinitionDefaults();

我们看一下BeanDefinitionDefaults这个类

public class BeanDefinitionDefaults {

    @Nullable
    //懒加载
    private Boolean lazyInit;

    private int autowireMode = AbstractBeanDefinition.AUTOWIRE_NO;

    private int dependencyCheck = AbstractBeanDefinition.DEPENDENCY_CHECK_NONE;

    @Nullable
    private String initMethodName;

    @Nullable
    private String destroyMethodName;

    //还有一些对应的get,set方法,构造方法,都省略,这里主要看一下设置哪些默认属性
}

也就是说,@ComponentScan注解lazyInit属性值设置到这个对象里面了。在后面会这个对象中的值设置到扫描出来的BeanDefinition中,见2.3.3.5(5-4)

2.3.3.5开始扫描

经过前面设置的扫描参数后,现在开始扫描

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

This method does not register an annotation config processor * but rather leaves this up to the caller. * @param basePackages the packages to check for annotated classes * @return set of beans registered if any for tooling registration purposes (never {@code null}) */ protected Set<BeanDefinitionHolder> doScan(String... basePackages) { Assert.notEmpty(basePackages, "At least one base package must be specified"); Set<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet<>(); for (String basePackage : basePackages) { //(5-1)核心方法,扫描包,创建对应类的BeanDefinition(ScannedGenericBeanDefinition) Set<BeanDefinition> candidates = findCandidateComponents(basePackage); //进一步解析扫描的组件 for (BeanDefinition candidate : candidates) { //(5-2)解析组件中的@Scope注解,获取ScopeMetadata ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate); candidate.setScope(scopeMetadata.getScopeName()); //(5-3)使用BeanNameGenerate生成对应bean的名字 String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry); if (candidate instanceof AbstractBeanDefinition) { //(5-4)向BeanDefinition设置一些默认属性 postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName); } if (candidate instanceof AnnotatedBeanDefinition) { //(5-5)处理bean中的一些其他注解 AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate); } //(5-6)判断当前BeanDefinition是否可以被注册到容器中(不是实例化) if (checkCandidate(beanName, candidate)) { BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName); //(5-7)应用@Scope注解指定的代理模式(是否创建代理的BeanDefinition) definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry); beanDefinitions.add(definitionHolder); //注册到容器中,会注册BeanDefinition和别名 registerBeanDefinition(definitionHolder, this.registry); } } } return beanDefinitions; }

总结:这个方法可以说是@ComponentScan的核心方法,在这个方法里面完成对指定包的扫描,并且解析扫描到的组件中的@Scope@Lazy@Primary@DependsOn@Role@Description注解。

(5-1)核心方法,扫描包,创建对应类的BeanDefinition
/**
 * Scan the class path for candidate components.
 * @param basePackage the package to check for annotated classes
 * @return a corresponding Set of autodetected bean definitions
 */
public Set<BeanDefinition> findCandidateComponents(String basePackage) {
    //就是组件索引,方便找到组件(componentsIndex见2.3.3.1构造方法)
    if (this.componentsIndex != null && indexSupportsIncludeFilters()) {
        //根据索引快速扫描组件
        return addCandidateComponentsFromIndex(this.componentsIndex, basePackage);
    }
    //普通方式扫描
    else {
        return scanCandidateComponents(basePackage);
    }
}

组件索引速扫描组件

这个是spring官方文档地址https://docs.spring.io/spring-framework/docs/5.1.12.RELEASE/spring-framework-reference/core.html#beans-scanning-index

要使用组件索引,必须引入下面依赖

<dependency>
    <groupId>org.springframeworkgroupId>
    <artifactId>spring-context-indexerartifactId>
    <version>5.1.12.RELEASEversion>
    <optional>trueoptional>
dependency>

有了这个依赖,spring就会在程序编译的时候,自动创建META-INF/spring.components文件,里面包含了对应类的索引。

文件内容大概如下

#
#Sun Dec 27 16:27:11 CST 2020
cn.lx.spring.v1.Config=org.springframework.stereotype.Component
cn.lx.spring.v1.Person=org.springframework.stereotype.Component

文件中直接记录了所有@Component注解标注类的限定名,这样做,可以在大型项目中显著提升启动性能。

/**
 * Determine if the index can be used by this instance.
 * @return {@code true} if the index is available and the configuration of this
 * instance is supported by it, {@code false} otherwise
 * @since 5.0
 */
private boolean indexSupportsIncludeFilters() {
    //必须是所有过滤规则都通过才能使用组件索引
    //我们默认的就一种过滤规则(@Component)
    for (TypeFilter includeFilter : this.includeFilters) {
        if (!indexSupportsIncludeFilter(includeFilter)) {
            return false;
        }
    }
    return true;
}

/**
 * Determine if the specified include {@link TypeFilter} is supported by the index.
 * @param filter the filter to check
 * @return whether the index supports this include filter
 * @since 5.0
 * @see #extractStereotype(TypeFilter)
 */
private boolean indexSupportsIncludeFilter(TypeFilter filter) {
    if (filter instanceof AnnotationTypeFilter) {
        Class<? extends Annotation> annotation = ((AnnotationTypeFilter) filter).getAnnotationType();
        /**
         * isAnnotationDeclaredLocally()就是判断annotation注解中是否包含Indexed注解
         * 经过我们查看@Component源码,我们发现,上面的确包含@Indexed注解
         */
        return (AnnotationUtils.isAnnotationDeclaredLocally(Indexed.class, annotation) ||
                annotation.getName().startsWith("javax."));
    }
    if (filter instanceof AssignableTypeFilter) {
        Class<?> target = ((AssignableTypeFilter) filter).getTargetType();
        return AnnotationUtils.isAnnotationDeclaredLocally(Indexed.class, target);
    }
    return false;
}

根据索引快速扫描组件

private Set<BeanDefinition> addCandidateComponentsFromIndex(CandidateComponentsIndex index, String basePackage) {
    Set<BeanDefinition> candidates = new LinkedHashSet<>();
    try {
        Set<String> types = new HashSet<>();
        for (TypeFilter filter : this.includeFilters) {
            //获取当前过滤规则的名字,实际上就是org.springframework.stereotype.Component
            String stereotype = extractStereotype(filter);
            if (stereotype == null) {
                throw new IllegalArgumentException("Failed to extract stereotype from " + filter);
            }
            //根据@Component注解的完全限定名从索引中获取到有该注解的类的完全限定名
            types.addAll(index.getCandidateTypes(basePackage, stereotype));
        }
        boolean traceEnabled = logger.isTraceEnabled();
        boolean debugEnabled = logger.isDebugEnabled();
        for (String type : types) {
            //获取该类的MetadataReader
            MetadataReader metadataReader = getMetadataReaderFactory().getMetadataReader(type);
            //再次判断类是否可以通过过滤规则(excludeFilters和includeFilters)
            if (isCandidateComponent(metadataReader)) {
                /**
				 * 通过MetadataReader初始化一个BeanDefinition
				 * 构造方法中就这三个方法
				 * this.metadata = metadataReader.getAnnotationMetadata();注解元数据
				 * setBeanClassName(this.metadata.getClassName());beanName
				 * setResource(metadataReader.getResource());统一资源描述
				 */
                ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader);
                sbd.setSource(metadataReader.getResource());
                /**
                 * 这里又出现了isCandidateComponent()方法
                 * 这个方法是重载版的,我们需要弄清楚这两个方法的作用
                 */
                if (isCandidateComponent(sbd)) {
                    if (debugEnabled) {
                        logger.debug("Using candidate component class from index: " + type);
                    }
                    //添加到集合中,返回
                    candidates.add(sbd);
                }
                else {
                    if (debugEnabled) {
                        logger.debug("Ignored because not a concrete top-level class: " + type);
                    }
                }
            }
            else {
                if (traceEnabled) {
                    logger.trace("Ignored because matching an exclude filter: " + type);
                }
            }
        }
    }
    catch (IOException ex) {
        throw new BeanDefinitionStoreException("I/O failure during classpath scanning", ex);
    }
    return candidates;
}

/**
 * Determine whether the given class does not match any exclude filter
 * and does match at least one include filter.
 * @param metadataReader the ASM ClassReader for the class
 * @return whether the class qualifies as a candidate component
 */
protected boolean isCandidateComponent(MetadataReader metadataReader) throws IOException {
    /**
     * 先进行excludeFilters的过滤,我们已经知道里面只有一个过滤规则
     * 那就是排除当前注解标注的类
     */
    for (TypeFilter tf : this.excludeFilters) {
        if (tf.match(metadataReader, getMetadataReaderFactory())) {
            return false;
        }
    }

    /**
     * 先进行includeFilters的过滤,我们已经知道里面也只有一个过滤规则
     * 那就包含@Component注解的类
     */
    for (TypeFilter tf : this.includeFilters) {
        if (tf.match(metadataReader, getMetadataReaderFactory())) {
            return isConditionMatch(metadataReader);
        }
    }
    return false;
}


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

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

Can be overridden in subclasses. * @param beanDefinition the bean definition to check * @return whether the bean definition qualifies as a candidate component * 这个方法就是判断BeanDefinition是否符合条件了 */ protected boolean isCandidateComponent(AnnotatedBeanDefinition beanDefinition) { AnnotationMetadata metadata = beanDefinition.getMetadata(); /** * isIndependent() 判断当前BeanDefinition对应的类是否是独立类(顶级类,静态内部类) * isConcrete() 是否非接口非抽象类 * hasAnnotatedMethods(Lookup.class.getName())是否有包含@Lookup注解的方法 * * 成立条件:首先必须是独立类,其次要么是非抽象类非接口,要么是抽象类但是有@Lookup注解的方法 */ return (metadata.isIndependent() && (metadata.isConcrete() || (metadata.isAbstract() && metadata.hasAnnotatedMethods(Lookup.class.getName())))); }

普通方式扫描组件

很明显,这个是ASM的方式扫描组件,相比于反射的优点就是不需要将对应包下类加载到jvm中,节省了jvm的内存

private Set<BeanDefinition> scanCandidateComponents(String basePackage) {
    Set<BeanDefinition> candidates = new LinkedHashSet<>();
    try {

        //包名加上前后缀
        //ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX="classpath*:"
        //classpath*:说明会去所有的jar包找
        //this.resourcePattern="**/*.class"
        String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX +
            resolveBasePackage(basePackage) + '/' + this.resourcePattern;
        //获取当前的ResourcePatternResolver,实际上就是当前上下文对象
        //获取到当前包下面所有类的资源
        Resource[] resources = getResourcePatternResolver().getResources(packageSearchPath);
        boolean traceEnabled = logger.isTraceEnabled();
        boolean debugEnabled = logger.isDebugEnabled();
        for (Resource resource : resources) {
            if (traceEnabled) {
                logger.trace("Scanning " + resource);
            }
            //判断当前资源是否可读(是否存在)
            if (resource.isReadable()) {
                try {
                    //到了这里,后面的流程就和索引方式的一样了
                    MetadataReader metadataReader = getMetadataReaderFactory().getMetadataReader(resource);
                    /**
                     * 两个同名方法isCandidateComponent()
                     * 并且BeanDefinition的类型都是ScannedGenericBeanDefinition
                     * 到了这一步,我们可以很明确的说扫描的类都是ScannedGenericBeanDefinition
                     */
                    if (isCandidateComponent(metadataReader)) {
                        ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader);
                        sbd.setSource(resource);
                        if (isCandidateComponent(sbd)) {
                            if (debugEnabled) {
                                logger.debug("Identified candidate component class: " + resource);
                            }
                            candidates.add(sbd);
                        }
                        else {
                            if (debugEnabled) {
                                logger.debug("Ignored because not a concrete top-level class: " + resource);
                            }
                        }
                    }
                    else {
                        if (traceEnabled) {
                            logger.trace("Ignored because not matching any filter: " + resource);
                        }
                    }
                }
                catch (Throwable ex) {
                    throw new BeanDefinitionStoreException(
                        "Failed to read candidate component class: " + resource, ex);
                }
            }
            else {
                if (traceEnabled) {
                    logger.trace("Ignored because not readable: " + resource);
                }
            }
        }
    }
    catch (IOException ex) {
        throw new BeanDefinitionStoreException("I/O failure during classpath scanning", ex);
    }
    return candidates;
}
(5-2)解析组件中的@Scope注解,获取ScopeMetadata

ClassPathBeanDefinitionScanner默认使用的ScopeMetadataResolver就是AnnotationScopeMetadataResolver,它是专门用来解析@Scope注解的

private ScopeMetadataResolver scopeMetadataResolver = new AnnotationScopeMetadataResolver();

解析@Scope注解

//该方法实际上就是解析类上的@Scope注解,没有就使用默认值
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) {
            //有@Scope注解,获取value属性和proxyMode属性
            metadata.setScopeName(attributes.getString("value"));
            ScopedProxyMode proxyMode = attributes.getEnum("proxyMode");
            if (proxyMode == ScopedProxyMode.DEFAULT) {
                /**
                 * 这里面终于用到了this.defaultProxyMode这个属性
                 * 这个属性的来源就是@ComponentScan注解的scopedProxy属性,见2.3.3.2
                 * 
                 * 你注意一下此时的成立条件
                 * 首先对应的类是不是得有@Scope注解
                 * 其次proxyMode属性必须为默认的ScopedProxyMode.DEFAULT
                 *
                 * 由上可以总结:@ComponentScan注解的scopedProxy属性是修改代理模式的默认值
                 * 并且需要使用@Scope注解才会生效
                 */
                proxyMode = this.defaultProxyMode;
            }
            //将代理模式设置到ScopeMetadata(作用域元数据)中
            metadata.setScopedProxyMode(proxyMode);
        }
    }
    return metadata;
}

默认值

public class ScopeMetadata {

    private String scopeName = BeanDefinition.SCOPE_SINGLETON;

    private ScopedProxyMode scopedProxyMode = ScopedProxyMode.NO;
}
(5-3)使用BeanNameGenerate生成对应bean的名字

生成的是短类名,见2.2指定的BeanNameGenerate

public String generateBeanName(BeanDefinition definition, BeanDefinitionRegistry registry) {
    if (definition instanceof AnnotatedBeanDefinition) {
        //获取@Component注解中指定的名字
        String beanName = determineBeanNameFromAnnotation((AnnotatedBeanDefinition) definition);
        if (StringUtils.hasText(beanName)) {
            // Explicit bean name found.
            return beanName;
        }
    }
    // Fallback: generate a unique default bean name.
    //自动生成一个默认的名字
    return buildDefaultBeanName(definition, registry);
}

/**
 * Derive a bean name from one of the annotations on the class.
 * @param annotatedDef the annotation-aware bean definition
 * @return the bean name, or {@code null} if none is found
 */
@Nullable
protected String determineBeanNameFromAnnotation(AnnotatedBeanDefinition annotatedDef) {
    AnnotationMetadata amd = annotatedDef.getMetadata();
    //获取该bean的所有注解的完全限定名
    Set<String> types = amd.getAnnotationTypes();
    String beanName = null;
    for (String type : types) {
        //获取指定注解名的属性键值对
        AnnotationAttributes attributes = AnnotationConfigUtils.attributesFor(amd, type);
        if (attributes != null) {
            Set<String> metaTypes = this.metaAnnotationTypesCache.computeIfAbsent(type, key -> {
                //获取key类上的注解的完全限定名,实际上就是注解上面的注解
                //就比如@Component注解上面有@Indexed注解
                Set<String> result = amd.getMetaAnnotationTypes(key);
                return (result.isEmpty() ? Collections.emptySet() : result);
            });
            //检查是否允许获取注解中value属性值作为beanName
            if (isStereotypeWithNameValue(type, metaTypes, attributes)) {
                Object value = attributes.get("value");
                if (value instanceof String) {
                    String strVal = (String) value;
                    if (StringUtils.hasLength(strVal)) {
                        if (beanName != null && !strVal.equals(beanName)) {
                            throw new IllegalStateException("Stereotype annotations suggest inconsistent " +
                                                            "component names: '" + beanName + "' versus '" + strVal + "'");
                        }
                        beanName = strVal;
                    }
                }
            }
        }
    }
    return beanName;
}


/**
 * Derive a default bean name from the given bean definition.
 * 

The default implementation delegates to {@link #buildDefaultBeanName(BeanDefinition)}. * @param definition the bean definition to build a bean name for * @param registry the registry that the given bean definition is being registered with * @return the default bean name (never {@code null}) */ protected String buildDefaultBeanName(BeanDefinition definition, BeanDefinitionRegistry registry) { //这个方法生成默认beanName return buildDefaultBeanName(definition); } /** * Derive a default bean name from the given bean definition. *

The default implementation simply builds a decapitalized version * of the short class name: e.g. "mypackage.MyJdbcDao" -> "myJdbcDao". *

Note that inner classes will thus have names of the form * "outerClassName.InnerClassName", which because of the period in the * name may be an issue if you are autowiring by name. * @param definition the bean definition to build a bean name for * @return the default bean name (never {@code null}) */ protected String buildDefaultBeanName(BeanDefinition definition) { //这个方法获取bean的完全限定名 String beanClassName = definition.getBeanClassName(); Assert.state(beanClassName != null, "No bean class name set"); //工具类截取,得到短类名 String shortClassName = ClassUtils.getShortName(beanClassName); return Introspector.decapitalize(shortClassName); }

(5-4)向BeanDefinition设置一些默认属性

这个需要我们的2.3.3.4章节结合起来看

/**
 * Apply further settings to the given bean definition,
 * beyond the contents retrieved from scanning the component class.
 * @param beanDefinition the scanned bean definition
 * @param beanName the generated bean name for the given bean
 */
protected void postProcessBeanDefinition(AbstractBeanDefinition beanDefinition, String beanName) {
    //private BeanDefinitionDefaults beanDefinitionDefaults = new BeanDefinitionDefaults();
    //将BeanDefinitionDefaults覆盖到BeanDefinition中
    beanDefinition.applyDefaults(this.beanDefinitionDefaults);
    //这个没用到,不管
    if (this.autowireCandidatePatterns != null) {
        beanDefinition.setAutowireCandidate(PatternMatchUtils.simpleMatch(this.autowireCandidatePatterns, beanName));
    }
}

我们看一下这个applyDefaults方法

/**
 * Apply the provided default values to this bean.
 * @param defaults the default settings to apply
 * @since 2.5
 * 将BeanDefinitionDefaults覆盖到BeanDefinition中
 */
public void applyDefaults(BeanDefinitionDefaults defaults) {
    //调用set方法设值
    Boolean lazyInit = defaults.getLazyInit();
    if (lazyInit != null) {
        setLazyInit(lazyInit);
    }
    setAutowireMode(defaults.getAutowireMode());
    setDependencyCheck(defaults.getDependencyCheck());
    setInitMethodName(defaults.getInitMethodName());
    setEnforceInitMethod(false);
    setDestroyMethodName(defaults.getDestroyMethodName());
    setEnforceDestroyMethod(false);
}
(5-5)解析bean中的一些公共的注解

这个方法很简单,就是将这几个注解(@Lazy@Primary@DependsOn@Role@Description)解析,然后将值设置到BeanDefinition

public static void processCommonDefinitionAnnotations(AnnotatedBeanDefinition abd) {
    processCommonDefinitionAnnotations(abd, abd.getMetadata());
}

static void processCommonDefinitionAnnotations(AnnotatedBeanDefinition abd, AnnotatedTypeMetadata metadata) {
    /**************************@Lazy************************************/
    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"));
        }
    }

    /**************************@Primary************************************/
    if (metadata.isAnnotated(Primary.class.getName())) {
        abd.setPrimary(true);
    }

    /**************************@DependsOn************************************/
    AnnotationAttributes dependsOn = attributesFor(metadata, DependsOn.class);
    if (dependsOn != null) {
        abd.setDependsOn(dependsOn.getStringArray("value"));
    }

    /**************************@Role************************************/
    AnnotationAttributes role = attributesFor(metadata, Role.class);
    if (role != null) {
        abd.setRole(role.getNumber("value").intValue());
    }

    /**************************@Description************************************/
    AnnotationAttributes description = attributesFor(metadata, Description.class);
    if (description != null) {
        abd.setDescription(description.getString("value"));
    }
}
(5-6)判断当前BeanDefinition是否可以被注册到容器中(不是实例化)
/**
 * Check the given candidate's bean name, determining whether the corresponding
 * bean definition needs to be registered or conflicts with an existing definition.
 * @param beanName the suggested name for the bean
 * @param beanDefinition the corresponding bean definition
 * @return {@code true} if the bean can be registered as-is;
 * {@code false} if it should be skipped because there is an
 * existing, compatible bean definition for the specified name
 * @throws ConflictingBeanDefinitionException if an existing, incompatible
 * bean definition has been found for the specified name
 */
protected boolean checkCandidate(String beanName, BeanDefinition beanDefinition) throws IllegalStateException {
    //不能存在同名BeanDefinition
    if (!this.registry.containsBeanDefinition(beanName)) {
        return true;
    }
    //存在同名BeanDefinition,获取容器中的那个BeanDefinition
    BeanDefinition existingDef = this.registry.getBeanDefinition(beanName);
    BeanDefinition originatingDef = existingDef.getOriginatingBeanDefinition();
    if (originatingDef != null) {
        existingDef = originatingDef;
    }
    //判断是否兼容
    //来自同一个Resource或者非扫描的,兼容
    if (isCompatible(beanDefinition, existingDef)) {
        return false;
    }
    throw new ConflictingBeanDefinitionException("Annotation-specified bean name '" + beanName +
                                                 "' for bean class [" + beanDefinition.getBeanClassName() + "] conflicts with existing, " +
                                                 "non-compatible bean definition of same name and class [" + existingDef.getBeanClassName() + "]");
}
(5-7)应用@Scope注解指定的代理模式(是否创建代理的BeanDefinition)
static BeanDefinitionHolder applyScopedProxyMode(
    ScopeMetadata metadata, BeanDefinitionHolder definition, BeanDefinitionRegistry registry) {

    //获取代理模式
    ScopedProxyMode scopedProxyMode = metadata.getScopedProxyMode();
    //NO模式不做任何操作
    if (scopedProxyMode.equals(ScopedProxyMode.NO)) {
        return definition;
    }
    //TARGET_CLASS模式则创建代理BeanDefinition
    boolean proxyTargetClass = scopedProxyMode.equals(ScopedProxyMode.TARGET_CLASS);
    return ScopedProxyCreator.createScopedProxy(definition, registry, proxyTargetClass);
}

我们看一下创建代理的关键方法

/**
 * Generate a scoped proxy for the supplied target bean, registering the target
 * bean with an internal name and setting 'targetBeanName' on the scoped proxy.
 * @param definition the original bean definition
 * @param registry the bean definition registry
 * @param proxyTargetClass whether to create a target class proxy
 * @return the scoped proxy definition
 * @see #getTargetBeanName(String)
 * @see #getOriginalBeanName(String)
 */
public static BeanDefinitionHolder createScopedProxy(BeanDefinitionHolder definition,
                                                     BeanDefinitionRegistry registry, boolean proxyTargetClass) {

    //原始名
    String originalBeanName = definition.getBeanName();
    //目标BeanDefinition(被代理的BeanDefinition)
    BeanDefinition targetDefinition = definition.getBeanDefinition();
    //目标beanName(实际上就是在原始名字上加前缀"scopedTarget.")
    String targetBeanName = getTargetBeanName(originalBeanName);

    // Create a scoped proxy definition for the original bean name,
    // "hiding" the target bean in an internal target definition.
    /**
     * 创建一个该clazz的BeanDefinition
     * ScopedProxyFactoryBean是什么东西呢?翻看源码我们发现,它实现了FactoryBean
     * 也就是说它可以使用getObject方法来生产bean
     * 所以Scope创建代理对象就是通过这个getObject方法来做到的
     */
    RootBeanDefinition proxyDefinition = new RootBeanDefinition(ScopedProxyFactoryBean.class);
    proxyDefinition.setDecoratedDefinition(new BeanDefinitionHolder(targetDefinition, targetBeanName));
    //将目标BeanDefinition设置到代理的BeanDefinition中
    proxyDefinition.setOriginatingBeanDefinition(targetDefinition);
    //目标bean的Resource
    proxyDefinition.setSource(definition.getSource());
    proxyDefinition.setRole(targetDefinition.getRole());

    //目标beanName设置到代理BeanDefinition属性中
    proxyDefinition.getPropertyValues().add("targetBeanName", targetBeanName);
    //true 表示用的是ScopedProxyMode.TARGET_CLASS模式,向BeanDefinition中设置对应值表示代理模式
    if (proxyTargetClass) {
        targetDefinition.setAttribute(AutoProxyUtils.PRESERVE_TARGET_CLASS_ATTRIBUTE, Boolean.TRUE);
        // ScopedProxyFactoryBean's "proxyTargetClass" default is TRUE, so we don't need to set it explicitly here.
    }
    //false 表示用的是ScopedProxyMode.INTERFACES模式
    else {
        proxyDefinition.getPropertyValues().add("proxyTargetClass", Boolean.FALSE);
    }

    // Copy autowire settings from original bean definition.
    //拷贝目标beanDefinition属性到代理BeanDefinition
    proxyDefinition.setAutowireCandidate(targetDefinition.isAutowireCandidate());
    proxyDefinition.setPrimary(targetDefinition.isPrimary());
    if (targetDefinition instanceof AbstractBeanDefinition) {
        proxyDefinition.copyQualifiersFrom((AbstractBeanDefinition) targetDefinition);
    }

    // The target bean should be ignored in favor of the scoped proxy.
    targetDefinition.setAutowireCandidate(false);
    targetDefinition.setPrimary(false);

    // Register the target bean as separate bean in the factory.
    /**
     * 将目标BeanDefinition注册到容器中,注册的名字上有前缀"scopedTarget."
     * 在后面,还会将代理类也注册容器中,注册名字是原始名
     */
    registry.registerBeanDefinition(targetBeanName, targetDefinition);

    // Return the scoped proxy definition as primary bean definition
    // (potentially an inner bean).
    //此时proxyDefinition持有者的beanName是原始名
    //那么以后代理BeanDefinition实例化,在容器中也是原始名
    //这里有点AOP的感觉
    return new BeanDefinitionHolder(proxyDefinition, originalBeanName, definition.getAliases());
}

2.3.4处理@Import注解

//进入这个方法之前,我们得先看看getImports()方法干了啥
processImports(configClass, sourceClass, getImports(sourceClass), filter, true);
2.3.4.1SourceClass

这是ConfigurationClassParser的内部类,它的内部方法都非常重要。

(1)它实现了Ordered接口,那么该类肯定可以进行排序,决定处理的先后顺序。

(2)Object source注释上说了,它可以是一个clazz对象也可以是MetadataReader·对象,两种对象类型,很明显就对应了两种处理方式,一种是简单反射,一种是ASM,看一下类的方法源码,确实如此。

(3)AnnotationMetadata metadata这个没什么好说的,就是类的注解元数据

/**
 * Simple wrapper that allows annotated source classes to be dealt with
 * in a uniform manner, regardless of how they are loaded.
 */
private class SourceClass implements Ordered {

    private final Object source;  // Class or MetadataReader

    private final AnnotationMetadata metadata;


    /*****************************2.3.4.2中用到********************************/
    /**
     * 获取source类所有注解的SourceClass
     * 注解和主类保持同样的加载方式
     */
    public Set<SourceClass> getAnnotations() {
        Set<SourceClass> result = new LinkedHashSet<>();
        //当前类已经被加载到jvm中了,使用简单反射来获取所有注解信息
        if (this.source instanceof Class) {
            Class<?> sourceClass = (Class<?>) this.source;
            for (Annotation ann : sourceClass.getDeclaredAnnotations()) {
                Class<?> annType = ann.annotationType();
                if (!annType.getName().startsWith("java")) {
                    try {
                        result.add(asSourceClass(annType, DEFAULT_EXCLUSION_FILTER));
                    }
                    catch (Throwable ex) {
                        // An annotation not present on the classpath is being ignored
                        // by the JVM's class loading -> ignore here as well.
                    }
                }
            }
        }
        //当前类未被加载到jvm,使用ASM获取类上所有注解信息
        else {
            //获取当前类的所有注解的完全限定名
            for (String className : this.metadata.getAnnotationTypes()) {
                //非java原生注解
                if (!className.startsWith("java")) {
                    try {
                        /**
                         * 这里使用ASM解析className对应的文件,主要是为了解析注解上的注解
                         * 因为有的注解上面可能标注了@Import注解
                         */
                        result.add(getRelated(className));
                    }
                    catch (Throwable ex) {
                        // An annotation not present on the classpath is being ignored
                        // by the JVM's class loading -> ignore here as well.
                    }
                }
            }
        }
        return result;
    }


    /**
     * 根据完全限定名获取对应类的SourceClass
     * 和主类保持同样的加载方式
     */
    private SourceClass getRelated(String className) throws IOException {
        //如果当前配置类已经被加载到jvm中了,就使用简单反射
        if (this.source instanceof Class) {
            try {
                //获取className对应的clazz
                Class<?> clazz = ClassUtils.forName(className, ((Class<?>) this.source).getClassLoader());
                //简单反射获取类上注解的SourceClass
                return asSourceClass(clazz, DEFAULT_EXCLUSION_FILTER);
            }
            catch (ClassNotFoundException ex) {
                // Ignore -> fall back to ASM next, except for core java types.
                if (className.startsWith("java")) {
                    throw new NestedIOException("Failed to load class [" + className + "]", ex);
                }
                return new SourceClass(metadataReaderFactory.getMetadataReader(className));
            }
        }
        //使用ASM获取类上注解的SourceClass
        return asSourceClass(className, DEFAULT_EXCLUSION_FILTER);
    }


    /**
     * 获取当前配置类上指定注解指定属性的属性值对应的类的SourceClass
     * 和主类保持同样的加载方式
     * @param annType	注解的完全限定名
     * @param attribute	注解的某一个属性名
     */
    public Collection<SourceClass> getAnnotationAttributes(String annType, String attribute) throws IOException {
        //获取该注解所有属性键值对
        Map<String, Object> annotationAttributes = this.metadata.getAnnotationAttributes(annType, true);
        //校验这个SourceClass中是否包含该注解,是否包含该属性
        if (annotationAttributes == null || !annotationAttributes.containsKey(attribute)) {
            //空set集合
            return Collections.emptySet();
        }
        //获取注解中attribute属性对应的值(导入的类的完全限定名)
        String[] classNames = (String[]) annotationAttributes.get(attribute);
        Set<SourceClass> result = new LinkedHashSet<>();
        //遍历
        for (String className : classNames) {
            //使用和当前配置类同样的方式得到SourceClass
            result.add(getRelated(className));
        }
        return result;
    }

    /*****************************2.3.4.3中用到********************************/
    /**
     * 判断指定类是否是当前类的超类或相同
     * 根据当前类的加载方式使用不同的方式判断
     * @param clazz	指定类
     */
    public boolean isAssignable(Class<?> clazz) throws IOException {
        if (this.source instanceof Class) {
            //反射判断指定类是否是当前类的超类或相同
            return clazz.isAssignableFrom((Class<?>) this.source);
        }
        //ASM反射判断指定类是否是当前类的超类或相同
        return new AssignableTypeFilter(clazz).match((MetadataReader) this.source, metadataReaderFactory);
    }


    /**
     * 获取当前类的clazz对象
     * 当前类未加载到jvm中就先通过ASM获取完全限定名,然后forName加载到jvm中
     */
    public Class<?> loadClass() throws ClassNotFoundException {
        if (this.source instanceof Class) {
            return (Class<?>) this.source;
        }
        String className = ((MetadataReader) this.source).getClassMetadata().getClassName();
        return ClassUtils.forName(className, resourceLoader.getClassLoader());
    }

    /*****************************2.3.6.4中用到********************************/

    //获取当前SourceClass的所有接口的SourceClass
    public Set<SourceClass> getInterfaces() throws IOException {
        Set<SourceClass> result = new LinkedHashSet<>();
        //标准反射
        if (this.source instanceof Class) {
            Class<?> sourceClass = (Class<?>) this.source;
            //反射获取所有父接口clazz
            for (Class<?> ifcClass : sourceClass.getInterfaces()) {
                result.add(asSourceClass(ifcClass, DEFAULT_EXCLUSION_FILTER));
            }
        }
        //ASM
        else {
            //ASM获取所有父接口的完全限定名
            for (String className : this.metadata.getInterfaceNames()) {
                result.add(asSourceClass(className, DEFAULT_EXCLUSION_FILTER));
            }
        }
        return result;
    }

}

首先你得知道DEFAULT_EXCLUSION_FILTER是什么,它是一个匿名内部类,实现Predicate接口,核心方法是test()

@FunctionalInterface
public interface Predicate<T> {

    /**
     * Evaluates this predicate on the given argument.
     *
     * @param t the input argument
     * @return {@code true} if the input argument matches the predicate,
     * otherwise {@code false}
     */
    boolean test(T t);
}

DEFAULT_EXCLUSION_FILTERasSourceClass()是定义在这个内部类外部的主类ConfigurationClassParser中的

//从这个test方法的实现,我们知道,它是判断className是不是一个java或者spring的原生注解
//spring的原生注解就是这几个@Component,@Repository,@Service,@Controller,@Indexed
private static final Predicate<String> DEFAULT_EXCLUSION_FILTER = className ->
    (className.startsWith("java.lang.annotation.") || className.startsWith("org.springframework.stereotype."));

//当碰到java或spring原生注解时,直接返回这个SourceClass
private final SourceClass objectSourceClass = new SourceClass(Object.class);

接下来我们看一下这个asSourceClass(),它有两个版本,分别对应简单反射和ASM

/**
 * Factory method to obtain a {@link SourceClass} from a {@link Class}.
 * 简单反射获取类上注解的SourceClass
 */
SourceClass asSourceClass(@Nullable Class<?> classType, Predicate<String> filter) throws IOException {
    //这里调用了上面定义的DEFAULT_EXCLUSION_FILTER,过滤掉java和spring的原生注解
    if (classType == null || filter.test(classType.getName())) {
        //返回SourceClass(Object.class)
        return this.objectSourceClass;
    }
    try {
        // Sanity test that we can reflectively read annotations,
        // including Class attributes; if not -> fall back to ASM
        for (Annotation ann : classType.getDeclaredAnnotations()) {
            AnnotationUtils.validateAnnotation(ann);
        }
        return new SourceClass(classType);
    }
    catch (Throwable ex) {
        // Enforce ASM via class name resolution
        return asSourceClass(classType.getName(), filter);
    }
}



/**
 * Factory method to obtain a {@link SourceClass} from a class name.
 * ASM获取类上注解的SourceClass
 */
SourceClass asSourceClass(@Nullable String className, Predicate<String> filter) throws IOException {
    //这里调用了上面定义的DEFAULT_EXCLUSION_FILTER,过滤掉java和spring的原生注解
    if (className == null || filter.test(className)) {
        //返回SourceClass(Object.class)
        return this.objectSourceClass;
    }
    //jdk中的类使用反射获取类上注解的SourceClass
    if (className.startsWith("java")) {
        // Never use ASM for core java types
        try {
            return new SourceClass(ClassUtils.forName(className, this.resourceLoader.getClassLoader()));
        }
        catch (ClassNotFoundException ex) {
            throw new NestedIOException("Failed to load class [" + className + "]", ex);
        }
    }
    //ASM获取类上注解的SourceClass
    return new SourceClass(this.metadataReaderFactory.getMetadataReader(className));
}
2.3.4.2解析@Import注解,获取需要导入的类的SourceClass

这个功能是由getImports()方法完成的

/**
 * Returns {@code @Import} class, considering all meta-annotations.
 * 这个方法返回了一个SourceClass集合
 */
private Set<SourceClass> getImports(SourceClass sourceClass) throws IOException {
    //@Import注解导入的类的SourceClass
    Set<SourceClass> imports = new LinkedHashSet<>();
    //递归已访问的SourceClass
    Set<SourceClass> visited = new LinkedHashSet<>();
    //解析sourceClass中@Import注解
    collectImports(sourceClass, imports, visited);
    return imports;
}

解析sourceClass@Import注解

/**
 * Recursively collect all declared {@code @Import} values. Unlike most
 * meta-annotations it is valid to have several {@code @Import}s declared with
 * different values; the usual process of returning values from the first
 * meta-annotation on a class is not sufficient.
 * 

For example, it is common for a {@code @Configuration} class to declare direct * {@code @Import}s in addition to meta-imports originating from an {@code @Enable} * annotation. * @param sourceClass the class to search * @param imports the imports collected so far * @param visited used to track visited classes to prevent infinite recursion * @throws IOException if there is any problem reading metadata from the named class */ private void collectImports(SourceClass sourceClass, Set<SourceClass> imports, Set<SourceClass> visited) throws IOException { /** * 这是使用的深度优先算法 * 它可以访问到当前sourceClass所有的注解 * 但是方法里面设置3个过滤规则,非java非spring原生注解非@Import注解 * 对于其它的注解都会获取注解的SourceClass,然后调用getAnnotationAttributes * 方法获取@Import注解信息 */ if (visited.add(sourceClass)) { /** * getAnnotations()方法见2.3.4.1 * 就是获取到所有非java非spring原生注解的SourceClass */ for (SourceClass annotation : sourceClass.getAnnotations()) { //当前注解的完全限定名 String annName = annotation.getMetadata().getClassName(); //当前注解不是@Import注解,就递归获取注解的注解 if (!annName.equals(Import.class.getName())) { collectImports(annotation, imports, visited); } } /** * getAnnotationAttributes()方法见2.3.4.1 * 就是获取@Import注解导入的类的SourceClass */ imports.addAll(sourceClass.getAnnotationAttributes(Import.class.getName(), "value")); } }

2.3.4.3 导入@Import注解指定的类(解析为BeanDefinition,等待统一实例化)
private void processImports(ConfigurationClass configClass, SourceClass currentSourceClass,
                            Collection<SourceClass> importCandidates, Predicate<String> exclusionFilter,
                            boolean checkForCircularImports) {

    //需要被导入的类集合为空直接返回
    if (importCandidates.isEmpty()) {
        return;
    }

    /**
     * checkForCircularImports为true表示检查循环导入
     * isChainedImportOnStack(configClass)	检查循环导入的方法
     */
    if (checkForCircularImports && isChainedImportOnStack(configClass)) {
        this.problemReporter.error(new CircularImportProblem(configClass, this.importStack));
    }
    else {
        //记录当前配置类,避免循环导入的问题
        this.importStack.push(configClass);
        try {
            //遍历需要被导入的类
            for (SourceClass candidate : importCandidates) {

                /*********************ImportSelector********************/
                //判断candidate是否是ImportSelector的子类,见2.3.4.1
                if (candidate.isAssignable(ImportSelector.class)) {
                    // Candidate class is an ImportSelector -> delegate to it to determine imports
                    //获得candidate的clazz对象,见2.3.4.1
                    Class<?> candidateClass = candidate.loadClass();

                    //(3-1)实例化ImportSelector
                    ImportSelector selector = ParserStrategyUtils.instantiateClass(candidateClass, ImportSelector.class,
                                                                                   this.environment, this.resourceLoader, this.registry);
                    Predicate<String> selectorFilter = selector.getExclusionFilter();
                    if (selectorFilter != null) {
                        //(3-2)合并两个exclusionFilter的过滤器
                        exclusionFilter = exclusionFilter.or(selectorFilter);
                    }
                    //(3-4)DeferredImportSelector,延迟导入
                    if (selector instanceof DeferredImportSelector) {
                        this.deferredImportSelectorHandler.handle(configClass, (DeferredImportSelector) selector);
                    }
                    //ImportSelector,不需要延迟导入
                    else {
                        //调用接口方法,获得所有需要导入类的完全限定名
                        String[] importClassNames = selector.selectImports(currentSourceClass.getMetadata());
                        //通过ASM获得指定完全限定名的SourceClass
                        Collection<SourceClass> importSourceClasses = asSourceClasses(importClassNames, exclusionFilter);
                        //递归调用处理@Import注解的方法
                        processImports(configClass, currentSourceClass, importSourceClasses, exclusionFilter, false);
                    }
                }

                /******************ImportBeanDefinitionRegistrar*****************/
                else if (candidate.isAssignable(ImportBeanDefinitionRegistrar.class)) {
                    // Candidate class is an ImportBeanDefinitionRegistrar ->
                    // delegate to it to register additional bean definitions
                    Class<?> candidateClass = candidate.loadClass();
                    //(3-1)实例化ImportBeanDefinitionRegistrar
                    ImportBeanDefinitionRegistrar registrar =
                        ParserStrategyUtils.instantiateClass(candidateClass, ImportBeanDefinitionRegistrar.class,
                                                             this.environment, this.resourceLoader, this.registry);
                    //(3-3)缓存ImportBeanDefinitionRegistrar到当前标注@Import注解配置类的ConfigurationClass上
                    configClass.addImportBeanDefinitionRegistrar(registrar, currentSourceClass.getMetadata());
                }

                /*********************普通的类*****************************/
                else {
                    // Candidate class not an ImportSelector or ImportBeanDefinitionRegistrar ->
                    // process it as an @Configuration class
                    /**
                     * 记录到importStack中
                     * ImportStack不仅本身继承对列,且里面包含了MultiValueMap imports属性
                     * 此方法就是以被导入类的完全限定名为key,来源类的AnnotationMetadata为value保存到imports属性中
                     * 最终,在2章节中将importStack保存到环境中
                     */
                    this.importStack.registerImport(
                        currentSourceClass.getMetadata(), candidate.getMetadata().getClassName());
                    //把被导入的类当成一个配置类进行处理,递归
                    //processConfigurationClass这个方法见2.3,它会处理被封装成ConfigurationClass的配置类
                    //asConfigClass()见2.3.1,会保存candidate配置类的来源类
                    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 {
            //@Import注解处理完成,就去掉当前配置类
            this.importStack.pop();
        }
    }
}


/**
 * 检查循环导入
 * 内部类上的@Import注解导入主类,报错
 */
private boolean isChainedImportOnStack(ConfigurationClass configClass) {
    //importStack你就把它看成一个map集合的存,key为配置类的完全限定名,value为该配置类的AnnotationMetadata(注解元数据)
    if (this.importStack.contains(configClass)) {
        //获取当前处理的配置类的完全限定名
        String configClassName = configClass.getMetadata().getClassName();
        //根据名字获取缓存中的AnnotationMetadata
        AnnotationMetadata importingClass = this.importStack.getImportingClassFor(configClassName);
        //判断缓存中的AnnotationMetadata和当前处理的是否对应
        while (importingClass != null) {
            if (configClassName.equals(importingClass.getClassName())) {
                return true;
            }
            importingClass = this.importStack.getImportingClassFor(importingClass.getClassName());
        }
    }
    return false;
}
(3-1)实例化ImportSelectorImportBeanDefinitionRegistrar
/**
 * Instantiate a class using an appropriate constructor and return the new
 * instance as the specified assignable type. The returned instance will
 * have {@link BeanClassLoaderAware}, {@link BeanFactoryAware},
 * {@link EnvironmentAware}, and {@link ResourceLoaderAware} contracts
 * invoked if they are implemented by the given object.
 * @since 5.2
 */
@SuppressWarnings("unchecked")
static <T> T instantiateClass(Class<?> clazz, Class<T> assignableTo, Environment environment,
                              ResourceLoader resourceLoader, BeanDefinitionRegistry registry) {

    Assert.notNull(clazz, "Class must not be null");
    Assert.isAssignable(assignableTo, clazz);
    if (clazz.isInterface()) {
        throw new BeanInstantiationException(clazz, "Specified class is an interface");
    }
    //获取类加载器
    ClassLoader classLoader = (registry instanceof ConfigurableBeanFactory ?
                               ((ConfigurableBeanFactory) registry).getBeanClassLoader() : resourceLoader.getClassLoader());
    /**
     * 选用合适的构造方法实例化
     * 什么叫合适的构造方法?
     * 它会根据这个4个对象(environment,resourceLoader,registry,classLoader)去最大程度上匹配构造方法
     */
    T instance = (T) createInstance(clazz, environment, resourceLoader, registry, classLoader);
    //执行这4个Aware接口方法
    ParserStrategyUtils.invokeAwareMethods(instance, environment, resourceLoader, registry, classLoader);
    return instance;
}
(3-2)合并两个exclusionFilter过滤器
/**
 * Evaluates this predicate on the given argument.
 *
 * @param t the input argument
 * @return {@code true} if the input argument matches the predicate,
 * otherwise {@code false}
 * Predicate接口的核心方法
 */
boolean test(T t);


/**
 * Returns a composed predicate that represents a short-circuiting logical
 * OR of this predicate and another.  When evaluating the composed
 * predicate, if this predicate is {@code true}, then the {@code other}
 * predicate is not evaluated.
 *
 * 

Any exceptions thrown during evaluation of either predicate are relayed * to the caller; if evaluation of this predicate throws an exception, the * {@code other} predicate will not be evaluated. * * @param other a predicate that will be logically-ORed with this * predicate * @return a composed predicate that represents the short-circuiting logical * OR of this predicate and the {@code other} predicate * @throws NullPointerException if other is null * 这是Predicate接口的有默认实现的方法 */ default Predicate<T> or(Predicate<? super T> other) { Objects.requireNonNull(other); //函数式编程创建的一个匿名类 //实际上就是当前调用or方法的过滤器和参数传入的过滤器的test方法,只要成立一个,匿名类的test方法就返回true return (t) -> { test(t) || other.test(t) }; }

(3-3)保存ImportBeanDefinitionRegistrar到当前标注@Import注解配置类的ConfigurationClass
//保存当前ImportBeanDefinitionRegistrar,等待后续处理
private final Map<ImportBeanDefinitionRegistrar, AnnotationMetadata> importBeanDefinitionRegistrars =
    new LinkedHashMap<>();

public void addImportBeanDefinitionRegistrar(ImportBeanDefinitionRegistrar registrar, AnnotationMetadata importingClassMetadata) {
    this.importBeanDefinitionRegistrars.put(registrar, importingClassMetadata);
}
(3-4)DeferredImportSelector,延迟导入

deferredImportSelectorHandlerConfigurationClassParser类的一个有默认值的属性

//延迟导入处理器
private final DeferredImportSelectorHandler deferredImportSelectorHandler = new DeferredImportSelectorHandler();

DeferredImportSelectorHandlerConfigurationClassParser的一个内部类

@Nullable
private List<DeferredImportSelectorHolder> deferredImportSelectors = new ArrayList<>();

/**
 * Handle the specified {@link DeferredImportSelector}. If deferred import
 * selectors are being collected, this registers this instance to the list. If
 * they are being processed, the {@link DeferredImportSelector} is also processed
 * immediately according to its {@link DeferredImportSelector.Group}.
 * @param configClass the source configuration class
 * @param importSelector the selector to handle
 */
public void handle(ConfigurationClass configClass, DeferredImportSelector importSelector) {
    //构建一个延迟导入配置类的持有者
    DeferredImportSelectorHolder holder = new DeferredImportSelectorHolder(configClass, importSelector);
    /**
     * 2.3.8处理延迟导入会将this.deferredImportSelectors置空
     * 说明此时已经在处理延迟导入了
     * 就不需要保存到延迟导入处理器中,而是直接处理
     * 具体的处理流程见2.3.8.2
     */
    if (this.deferredImportSelectors == null) {
        DeferredImportSelectorGroupingHandler handler = new DeferredImportSelectorGroupingHandler();
        handler.register(holder);
        handler.processGroupImports();
    }
    else {
        //保存到延迟导入处理器中,后续处理流程见2.3.8
        this.deferredImportSelectors.add(holder);
    }
}

总结@Import注解的处理流程如下:

  • 首先调用getImports(sourceClass)方法使用深度优先算法获取当前配置类所有@Import注解(会去查找注解的注解)导入类的SourceClass

  • 上面的方法处理完毕之后,会返回一个需要被导入的类的SourceClass集合,接下来就是调用processImports方法处理这些需要被导入的类了。处理流程也很简单,根据这些类的类型分为三类处理

    • 如果是ImportSelector接口的实现类,那么就直接使用ParserStrategyUtils.instantiateClass()方法实例化这个类,然后调用ImportSelector接口的selectImports方法获得这个导入器导入的类的完全限定名,得到完全限定名之后那就好办了,可以直接由asSourceClass方法获得对应的SourceClass,最后在递归接着调用processImports方法处理这些需要被导入的类。
    • 如果是ImportBeanDefinitionRegistrar接口的实现类,那么就直接使用ParserStrategyUtils.instantiateClass()方法实例化这个类,然后将对象保存到标注@Import注解配置类的ConfigurationClass对象的importBeanDefinitionRegistrars属性中,等待后续处理。
    • 如果没有实现上面两个接口,就表明这个类是一个普通的配置类,那么就递归重新走一遍处理配置类的流程(processConfigurationClass方法,见2.3)即可

2.3.5处理@ImportResource注解

//获取ImportResource注解的所有属性信息
AnnotationAttributes importResource =
    AnnotationConfigUtils.attributesFor(sourceClass.getMetadata(), ImportResource.class);
if (importResource != null) {
    //获取xml文件的路径
    String[] resources = importResource.getStringArray("locations");
    //获取指定的BeanDefinitionReader
    Class<? extends BeanDefinitionReader> readerClass = importResource.getClass("reader");
    for (String resource : resources) {
        //解析路径上的占位符
        String resolvedResource = this.environment.resolveRequiredPlaceholders(resource);
        //保存到ConfigurationClass中,等待后续处理
        configClass.addImportedResource(resolvedResource, readerClass);
    }
}

保存到ConfigurationClass中,等待后续处理

//key为路径,value为BeanDefinitionReader,到时候会使用这个reader来读取解析路径所对应的文件
private final Map<String, Class<? extends BeanDefinitionReader>> importedResources =
    new LinkedHashMap<>();

public void addImportedResource(String importedResource, Class<? extends BeanDefinitionReader> readerClass) {
    this.importedResources.put(importedResource, readerClass);
}

2.3.6处理@Bean注解

// Process individual @Bean methods
//获取所有@Bean方法
Set<MethodMetadata> beanMethods = retrieveBeanMethodMetadata(sourceClass);
for (MethodMetadata methodMetadata : beanMethods) {
    //2.3.6.3保存到配置类的ConfigurationClass中等候统一处理
    configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));
}

// Process default methods on interfaces
//2.3.6.4处理配置类接口有默认实现的@Bean方法
processInterfaces(configClass, sourceClass);

获取所有@Bean方法

/**
 * Retrieve the metadata for all @Bean methods.
 */
private Set<MethodMetadata> retrieveBeanMethodMetadata(SourceClass sourceClass) {
    //获取当前配置类的注解元数据
    AnnotationMetadata original = sourceClass.getMetadata();
    //2.3.6.1获取配置类中有@Bean注解的方法元数据
    Set<MethodMetadata> beanMethods = original.getAnnotatedMethods(Bean.class.getName());
    //2.3.6.2对标准反射获取的方法元数据进行排序
    if (beanMethods.size() > 1 && original instanceof StandardAnnotationMetadata) {
        // Try reading the class file via ASM for deterministic declaration order...
        // Unfortunately, the JVM's standard reflection returns methods in arbitrary
        // order, even between different runs of the same application on the same JVM.
        try {
            AnnotationMetadata asm =
                this.metadataReaderFactory.getMetadataReader(original.getClassName()).getAnnotationMetadata();
            Set<MethodMetadata> asmMethods = asm.getAnnotatedMethods(Bean.class.getName());
            if (asmMethods.size() >= beanMethods.size()) {
                Set<MethodMetadata> selectedMethods = new LinkedHashSet<>(asmMethods.size());
                for (MethodMetadata asmMethod : asmMethods) {
                    for (MethodMetadata beanMethod : beanMethods) {
                        if (beanMethod.getMethodName().equals(asmMethod.getMethodName())) {
                            selectedMethods.add(beanMethod);
                            break;
                        }
                    }
                }
                if (selectedMethods.size() == beanMethods.size()) {
                    // All reflection-detected methods found in ASM method set -> proceed
                    beanMethods = selectedMethods;
                }
            }
        }
        catch (IOException ex) {
            logger.debug("Failed to read class file via ASM for determining @Bean method order", ex);
            // No worries, let's continue with the reflection metadata we started with...
        }
    }
    return beanMethods;
}
2.3.6.1获取配置类中有@Bean注解的方法元数据
@Override
public Set<MethodMetadata> getAnnotatedMethods(String annotationName) {
    Set<MethodMetadata> annotatedMethods = null;
    for (MethodMetadata annotatedMethod : this.annotatedMethods) {
        //判断方法上的注解是不是annotationName
        if (annotatedMethod.isAnnotated(annotationName)) {
            if (annotatedMethods == null) {
                annotatedMethods = new LinkedHashSet<>(4);
            }
            annotatedMethods.add(annotatedMethod);
        } 
    }
    return annotatedMethods != null ? annotatedMethods : Collections.emptySet();
}

方法很简单,但是我们需要看一下MethodMetadata这个接口,它是spring内部定义的描述方法的接口,spring对接口提供两套实现,一种是使用反射来获取方法信息,另一种是ASM来实现,具体的实现原理,这里不再深究,只需要知道这个接口有什么作用,能够做啥就行。

直接看类图

spring--6--spring之ConfigurationClassPostProcessor源码_第2张图片

2.3.6.2对标准反射获取的MethodMetadata(方法元数据)进行排序

jvm标准反射会以任意的顺序返回MethodMetadata,即使是在同一jvm和同一应用程序中。

ASM则不相同,所以在这里会通过ASM获取有@Bean注解的方法,和反射获取的MethodMetadata进行对比,以ASM获取的为基准排序。

2.3.6.3保存到配置类的ConfigurationClass中等候统一处理
//BeanMethod代表配置类中的一个@Bean标注方法的包装
configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));

@Bean标注的方法保存到ConfigurationClassbeanMethods属性中

private final Set<BeanMethod> beanMethods = new LinkedHashSet<>();

public void addBeanMethod(BeanMethod method) {
   this.beanMethods.add(method);
}
2.3.6.4处理配置类接口有默认实现的@Bean方法
/**
 * Register default methods on interfaces implemented by the configuration class.
 */
private void processInterfaces(ConfigurationClass configClass, SourceClass sourceClass) throws IOException {
    //获取配置类所有接口的SourceClass,见2.3.4.1
    for (SourceClass ifc : sourceClass.getInterfaces()) {
        //获取ifc中有@Bean注解的方法元数据,见2.3.6.1
        Set<MethodMetadata> beanMethods = retrieveBeanMethodMetadata(ifc);
        for (MethodMetadata methodMetadata : beanMethods) {
            //非抽象方法就保存到配置类的ConfigurationClass对象中,见2.3.6.3
            if (!methodMetadata.isAbstract()) {
                // A default method or other concrete method on a Java 8+ interface...
                configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));
            }
        }
        //递归处理接口的接口
        processInterfaces(configClass, ifc);
    }
}

2.3.7如果有父类,返回当前配置类的父类重复处理流程

//如果有父类
if (sourceClass.getMetadata().hasSuperClass()) {
    //获取父类的完全限定名
    String superclass = sourceClass.getMetadata().getSuperClassName();
    //父类不能为jdk中的类
    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
//没有父类,返回null,while条件判断直接终止
return null;

总结

  • 一个类只会被处理一次,无论它被多少个配置类继承。
  • 不会处理jdk中的类。

2.3.8延迟处理@Import注解导入的DeferredImportSelector

此处处理衔接2.3.4.3(3-4),也就是说这个接口的实现类,会在所有配置类解析完成后再进行处理。

2.3.8.1延迟导入所涉及的类

下面所有类均为ConfigurationClassParser的内部类

延迟导入选择器持有者

private static class DeferredImportSelectorHolder {

    //标注@Import注解的配置
    private final ConfigurationClass configurationClass;

    //延迟导入选择器对象
    private final DeferredImportSelector importSelector;

    public DeferredImportSelectorHolder(ConfigurationClass configClass, DeferredImportSelector selector) {
        this.configurationClass = configClass;
        this.importSelector = selector;
    }
    //省略两属性的get方法
}

延迟导入处理器

private class DeferredImportSelectorHandler {

    @Nullable
    private List<DeferredImportSelectorHolder> deferredImportSelectors = new ArrayList<>();

    /**
     * Handle the specified {@link DeferredImportSelector}. If deferred import
     * selectors are being collected, this registers this instance to the list. If
     * they are being processed, the {@link DeferredImportSelector} is also processed
     * immediately according to its {@link DeferredImportSelector.Group}.
     * @param configClass the source configuration class
     * @param importSelector the selector to handle
     * 这个方法过程见2.3.4.3(3-4)
     * 调用方法的时候,如果已经开始处理延迟导入,就直接处理,和process流程差不多
     * 如果没有,就将它添加到等候处理的列表中
     */
    public void handle(ConfigurationClass configClass, DeferredImportSelector importSelector) {
        //省略实现
    }

    /**
     * 处理DeferredImportSelector
     */
    public void process() {
        //省略实现
    }
}

延迟导入选择器组处理器

private class DeferredImportSelectorGroupingHandler {

    private final Map<Object, DeferredImportSelectorGrouping> groupings = new LinkedHashMap<>();

    //保存了延迟导入选择器来源的配置类的注解元数据和ConfigurationClass
    private final Map<AnnotationMetadata, ConfigurationClass> configurationClasses = new HashMap<>();

    //将延迟导入选择器持有者注册到指定的分组中
    public void register(DeferredImportSelectorHolder deferredImport) {
        //调用DeferredImportSelector接口getImportGroup()方法获取指定的分组
        Class<? extends Group> group = deferredImport.getImportSelector().getImportGroup();
        /**
         * computeIfAbsent(k,Function) 如果map集合中存在k,就返回k对应的值,否则将接口方法的
         * 返回值作为value保存到集合中,并返回value
         */
        DeferredImportSelectorGrouping grouping = this.groupings.computeIfAbsent(
            (group != null ? group : deferredImport),
            key -> new DeferredImportSelectorGrouping(createGroup(group)));
        grouping.add(deferredImport);
        //保存来源类的注解元数据和ConfigurationClass
        this.configurationClasses.put(deferredImport.getConfigurationClass().getMetadata(),
                                      deferredImport.getConfigurationClass());
    }

    public void processGroupImports() {
        //遍历组,按组导入
        for (DeferredImportSelectorGrouping grouping : this.groupings.values()) {
            //获取当前分组合并后的exclusionFilter
            Predicate<String> exclusionFilter = grouping.getCandidateFilter();
            //遍历所有需要被导入的Entry
            grouping.getImports().forEach(entry -> {
                //获取来源类的ConfigurationClass
                ConfigurationClass configurationClass = this.configurationClasses.get(entry.getMetadata());
                try {
                    //这个就是2.3.4.3的处理@Import注解指定类的方法
                    //也就是说延迟导入的类,又重新走一遍处理@Import注解的流程
                    processImports(configurationClass, asSourceClass(configurationClass, exclusionFilter),
                                   Collections.singleton(asSourceClass(entry.getImportClassName(), exclusionFilter)),
                                   exclusionFilter, false);
                }
                catch (BeanDefinitionStoreException ex) {
                    throw ex;
                }
                catch (Throwable ex) {
                    throw new BeanDefinitionStoreException(
                        "Failed to process import candidates for configuration class [" +
                        configurationClass.getMetadata().getClassName() + "]", ex);
                }
            });
        }
    }

    //创建Group对象
    private Group createGroup(@Nullable Class<? extends Group> type) {
        //获取有效的Group
        Class<? extends Group> effectiveType = (type != null ? type : DefaultDeferredImportSelectorGroup.class);
        //又是这个类的方法实例化Group对象,见2.3.4.3(3-1)
        return ParserStrategyUtils.instantiateClass(effectiveType, Group.class,
                                                    ConfigurationClassParser.this.environment,
                                                    ConfigurationClassParser.this.resourceLoader,
                                                    ConfigurationClassParser.this.registry);
    }
}

延迟导入选择器组

//表示当前分组有哪些延迟导入选择器持有者
//这个类主要就是为了包装Group
private static class DeferredImportSelectorGrouping {


    //ConfigurationClassParser自带一个DefaultDeferredImportSelectorGroup内部类
    //DefaultDeferredImportSelectorGroup自带的默认分组,用户可以自己实现该接口,创建新的分组
    private final DeferredImportSelector.Group group;

    //当前分组中包含的延迟导入选择器持有者
    private final List<DeferredImportSelectorHolder> deferredImports = new ArrayList<>();

    DeferredImportSelectorGrouping(Group group) {
        this.group = group;
    }

    //为当前分组添加DeferredImportSelectorHolder
    public void add(DeferredImportSelectorHolder deferredImport) {
        this.deferredImports.add(deferredImport);
    }

    /**
     * Return the imports defined by the group.
     * @return each import with its associated configuration class
     * 获取当前分组的所有Entry
     * Entry中只有两个属性
     * AnnotationMetadata metadata 标注@Import注解配置类的注解元数据
     * String importClassName 通过延迟导入选择器导入的某个类的完全限定名
     */
    public Iterable<Group.Entry> getImports() {
        for (DeferredImportSelectorHolder deferredImport : this.deferredImports) {
            //见下面默认分组的实现
            //用户可以自定义实现对配置类的AnnotationMetadata做点什么
            this.group.process(deferredImport.getConfigurationClass().getMetadata(),
                               deferredImport.getImportSelector());
        }
        //process和selectImports是配套的
        return this.group.selectImports();
    }

    /**
     * 合并当前分组中所有延迟导入选择器的exclusionFilter
     */
    public Predicate<String> getCandidateFilter() {
        /**
         * 默认的exclusionFilter
         * 实际上就是排除java.lang.annotation开头和org.springframework.stereotype开头的类
         */
        Predicate<String> mergedFilter = DEFAULT_EXCLUSION_FILTER;
        //遍历当前分组中所有延迟导入选择器
        for (DeferredImportSelectorHolder deferredImport : this.deferredImports) {
            //获取延迟导入选择器的exclusionFilter(用户自定义的)
            Predicate<String> selectorFilter = deferredImport.getImportSelector().getExclusionFilter();
            if (selectorFilter != null) {
                //合并,见2.3.4.3(3-2)
                mergedFilter = mergedFilter.or(selectorFilter);
            }
        }
        return mergedFilter;
    }
}

默认的分组

private static class DefaultDeferredImportSelectorGroup implements Group {

    private final List<Entry> imports = new ArrayList<>();

    //构建一个Entry对象,然后缓存
    @Override
    public void process(AnnotationMetadata metadata, DeferredImportSelector selector) {
        for (String importClassName : selector.selectImports(metadata)) {
            this.imports.add(new Entry(metadata, importClassName));
        }
    }

    //返回缓存的Entry
    @Override
    public Iterable<Entry> selectImports() {
        return this.imports;
    }
}
2.3.8.2延迟导入处理流程

核心是DeferredImportSelectorHandler类的process方法

public void process() {
    //取出缓存在ConfigurationClassParser的DeferredImportSelectorHolder
    List<DeferredImportSelectorHolder> deferredImports = this.deferredImportSelectors;
    //这里置空,和handle方法对应了
    this.deferredImportSelectors = null;
    try {
        if (deferredImports != null) {
            DeferredImportSelectorGroupingHandler handler = new DeferredImportSelectorGroupingHandler();
            //排序
            deferredImports.sort(DEFERRED_IMPORT_COMPARATOR);
            //遍历调用register方法注册
            deferredImports.forEach(handler::register);
            //分组处理导入
            handler.processGroupImports();
        }
    }
    finally {
        //方法返回前,创建一个空的集合
        this.deferredImportSelectors = new ArrayList<>();
    }
}

我们看一下是如何进行排序的

  • 使用的是集合的排序方法,传入比较规则
private static final Comparator<DeferredImportSelectorHolder> DEFERRED_IMPORT_COMPARATOR =
    (o1, o2) -> AnnotationAwareOrderComparator.INSTANCE.compare(o1.getImportSelector(), o2.getImportSelector());
  • 核心compare方法
@Override
public int compare(@Nullable Object o1, @Nullable Object o2) {
    return doCompare(o1, o2, null);
}

private int doCompare(@Nullable Object o1, @Nullable Object o2, @Nullable OrderSourceProvider sourceProvider) {
    //实现了PriorityOrdered接口的优先级最高
    boolean p1 = (o1 instanceof PriorityOrdered);
    boolean p2 = (o2 instanceof PriorityOrdered);
    //两个中只有一个实现了PriorityOrdered接口
    if (p1 && !p2) {
        return -1;
    }
    else if (p2 && !p1) {
        return 1;
    }

    //获取PriorityOrdered接口或Ordered接口的或@Order注解的优先级值
    int i1 = getOrder(o1, sourceProvider);
    int i2 = getOrder(o2, sourceProvider);
    return Integer.compare(i1, i2);
}

延迟导入处理流程总结

  • 首先是扫描到配置类上的@Import注解,实例化之后发现注解导入的类是一个DeferredImportSelector(延迟导入选择器)。
  • DeferredImportSelector对象保存到ConfigurationClassParserdeferredImportSelectorHandler属性对象中,等待所有配置类解析完成后处理。
  • 所有配置类解析完成,ConfigurationClassParser对象就会调用内部属性对象的deferredImportSelectorHandler.process()方法,分组处理延迟导入。

2.4校验所有解析好的配置类

/**
 * Validate each {@link ConfigurationClass} object.
 * @see ConfigurationClass#validate
 */
public void validate() {
    //校验每一个ConfigurationClass对象
    for (ConfigurationClass configClass : this.configurationClasses.keySet()) {
        configClass.validate(this.problemReporter);
    }
}

校验每一个ConfigurationClass对象

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注解,且proxyBeanMethods属性值为true
    if (attributes != null && (Boolean) attributes.get("proxyBeanMethods")) {
        //不能是final类
        if (this.metadata.isFinal()) {
            problemReporter.error(new FinalConfigurationProblem());
        }
        //且需要校验该配置类中每一个BeanMethod对象
        for (BeanMethod beanMethod : this.beanMethods) {
            beanMethod.validate(problemReporter);
        }
    }
}

校验该配置类中每一个BeanMethod对象,实际上就是@Bean方法对象

@Override
public void validate(ProblemReporter problemReporter) {
    //静态@Bean方法无需校验
    if (getMetadata().isStatic()) {
        // static @Bean methods have no constraints to validate -> return immediately
        return;
    }

    /**
     * 普通@Bean方法必须可以被重写,应为proxyBeanMethods属性值为true,需要创建代理
     * 如何判断方法可以被重写,其实就是判断方法非final,非static,非private
     */
    if (this.configurationClass.getMetadata().isAnnotated(Configuration.class.getName())) {
        if (!getMetadata().isOverridable()) {
            // instance @Bean methods within @Configuration classes must be overridable to accommodate CGLIB
            problemReporter.error(new NonOverridableMethodError());
        }
    }
}

校验总结

  • 只会校验有@Configuration注解,且proxyBeanMethods属性值为true的配置类。
  • 被校验的配置类不能是final,因为需要使用CGLIB代理。
  • 还会校验配置类中所有的@Bean方法。
  • @Bean方法如果不是静态的,就必须可以被重写。

2.5使用ConfigurationClassBeanDefinitionReader加载ConfigurationClass中的BeanDefinition

/**
 * Read {@code configurationModel}, registering bean definitions
 * with the registry based on its contents.
 */
public void loadBeanDefinitions(Set<ConfigurationClass> configurationModel) {
    TrackedConditionEvaluator trackedConditionEvaluator = new TrackedConditionEvaluator();
    //加载每一个ConfigurationClass中的BeanDefinition
    for (ConfigurationClass configClass : configurationModel) {
        loadBeanDefinitionsForConfigurationClass(configClass, trackedConditionEvaluator);
    }
}

加载每一个ConfigurationClass中的BeanDefinition

/**
 * Read a particular {@link ConfigurationClass}, registering bean definitions
 * for the class itself and all of its {@link Bean} methods.
 */
private void loadBeanDefinitionsForConfigurationClass(
    ConfigurationClass configClass, TrackedConditionEvaluator trackedConditionEvaluator) {

    //@Conditional注解处理
    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;
    }

    /**
     * 2.5.1当前配置类是被别的配置类导入的(内部类或@Import注解)
     * 这里很有意思,它只处理被别的配置类导入的ConfigurationClass,为什么不是所有的都处理呢
     * 首先你得明白一点,如果当前配置类不是被别的配置类导入的,那么它的来源有哪几种呢?
     * 第一种,XML文件中的bean标签定义,ClassPathXmlApplicationContext中的setConfigLocation方法指定XML文件位置
     * 第二种,AnnotationConfigApplicationContext中的register方法指定配置类
     * 只有这两种,并且spring在ConfigurationClassPostProcessor执行前已经生成BeanDefinition了
     * 别的比如@ComponentScan扫描到的配置类和@Import注解导入的配置类均会记录其来源类
     */
    if (configClass.isImported()) {
        registerBeanDefinitionForImportedConfigurationClass(configClass);
    }

    //2.5.2处理@Bean方法
    for (BeanMethod beanMethod : configClass.getBeanMethods()) {
        loadBeanDefinitionsForBeanMethod(beanMethod);
    }

    //2.5.3处理@ImportResource注解导入的资源
    loadBeanDefinitionsFromImportedResources(configClass.getImportedResources());

    //2.5.4处理@Import注解导入的ImportBeanDefinitionRegistrar
    loadBeanDefinitionsFromRegistrars(configClass.getImportBeanDefinitionRegistrars());
}

2.5.1当前配置类是被别的配置类导入的(内部类或@Import注解)

/**
 * Register the {@link Configuration} class itself as a bean definition.
 */
private void registerBeanDefinitionForImportedConfigurationClass(ConfigurationClass configClass) {
    AnnotationMetadata metadata = configClass.getMetadata();
    
    //2.5.1.1根据置类的AnnotationMetadata创建一个BeanDefinition
    AnnotatedGenericBeanDefinition configBeanDef = new AnnotatedGenericBeanDefinition(metadata);

    //2.5.1.2解析配置类上的@Scope注解
    ScopeMetadata scopeMetadata = scopeMetadataResolver.resolveScopeMetadata(configBeanDef);
    configBeanDef.setScope(scopeMetadata.getScopeName());
    //2.5.1.3生成当前配置类的BeanName
    String configBeanName = this.importBeanNameGenerator.generateBeanName(configBeanDef, this.registry);
    //2.5.1.4处理一些公共的注解
    AnnotationConfigUtils.processCommonDefinitionAnnotations(configBeanDef, metadata);

    BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(configBeanDef, configBeanName);
    //2.5.1.5应用@Scope注解指定的代理模式(是否创建代理的BeanDefinition)
    definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
    //2.5.1.6将beanName和BeanDefinition注册到容器中
    this.registry.registerBeanDefinition(definitionHolder.getBeanName(), definitionHolder.getBeanDefinition());
    //将生成当beanName保存到ConfigurationClass中
    configClass.setBeanName(configBeanName);

    if (logger.isTraceEnabled()) {
        logger.trace("Registered bean definition for imported class '" + configBeanName + "'");
    }
}
2.5.1.1根据配置类的AnnotationMetadata创建一个BeanDefinition

在构造方法中解析出配置类的完全限定名,并保存

/**
 * Create a new AnnotatedGenericBeanDefinition for the given annotation metadata,
 * allowing for ASM-based processing and avoidance of early loading of the bean class.
 * Note that this constructor is functionally equivalent to
 * {@link org.springframework.context.annotation.ScannedGenericBeanDefinition
 * ScannedGenericBeanDefinition}, however the semantics of the latter indicate that a
 * bean was discovered specifically via component-scanning as opposed to other means.
 * @param metadata the annotation metadata for the bean class in question
 * @since 3.1.1
 */
public AnnotatedGenericBeanDefinition(AnnotationMetadata metadata) {
    Assert.notNull(metadata, "AnnotationMetadata must not be null");
    //标准反射,获取当前类的完全限定名
    if (metadata instanceof StandardAnnotationMetadata) {
        setBeanClass(((StandardAnnotationMetadata) metadata).getIntrospectedClass());
    }
    //ASM,获取当前类的完全限定名
    else {
        setBeanClassName(metadata.getClassName());
    }
    this.metadata = metadata;
}
2.5.1.2解析配置类上的@Scope注解

ConfigurationClassBeanDefinitionReader默认使用的ScopeMetadataResolver就是AnnotationScopeMetadataResolver

private static final ScopeMetadataResolver scopeMetadataResolver = new AnnotationScopeMetadataResolver();

它是专门用来解析@Scope注解的,具体如何解析,在解析@ComponentScan注解的时候已经说过了,见2.3.3.5(5-2)

2.5.1.3生成当前配置类的BeanName
String configBeanName = this.importBeanNameGenerator.generateBeanName(configBeanDef, this.registry);

首先这个importBeanNameGenerator是通过ConfigurationClassBeanDefinitionReader的构造函数赋值的,真正的对象是在ConfigurationClassPostProcessor中定义的

/* Using fully qualified class names as default bean names by default. */
private BeanNameGenerator importBeanNameGenerator = IMPORT_BEAN_NAME_GENERATOR;

/**
 * A {@code BeanNameGenerator} using fully qualified class names as default bean names.
 * 

This default for configuration-level import purposes may be overridden through * {@link #setBeanNameGenerator}. Note that the default for component scanning purposes * is a plain {@link AnnotationBeanNameGenerator#INSTANCE}, unless overridden through * {@link #setBeanNameGenerator} with a unified user-level bean name generator. * @since 5.2 * @see #setBeanNameGenerator */ public static final AnnotationBeanNameGenerator IMPORT_BEAN_NAME_GENERATOR = new FullyQualifiedAnnotationBeanNameGenerator();

显然,此时生成的是完全限定名。

2.5.1.4处理一些公共的注解

这个方法很简单,就是将这几个注解(@Lazy@Primary@DependsOn@Role@Description)解析,然后将值设置到BeanDefinition中。

这个方法在解析@ComponentScan注解的时候已经说过了,见2.3.3.5(5-5)

2.5.1.5应用@Scope注解指定的代理模式(是否创建代理的BeanDefinition)

这个方法在解析@ComponentScan注解的时候已经说过了,见2.3.3.5(5-7)

2.5.1.6将beanNameBeanDefinition注册到容器中

要想理解这个方法,首先的明白BeanDefinition的继承关系

spring--6--spring之ConfigurationClassPostProcessor源码_第3张图片

总结

  • 所有的BeanDefinition都继承了AbstractBeanDefinition
  • 加载xml中定义的bean生成的是GenericBeanDefinition
  • @ComponentScan注解扫描生成的是ScannedGenericBeanDefinition
  • @Import注解导入和配置类的内部类生成的是AnnotatedGenericBeanDefinition
  • @Bean方法生成的是ConfigurationClassBeanDefinition
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
    throws BeanDefinitionStoreException {

    Assert.hasText(beanName, "Bean name must not be empty");
    Assert.notNull(beanDefinition, "BeanDefinition must not be null");

    /**
     * 方法重写和工厂方法不能同时存在
     * 但是这个BeanFactoryPostProcessor没有获取@Lookup注解的功能
     * 所以此时校验BeanDefinition相当于什么也没干
     */ 
    if (beanDefinition instanceof AbstractBeanDefinition) {
        try {
            ((AbstractBeanDefinition) beanDefinition).validate();
        }
        catch (BeanDefinitionValidationException ex) {
            throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
                                                   "Validation of bean definition failed", ex);
        }
    }

    //容器中已存在该名字对应的BeanDefinition
    BeanDefinition existingDefinition = this.beanDefinitionMap.get(beanName);
    if (existingDefinition != null) {
        
        //allowBeanDefinitionOverriding默认为true,表示允许BeanDefinition覆盖
        if (!isAllowBeanDefinitionOverriding()) {
            throw new BeanDefinitionOverrideException(beanName, beanDefinition, existingDefinition);
        }
        
        //容器中的BeanDefinition角色优先级低于当前BeanDefinition,允许BeanDefinition覆盖
        else if (existingDefinition.getRole() < beanDefinition.getRole()) {
            // e.g. was ROLE_APPLICATION, now overriding with ROLE_SUPPORT or ROLE_INFRASTRUCTURE
            if (logger.isInfoEnabled()) {
                logger.info("Overriding user-defined bean definition for bean '" + beanName +
                            "' with a framework-generated bean definition: replacing [" +
                            existingDefinition + "] with [" + beanDefinition + "]");
            }
        }
        
         //两个BeanDefinition对象不相同,允许BeanDefinition覆盖
        else if (!beanDefinition.equals(existingDefinition)) {
            if (logger.isDebugEnabled()) {
                logger.debug("Overriding bean definition for bean '" + beanName +
                             "' with a different definition: replacing [" + existingDefinition +
                             "] with [" + beanDefinition + "]");
            }
        }
        
        //同时不满足上述三条件,也允许BeanDefinition覆盖
        else {
            if (logger.isTraceEnabled()) {
                logger.trace("Overriding bean definition for bean '" + beanName +
                             "' with an equivalent definition: replacing [" + existingDefinition +
                             "] with [" + beanDefinition + "]");
            }
        }
        //覆盖BeanDefinition
        this.beanDefinitionMap.put(beanName, beanDefinition);
    }
    
    //容器中不存在该名字对应的BeanDefinition
    else {
        /**
         * 判断容器中是否已经为BeanDefinition创建对象了
         * 使用getBean方法创建对象的时候,会将已经创建成功的对象保存到工厂内部属性alreadyCreated中
         * 此处方法就是直接检测alreadyCreated中元素个数是否为0
         * 此时已经调用了getBean方法实例化ConfigurationClassPostProcessor
         */
        if (hasBeanCreationStarted()) {
            // Cannot modify startup-time collection elements anymore (for stable iteration)
            //容器已经开始创建bean了,此时就得加锁,不能随意添加
            synchronized (this.beanDefinitionMap) {
                this.beanDefinitionMap.put(beanName, beanDefinition);
                List<String> updatedDefinitions = new ArrayList<>(this.beanDefinitionNames.size() + 1);
                updatedDefinitions.addAll(this.beanDefinitionNames);
                updatedDefinitions.add(beanName);
                this.beanDefinitionNames = updatedDefinitions;
                removeManualSingletonName(beanName);
            }
        }
        //容器还未开始创建bean,此时可以直接添加
        else {
            // Still in startup registration phase
            this.beanDefinitionMap.put(beanName, beanDefinition);
            this.beanDefinitionNames.add(beanName);
            /**
             * 如果当前beanName是工厂内部的Bean(environment,systemProperty,systemEnvironment)
             * 就从列表中去掉该beanName
             */
            removeManualSingletonName(beanName);
        }
        //将该属性置空,表明此时不冻结容器中的BeanDefinition(增删改操作)
        this.frozenBeanDefinitionNames = null;
    }

    //containsSingleton方法判断容器单例对象池中是否包含beanName对应的对象
    if (existingDefinition != null || containsSingleton(beanName)) {
        //重置该beanName对应的BeanDefinition
        resetBeanDefinition(beanName);
    }
    else if (isConfigurationFrozen()) {
        //清空所有类型映射的缓存
        clearByTypeCache();
    }
}

重置该beanName对应的BeanDefinition

  • 重置只会删除容器中的缓存,也就是除beanDefinitionNamesbeanDefinitionMap之外的一切相关的全部删除
/**
 * Reset all bean definition caches for the given bean,
 * including the caches of beans that are derived from it.
 * 

Called after an existing bean definition has been replaced or removed, * triggering {@link #clearMergedBeanDefinition}, {@link #destroySingleton} * and {@link MergedBeanDefinitionPostProcessor#resetBeanDefinition} on the * given bean and on all bean definitions that have the given bean as parent. * @param beanName the name of the bean to reset * @see #registerBeanDefinition * @see #removeBeanDefinition */ protected void resetBeanDefinition(String beanName) { // Remove the merged bean definition for the given bean, if already created. //删除容器中beanName对应的已经合并的BeanDefinition clearMergedBeanDefinition(beanName); // Remove corresponding bean from singleton cache, if any. Shouldn't usually // be necessary, rather just meant for overriding a context's default beans // (e.g. the default StaticMessageSource in a StaticApplicationContext). //删除单例对象池中的对象,会删除一二三即缓存,并调用销毁方法(DisposableBean接口方法) destroySingleton(beanName); // Notify all post-processors that the specified bean definition has been reset. //resetBeanDefinition方法通知该beanName对应的BeanDefinition已经重置 for (BeanPostProcessor processor : getBeanPostProcessors()) { if (processor instanceof MergedBeanDefinitionPostProcessor) { ((MergedBeanDefinitionPostProcessor) processor).resetBeanDefinition(beanName); } } // Reset all bean definitions that have the given bean as parent (recursively). //递归,重置所有依赖该bean的BeanDefinition for (String bdName : this.beanDefinitionNames) { if (!beanName.equals(bdName)) { BeanDefinition bd = this.beanDefinitionMap.get(bdName); // Ensure bd is non-null due to potential concurrent modification of beanDefinitionMap. if (bd != null && beanName.equals(bd.getParentName())) { resetBeanDefinition(bdName); } } } }

2.5.2处理@Bean方法

/**
 * Read the given {@link BeanMethod}, registering bean definitions
 * with the BeanDefinitionRegistry based on its contents.
 */
@SuppressWarnings("deprecation")  // for RequiredAnnotationBeanPostProcessor.SKIP_REQUIRED_CHECK_ATTRIBUTE
private void loadBeanDefinitionsForBeanMethod(BeanMethod beanMethod) {
    //获取@Bean方法所在配置类的ConfigurationClass
    ConfigurationClass configClass = beanMethod.getConfigurationClass();
    //获取@Bean方法的MethodeMetadata
    MethodMetadata metadata = beanMethod.getMetadata();
    //获取方法名
    String methodName = metadata.getMethodName();

    /**********************@Conditional注解处理********************/
    // 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
    //获取用户在@Bean注解上指定的名字
    List<String> names = new ArrayList<>(Arrays.asList(bean.getStringArray("name")));
    //第一个是beanName,其余的都是别名
    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)?
    /**
     * 2.5.2.1判断容器中是否已经存在该beanName对应的BeanDefinition
     */
    if (isOverriddenByExistingDefinition(beanMethod, beanName)) {
        //@Bean注解注册的名字不能是配置类的名字
        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!");
        }
        //跳过后面@Bean解析流程,不覆盖BeanDefinition了
        return;
    }

    //2.5.2.2构造ConfigurationClassBeanDefinition
    ConfigurationClassBeanDefinition beanDef = new ConfigurationClassBeanDefinition(configClass, metadata, beanName);
    /**
     * this.sourceExtractor实际就是PassThroughSourceExtractor
     * 它是SourceExtractor的一个简单实现(直接返回metadata)
     * 这个接口的extractSource方法允许在获得源元数据之前对它进行修改
     */
    beanDef.setSource(this.sourceExtractor.extractSource(metadata, configClass.getResource()));

    //静态@Bean方法
    if (metadata.isStatic()) {
        // static @Bean method
        //根据配置类AnnotationMetadata的获得类型,获取配置类的clazz或完全限定名
        if (configClass.getMetadata() instanceof StandardAnnotationMetadata) {
            beanDef.setBeanClass(((StandardAnnotationMetadata) configClass.getMetadata()).getIntrospectedClass());
        }
        else {
            beanDef.setBeanClassName(configClass.getMetadata().getClassName());
        }
        //设置工厂方法名
        beanDef.setUniqueFactoryMethodName(methodName);
    }
    //非静态@Bean方法
    else {
        // instance @Bean method
        beanDef.setFactoryBeanName(configClass.getBeanName());
        beanDef.setUniqueFactoryMethodName(methodName);
    }

    //配置类通过反射解析
    if (metadata instanceof StandardMethodMetadata) {
        //反射获取方法对象,并设置到BeanDefinition中
        beanDef.setResolvedFactoryMethod(((StandardMethodMetadata) metadata).getIntrospectedMethod());
    }

    //设置自动注入的默认模式为构造方法自动注入
    beanDef.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_CONSTRUCTOR);
    //兼容@Required注解,在spring5.1中已经废弃了该注解
    beanDef.setAttribute(org.springframework.beans.factory.annotation.RequiredAnnotationBeanPostProcessor.
                         SKIP_REQUIRED_CHECK_ATTRIBUTE, Boolean.TRUE);

    /**
     * 处理一些公共注解,见2.3.3.5(5-5)
     * @Lazy、@Primary、@DependsOn、@Role、@Description
     */
    AnnotationConfigUtils.processCommonDefinitionAnnotations(beanDef, metadata);

    //设置@Bean注解上指定的自动注入模式,在spring5.1中已经废弃了该属性
    Autowire autowire = bean.getEnum("autowire");
    if (autowire.isAutowire()) {
        beanDef.setAutowireMode(autowire.value());
    }

    //该bean是否作为自动注入的候选bean
    boolean autowireCandidate = bean.getBoolean("autowireCandidate");
    if (!autowireCandidate) {
        beanDef.setAutowireCandidate(false);
    }

    //设置@Bean注解上指定的初始化方法名
    String initMethodName = bean.getString("initMethod");
    if (StringUtils.hasText(initMethodName)) {
        beanDef.setInitMethodName(initMethodName);
    }

    //设置@Bean注解上指定的销毁方法名
    String destroyMethodName = bean.getString("destroyMethod");
    beanDef.setDestroyMethodName(destroyMethodName);

    // Consider scoping
    //解析@Scope注解,并设置到BeanDefinition中,此处不是通过ScopeMetadataResolver解析
    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;
        }
    }

    // Replace the original bean definition with the target one, if necessary
    //应用@Scope注解指定的代理模式(是否创建代理的BeanDefinition),见2.3.3.5(5-7)
    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, beanName);
    }

    if (logger.isTraceEnabled()) {
        logger.trace(String.format("Registering bean definition for @Bean method %s.%s()",
                                   configClass.getMetadata().getClassName(), beanName));
    }
    //注册到容器中,见2.5.1.6
    this.registry.registerBeanDefinition(beanName, beanDefToRegister);
}
2.5.2.1判断容器中是否已经存在该beanName对应的BeanDefinition
protected boolean isOverriddenByExistingDefinition(BeanMethod beanMethod, String beanName) {
    //容器中不存在该beanName对应的BeanDefinition,直接返回false
    if (!this.registry.containsBeanDefinition(beanName)) {
        return false;
    }

    //存在,就获取该BeanDefinition
    BeanDefinition existingBeanDef = this.registry.getBeanDefinition(beanName);

    // Is the existing bean definition one that was created from a configuration class?
    // -> allow the current bean method to override, since both are at second-pass level.
    // However, if the bean method is an overloaded case on the same configuration class,
    // preserve the existing bean definition.
    /**
     * 如果这个BeanDefinition是@Bean方法创建的,且它们不是来源于同一配置类的@Bean方法,
     * 返回false,否则true
     * 因为它们都是第二级别
     */
    if (existingBeanDef instanceof ConfigurationClassBeanDefinition) {
        ConfigurationClassBeanDefinition ccbd = (ConfigurationClassBeanDefinition) existingBeanDef;
        //比较它们来源的配置类是否相同
        if (ccbd.getMetadata().getClassName().equals(
            beanMethod.getConfigurationClass().getMetadata().getClassName())) {
            //相同,再比较两个@Bean方法的方法名
            if (ccbd.getFactoryMethodMetadata().getMethodName().equals(ccbd.getFactoryMethodName())) {
                //覆盖原本的factoryMethodName,并将isFactoryMethodUnique置为false,表明该工厂方法需要被重写
                ccbd.setNonUniqueFactoryMethodName(ccbd.getFactoryMethodMetadata().getMethodName());
            }
            return true;
        }
        else {
            return false;
        }
    }

    // A bean definition resulting from a component scan can be silently overridden
    // by an @Bean method, as of 4.2...
    //如果是@ComponentScan注解扫描生成的BeanDefinition,直接返回false
    if (existingBeanDef instanceof ScannedGenericBeanDefinition) {
        return false;
    }

    // Has the existing bean definition bean marked as a framework-generated bean?
    // -> allow the current bean method to override it, since it is application-level
    /**
     * BeanDefinition.ROLE_APPLICATION=0 表明该BeanDefinition是应用程序级别的,一般用户定义的就是这个级别
     * BeanDefinition.ROLE_SUPPORT=1 表明该BeanDefinition是某些较大配置的一部分
     * BeanDefinition.ROLE_INFRASTRUCTURE=2 表明该BeanDefinition是框架内部定义的bean
     * 非用户定义的直接false
     */
    if (existingBeanDef.getRole() > BeanDefinition.ROLE_APPLICATION) {
        return false;
    }

    // At this point, it's a top-level override (probably XML), just having been parsed
    // before configuration class processing kicks in...
    /**
     * 到了这一步,就说明容器中的BeanDefinition可能是通过XML注册进来的,
     * 那么就需要检查容器是否开启BeanDefinition覆盖的功能
     */
    if (this.registry instanceof DefaultListableBeanFactory &&
        !((DefaultListableBeanFactory) this.registry).isAllowBeanDefinitionOverriding()) {
        throw new BeanDefinitionStoreException(beanMethod.getConfigurationClass().getResource().getDescription(),
                                               beanName, "@Bean definition illegally overridden by existing bean definition: " + existingBeanDef);
    }
    if (logger.isDebugEnabled()) {
        logger.debug(String.format("Skipping bean definition for %s: a definition for bean '%s' " +
                                   "already exists. This top-level bean definition is considered as an override.",
                                   beanMethod, beanName));
    }
    return true;
}

总结

  • 这个方法返回true表明容器中存在的那个bean是一个顶级bean,此时不需要覆盖

  • 返回false,会继续解析@Bean方法。false存在以下几种情况

    • 容器中不存在该beanName对应的BeanDefinition
    • 这个BeanDefinition@Bean方法创建的,且它们不是来源于同一配置类的@Bean方法
    • @ComponentScan注解扫描生成的BeanDefinition
    • 存在的BeanDefinition不是BeanDefinition.ROLE_APPLICATION(用户定义的)级别的
2.5.2.2构造ConfigurationClassBeanDefinition
public ConfigurationClassBeanDefinition(
    ConfigurationClass configClass, MethodMetadata beanMethodMetadata, String derivedBeanName) {

    //配置类的AnnotationMetadata
    this.annotationMetadata = configClass.getMetadata();
    //MethodMetadata
    this.factoryMethodMetadata = beanMethodMetadata;
    //就是beanName
    this.derivedBeanName = derivedBeanName;
    setResource(configClass.getResource());
    //指定使用宽松模式解析构造方法(还有严格模式,未匹配上就抛异常)
    setLenientConstructorResolution(false);
}

2.5.3处理@ImportResource注解导入的资源

loadBeanDefinitionsFromImportedResources(configClass.getImportedResources());

经由2.3.5章节初步处理@ImportResource注解后,这里做进一步处理。

//取出2.3.5章节保存在ConfigurationClass中的importedResources
public Map<String, Class<? extends BeanDefinitionReader>> getImportedResources() {
   return this.importedResources;
}

使用指定的BeanDefinitionReader来读取资源。

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

    Map<Class<?>, BeanDefinitionReader> readerInstanceCache = new HashMap<>();

    importedResources.forEach((resource, readerClass) -> {
        // Default reader selection necessary?
        //@ImportResource未指定reader属性
        if (BeanDefinitionReader.class == readerClass) {
            //根据资源的类型判断使用哪个默认的BeanDefinitionReader
            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
                readerClass = XmlBeanDefinitionReader.class;
            }
        }

        BeanDefinitionReader reader = readerInstanceCache.get(readerClass);
        if (reader == null) {
            try {
                // Instantiate the specified BeanDefinitionReader
                //实例化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
        //读取资源
        reader.loadBeanDefinitions(resource);
    });
}

2.5.4处理@Import注解导入的ImportBeanDefinitionRegistrar

loadBeanDefinitionsFromRegistrars(configClass.getImportBeanDefinitionRegistrars());

经由2.3.4.3(3-3)章节初步处理@Import注解后,这里做进一步处理。

//取出2.3.4.3(3-3)章节保存在ConfigurationClass中的importedResources
public Map<ImportBeanDefinitionRegistrar, AnnotationMetadata> getImportBeanDefinitionRegistrars() {
    return this.importBeanDefinitionRegistrars;
}

处理ImportBeanDefinitionRegistrar

private void loadBeanDefinitionsFromRegistrars(Map<ImportBeanDefinitionRegistrar, AnnotationMetadata> registrars) {
    /**
     * 实际上就是遍历调用ImportBeanDefinitionRegistrar接口的registerBeanDefinitions方法
     * metadata ImportBeanDefinitionRegistrar来源的配置类注解元数据
     * registry BeanDefinitionRegistry注册BeanDefinition
     * this.importBeanNameGenerator 当前使用的beanName生成器
     */
    registrars.forEach((registrar, metadata) ->
                       registrar.registerBeanDefinitions(metadata, this.registry, this.importBeanNameGenerator));
}

3postProcessBeanFactory

/**
 * Prepare the Configuration classes for servicing bean requests at runtime
 * by replacing them with CGLIB-enhanced subclasses.
 */
@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);
    //此处判断该工厂是否经过2章节的处理
    if (!this.registriesPostProcessed.contains(factoryId)) {
        // BeanDefinitionRegistryPostProcessor hook apparently not supported...
        // Simply call processConfigurationClasses lazily at this point then.
        processConfigBeanDefinitions((BeanDefinitionRegistry) beanFactory);
    }

    //3.1代理容器中所有为full的配置类(CGLIB)
    enhanceConfigurationClasses(beanFactory);
    //3.2向容器中添加ImportAwareBeanPostProcessor
    beanFactory.addBeanPostProcessor(new ImportAwareBeanPostProcessor(beanFactory));
}

3.1代理容器中所有为full的配置类(CGLIB)

/**
 * Post-processes a BeanFactory in search of Configuration class BeanDefinitions;
 * any candidates are then enhanced by a {@link ConfigurationClassEnhancer}.
 * Candidate status is determined by BeanDefinition attribute metadata.
 * @see ConfigurationClassEnhancer
 */
public void enhanceConfigurationClasses(ConfigurableListableBeanFactory beanFactory) {
    Map<String, AbstractBeanDefinition> configBeanDefs = new LinkedHashMap<>();
    for (String beanName : beanFactory.getBeanDefinitionNames()) {
        BeanDefinition beanDef = beanFactory.getBeanDefinition(beanName);
        //获取配置类标识(full或lite)
        Object configClassAttr = beanDef.getAttribute(ConfigurationClassUtils.CONFIGURATION_CLASS_ATTRIBUTE);
        MethodMetadata methodMetadata = null;
        /**
         * 对于ConfigurationClassBeanDefinition类型的BeanDefinition
         * @Bean方法的MethodMetadata就是FactoryMethodMetadata
         */
        if (beanDef instanceof AnnotatedBeanDefinition) {
            methodMetadata = ((AnnotatedBeanDefinition) beanDef).getFactoryMethodMetadata();
        }
        //是一个配置类,就将该bean对应的class文件加载到JVM中
        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;
            if (!abd.hasBeanClass()) {
                try {
                    //ClassUtils.forName("完全限定名")加载到JVM
                    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)) {
            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);
        }
    }
    if (configBeanDefs.isEmpty()) {
        // nothing to enhance -> return immediately
        return;
    }

    /************************代理full配置类*****************************/
    
    ConfigurationClassEnhancer enhancer = new ConfigurationClassEnhancer();
    for (Map.Entry<String, AbstractBeanDefinition> entry : configBeanDefs.entrySet()) {
        AbstractBeanDefinition beanDef = entry.getValue();
        // If a @Configuration class gets proxied, always proxy the target class
        //硬编码指定代理模式为CGLIB
        beanDef.setAttribute(AutoProxyUtils.PRESERVE_TARGET_CLASS_ATTRIBUTE, Boolean.TRUE);
        // Set enhanced subclass of the user-specified bean class
        //获取被代理类的clazz对象
        Class<?> configClass = beanDef.getBeanClass();
        //增强被代理类,获取代理类的clazz对象
        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()));
            }
            //设置到BeanDefinition中,以后反射就使用代理的clazz实例化
            beanDef.setBeanClass(enhancedClass);
        }
    }
}

3.2向容器中添加ImportAwareBeanPostProcessor

这个类了InstantiationAwareBeanPostProcessorAdapter,核心方法有两个

  • postProcessProperties() 属性赋值执行

    public PropertyValues postProcessProperties(@Nullable PropertyValues pvs, Object bean, String beanName) {
        // Inject the BeanFactory before AutowiredAnnotationBeanPostProcessor's
        // postProcessProperties method attempts to autowire other configuration beans.
        //就是将BeanFactory设置到代理的full配置类对象中
        if (bean instanceof EnhancedConfiguration) {
            ((EnhancedConfiguration) bean).setBeanFactory(this.beanFactory);
        }
        return pvs;
    }
    
  • postProcessBeforeInitialization() 初始化前执行

    public Object postProcessBeforeInitialization(Object bean, String beanName) {
        /**
         * 只有通过@Import注解导入的非ImportBeanDefinitionRegistrar类型的组件才能实现这个接口ImportAware
         * 参考2.3.4.3章节,ImportStack保存了来源类的AnnotationMetadata
         * 也就是说被导入类可以通过实现ImportAware接口来获得来源类的AnnotationMetadata
         */
        if (bean instanceof ImportAware) {
            //这不就是2中注册的ImportStack
            ImportRegistry ir = this.beanFactory.getBean(IMPORT_REGISTRY_BEAN_NAME, ImportRegistry.class);
            //根据名字获取对应的AnnotationMetadata
            AnnotationMetadata importingClass = ir.getImportingClassFor(ClassUtils.getUserClass(bean).getName());
            if (importingClass != null) {
                //调用接口方法设置到对象中
                ((ImportAware) bean).setImportMetadata(importingClass);
            }
        }
        return bean;
    }
    

到此为止,该BeanFactoryPostProcesser就已经分析完成了。

你可能感兴趣的:(spring源码,java,spring,ioc)