美文网首页
Spring 源码(四)解析配置类

Spring 源码(四)解析配置类

作者: xiaolyuh | 来源:发表于2019-09-29 12:50 被阅读0次

    我们要找出所有符合条件的业务Bean,首先我们需要知道在Spring中什么样的Bean是符合条件的,是需要容器来管理的:

    1. 使用组件标注注解的Bean(@Controller、@Service、@Repository、@Component),一般项目里面使用。
    2. 使用@Bean注解标准的方法,一般导入第三方组件的时候使用。
    3. 使用@Import注解导入的Bean,一般快速导入一批组件时使用。

    doProcessConfigurationClass 配置类的解析过程

    调用链路:

    doProcessConfigurationClass:289, ConfigurationClassParser (org.springframework.context.annotation)
    processConfigurationClass:247, ConfigurationClassParser (org.springframework.context.annotation)
    parse:200, ConfigurationClassParser (org.springframework.context.annotation)
    parse:169, ConfigurationClassParser (org.springframework.context.annotation)
    processConfigBeanDefinitions:308, ConfigurationClassPostProcessor (org.springframework.context.annotation)
    postProcessBeanDefinitionRegistry:228, ConfigurationClassPostProcessor (org.springframework.context.annotation)
    invokeBeanDefinitionRegistryPostProcessors:272, PostProcessorRegistrationDelegate (org.springframework.context.support)
    invokeBeanFactoryPostProcessors:92, PostProcessorRegistrationDelegate (org.springframework.context.support)
    invokeBeanFactoryPostProcessors:687, AbstractApplicationContext (org.springframework.context.support)
    refresh:525, AbstractApplicationContext (org.springframework.context.support)
    <init>:84, AnnotationConfigApplicationContext (org.springframework.context.annotation)
    

    源码:

    // 解析配置类将业务Bean的定义BeanDefinition注册到容器
    protected final SourceClass doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass)
            throws IOException {
    
        // Recursively process any member (nested) classes first
        processMemberClasses(configClass, sourceClass);
    
        // Process any @PropertySource annotations
        for (AnnotationAttributes propertySource : AnnotationConfigUtils.attributesForRepeatable(
                sourceClass.getMetadata(), PropertySources.class,
                org.springframework.context.annotation.PropertySource.class)) {
            if (this.environment instanceof ConfigurableEnvironment) {
                processPropertySource(propertySource);
            }
            else {
                logger.warn("Ignoring @PropertySource annotation on [" + sourceClass.getMetadata().getClassName() +
                        "]. Reason: Environment must implement ConfigurableEnvironment");
            }
        }
    
        // Process any @ComponentScan annotations
        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
                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
                for (BeanDefinitionHolder holder : scannedBeanDefinitions) {
                    BeanDefinition bdCand = holder.getBeanDefinition().getOriginatingBeanDefinition();
                    if (bdCand == null) {
                        bdCand = holder.getBeanDefinition();
                    }
                    if (ConfigurationClassUtils.checkConfigurationClassCandidate(bdCand, this.metadataReaderFactory)) {
                        parse(bdCand.getBeanClassName(), holder.getBeanName());
                    }
                }
            }
        }
    
        // Process any @Import annotations
        processImports(configClass, sourceClass, getImports(sourceClass), true);
    
        // Process any @ImportResource annotations
        if (sourceClass.getMetadata().isAnnotated(ImportResource.class.getName())) {
            AnnotationAttributes importResource =
                    AnnotationConfigUtils.attributesFor(sourceClass.getMetadata(), ImportResource.class);
            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);
            }
        }
    
        // Process individual @Bean methods
        Set<MethodMetadata> beanMethods = retrieveBeanMethodMetadata(sourceClass);
        for (MethodMetadata methodMetadata : beanMethods) {
            configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));
        }
    
        // Process default methods on interfaces
        processInterfaces(configClass, sourceClass);
    
        // Process superclass, if any
        if (sourceClass.getMetadata().hasSuperClass()) {
            String superclass = sourceClass.getMetadata().getSuperClassName();
            if (!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;
    }
    

    从源码我们可以看到解析配置类的完整过程:

    1. 使用递归的方式处理嵌套类
    2. 处理@PropertySource注解,解析配置文件,将配置项加载到环境变量里面
    3. 处理@ComponentScan注解,将所有符合条件Bean的BeanDefinition注册到容器
    4. 处理@Import注解
    5. 处理@ImportResource注解
    6. 处理@Bean方法
    7. 处理接口的默认方法
    8. 处理父类

    处理@ComponentScan注解

    我们这里主要介绍下@ComponentScan注解的处理过程,最后主要的处理方法是ClassPathBeanDefinitionScanner#doScan()方法。

    调用链路:

    doScan:270, ClassPathBeanDefinitionScanner (org.springframework.context.annotation)
    parse:135, ComponentScanAnnotationParser (org.springframework.context.annotation)
    doProcessConfigurationClass:289, ConfigurationClassParser (org.springframework.context.annotation)
    processConfigurationClass:247, ConfigurationClassParser (org.springframework.context.annotation)
    parse:200, ConfigurationClassParser (org.springframework.context.annotation)
    parse:169, ConfigurationClassParser (org.springframework.context.annotation)
    processConfigBeanDefinitions:308, ConfigurationClassPostProcessor (org.springframework.context.annotation)
    postProcessBeanDefinitionRegistry:228, ConfigurationClassPostProcessor (org.springframework.context.annotation)
    invokeBeanDefinitionRegistryPostProcessors:272, PostProcessorRegistrationDelegate (org.springframework.context.support)
    invokeBeanFactoryPostProcessors:92, PostProcessorRegistrationDelegate (org.springframework.context.support)
    invokeBeanFactoryPostProcessors:687, AbstractApplicationContext (org.springframework.context.support)
    refresh:525, AbstractApplicationContext (org.springframework.context.support)
    <init>:84, AnnotationConfigApplicationContext (org.springframework.context.annotation)
    

    源码:

    //  @ComponentScan 执行包扫描
    protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
        Assert.notEmpty(basePackages, "At least one base package must be specified");
        Set<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet<BeanDefinitionHolder>();
        for (String basePackage : basePackages) {
            // 根据包路径找到需要加载到容器的业务Bean
            Set<BeanDefinition> candidates = findCandidateComponents(basePackage);
            for (BeanDefinition candidate : candidates) {
                ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);
                candidate.setScope(scopeMetadata.getScopeName());
                String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry);
                if (candidate instanceof AbstractBeanDefinition) {
                    postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName);
                }
                if (candidate instanceof AnnotatedBeanDefinition) {
                    AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);
                }
                if (checkCandidate(beanName, candidate)) {
                    BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);
                    definitionHolder =
                            AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
                    beanDefinitions.add(definitionHolder);
                    // 将符合条件的Bean 定义注册到容器
                    registerBeanDefinition(definitionHolder, this.registry);
                }
            }
        }
        return beanDefinitions;
    }
    
    // 根据包路径找到需要加载到容器的业务Bean
    public Set<BeanDefinition> findCandidateComponents(String basePackage) {
        Set<BeanDefinition> candidates = new LinkedHashSet<BeanDefinition>();
        try {
            // 根据包路径找到需要加载到容器class文件
            String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX +
                    resolveBasePackage(basePackage) + '/' + this.resourcePattern;
                    
            // 根据资源加载器加载所有在对应包路径下的class文件到内存
            Resource[] resources = this.resourcePatternResolver.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 = this.metadataReaderFactory.getMetadataReader(resource);
                        // 判断是否是@Component组件
                        if (isCandidateComponent(metadataReader)) {
                            ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader);
                            sbd.setResource(resource);
                            sbd.setSource(resource);
                            if (isCandidateComponent(sbd)) {
                                if (debugEnabled) {
                                    logger.debug("Identified candidate component class: " + resource);
                                }
                                candidates.add(sbd);
                            }
                            ...
        return candidates;
    }
    
    // 判断是否是@Component组件
    protected boolean isCandidateComponent(MetadataReader metadataReader) throws IOException {
        // 执行excludeFilters
        for (TypeFilter tf : this.excludeFilters) {
            if (tf.match(metadataReader, this.metadataReaderFactory)) {
                return false;
            }
        }
        // 执行includeFilters
        for (TypeFilter tf : this.includeFilters) {
            if (tf.match(metadataReader, this.metadataReaderFactory)) {
                return isConditionMatch(metadataReader);
            }
        }
        return false;
    }
    

    findCandidateComponents方法最终会调用AnnotationMetadataReadingVisitor类的hasAnnotation和hasMetaAnnotation方法来判断是否是@Component组件。
    调用链路:

    hasMetaAnnotation:112, AnnotationMetadataReadingVisitor (org.springframework.core.type.classreading)
    matchSelf:86, AnnotationTypeFilter (org.springframework.core.type.filter)
    match:61, AbstractTypeHierarchyTraversingFilter (org.springframework.core.type.filter)
    isCandidateComponent:354, ClassPathScanningCandidateComponentProvider (org.springframework.context.annotation)
    findCandidateComponents:288, ClassPathScanningCandidateComponentProvider (org.springframework.context.annotation)
    doScan:272, ClassPathBeanDefinitionScanner (org.springframework.context.annotation)
    parse:135, ComponentScanAnnotationParser (org.springframework.context.annotation)
    doProcessConfigurationClass:289, ConfigurationClassParser (org.springframework.context.annotation)
    processConfigurationClass:247, ConfigurationClassParser (org.springframework.context.annotation)
    parse:200, ConfigurationClassParser (org.springframework.context.annotation)
    parse:169, ConfigurationClassParser (org.springframework.context.annotation)
    processConfigBeanDefinitions:308, ConfigurationClassPostProcessor (org.springframework.context.annotation)
    postProcessBeanDefinitionRegistry:228, ConfigurationClassPostProcessor (org.springframework.context.annotation)
    invokeBeanDefinitionRegistryPostProcessors:272, PostProcessorRegistrationDelegate (org.springframework.context.support)
    invokeBeanFactoryPostProcessors:92, PostProcessorRegistrationDelegate (org.springframework.context.support)
    invokeBeanFactoryPostProcessors:687, AbstractApplicationContext (org.springframework.context.support)
    refresh:525, AbstractApplicationContext (org.springframework.context.support)
    <init>:84, AnnotationConfigApplicationContext (org.springframework.context.annotation)
    

    源码:

    // 判断是否是@Component组件
    public class AnnotationMetadataReadingVisitor extends ClassMetadataReadingVisitor implements AnnotationMetadata {
    
        ...
        // 判断是否是业务Bean
        @Override
        public boolean hasAnnotation(String annotationName) {
            return this.annotationSet.contains(annotationName);
        }
        
        // 判断是否是业务Bean
        @Override
        public boolean hasMetaAnnotation(String metaAnnotationType) {
            // 如果业务Bean是加的@Service注解,那么在metaAnnotationMap中将会以 
            // org.springframework.stereotype.Service=org.springframework.stereotype.Component的形式存储,
            // 将@Service注解映射成@Component注解。其他继承自@Component注解的处理方式也一样
            Collection<Set<String>> allMetaTypes = this.metaAnnotationMap.values();
            for (Set<String> metaTypes : allMetaTypes) {
                if (metaTypes.contains(metaAnnotationType)) {
                    return true;
                }
            }
            return false;
        }
        ...
    }
    

    执行流程:

    1. 根据@ComponentScan注解配置的包范围找到所有符合条件的class文件
    2. 根据资源加载器,将所有的class文件加载到内存
    3. 循环遍历class找出符合条件的@Component组件
    4. 执行@ComponentScan的excludeFilters
    5. 执行@ComponentScan的includeFilters
    6. 获取当前class的metaAnnotationMap,判断是否是@Component组件
    7. 将符合条件的class的BeanDefinition注册到容器

    如果业务Bean是加的@Service注解,那么在metaAnnotationMap中将会以 org.springframework.stereotype.Service=org.springframework.stereotype.Component的形式存储, 将@Service注解映射成@Component注解。其他继承自@Component注解的处理方式也一样

    相关文章

      网友评论

          本文标题:Spring 源码(四)解析配置类

          本文链接:https://www.haomeiwen.com/subject/aafyyctx.html