• Spring之Condition(二)在哪里解析的


    通常情况下@Conditional都会会配合着@Bean一起使用的

    来看看代码中在哪里会对@Conditional进行解析

    首先看@Bean在哪里解析的

    ConfigurationClassParser
    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
            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);
                }
            }
    
            // Process individual @Bean methods
            Set<MethodMetadata> beanMethods = retrieveBeanMethodMetadata(sourceClass);
            for (MethodMetadata methodMetadata : beanMethods) {
                configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));//configClass是@Configuration注解类,把原信息包成BeanMethod,保存起来
            }
    private Set<MethodMetadata> retrieveBeanMethodMetadata(SourceClass sourceClass) {
            AnnotationMetadata original = sourceClass.getMetadata();
            Set<MethodMetadata> beanMethods = original.getAnnotatedMethods(Bean.class.getName());
            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;
        }

      现在回到 ConfigurationClassPostProcessor.processConfigBeanDefinitions

    public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
            List<BeanDefinitionHolder> configCandidates = new ArrayList<>();
            String[] candidateNames = registry.getBeanDefinitionNames();
    
            for (String beanName : candidateNames) {
                BeanDefinition beanDef = registry.getBeanDefinition(beanName);
                if (ConfigurationClassUtils.isFullConfigurationClass(beanDef) ||
                        ConfigurationClassUtils.isLiteConfigurationClass(beanDef)) {
                    if (logger.isDebugEnabled()) {
                        logger.debug("Bean definition has already been processed as a configuration class: " + beanDef);
                    }
                }
                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;
                if (!this.localBeanNameGeneratorSet) {
                    BeanNameGenerator generator = (BeanNameGenerator) sbr.getSingleton(CONFIGURATION_BEAN_NAME_GENERATOR);
                    if (generator != null) {
                        this.componentScanBeanNameGenerator = generator;
                        this.importBeanNameGenerator = generator;
                    }
                }
            }
    
            if (this.environment == null) {
                this.environment = new StandardEnvironment();
            }
    
            // Parse each @Configuration class
            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 {
                parser.parse(candidates);
                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());
                }
                this.reader.loadBeanDefinitions(configClasses);
                alreadyParsed.addAll(configClasses);
      ConfigurationClassBeanDefinitionReader.loadBeanDefinitions
    public void loadBeanDefinitions(Set<ConfigurationClass> configurationModel) {
            TrackedConditionEvaluator trackedConditionEvaluator = new TrackedConditionEvaluator();
            for (ConfigurationClass configClass : configurationModel) {
                loadBeanDefinitionsForConfigurationClass(configClass, trackedConditionEvaluator);
            }
        }

      

    private void loadBeanDefinitionsForConfigurationClass(
                ConfigurationClass configClass, TrackedConditionEvaluator trackedConditionEvaluator) {
    
            if (trackedConditionEvaluator.shouldSkip(configClass)) {
                String beanName = configClass.getBeanName();
                if (StringUtils.hasLength(beanName) && this.registry.containsBeanDefinition(beanName)) {
                    this.registry.removeBeanDefinition(beanName);
                }
                this.importRegistry.removeImportingClass(configClass.getMetadata().getClassName());
                return;
            }
    
            if (configClass.isImported()) {
                registerBeanDefinitionForImportedConfigurationClass(configClass);
            }
            for (BeanMethod beanMethod : configClass.getBeanMethods()) {
                loadBeanDefinitionsForBeanMethod(beanMethod);
            }
    
            loadBeanDefinitionsFromImportedResources(configClass.getImportedResources());
            loadBeanDefinitionsFromRegistrars(configClass.getImportBeanDefinitionRegistrars());
        }

      

    private void loadBeanDefinitionsForBeanMethod(BeanMethod beanMethod) {
            ConfigurationClass configClass = beanMethod.getConfigurationClass();
            MethodMetadata metadata = beanMethod.getMetadata();
            String methodName = metadata.getMethodName();
    
            // Do we need to mark the bean as skipped by its condition?
            if (this.conditionEvaluator.shouldSkip(metadata, ConfigurationPhase.REGISTER_BEAN)) {
                configClass.skippedBeanMethods.add(methodName);
                return;
            }
            if (configClass.skippedBeanMethods.contains(methodName)) {
                return;
            } 只是截取了一段代码

      其中conditionEvaluator就是判断该不该把这个@Bean注入到容器里

  • 相关阅读:
    java数组转list
    【转载】tomcat端口被占用问题完美解决方案!
    基于apicloud的英语课堂app设计与实现
    springboot整合mybatis(SSM开发环境搭建)
    POI Excel读取图片对应位置和顺序生成图片方法
    E: Sub-process /usr/bin/dpkg returned an error code (1) 出错解决方案
    Ubuntu 虚拟机无法关机的解决方案
    Celery 提示[ERROR/MainProcess] consumer: Cannot connect to amqp://guest:**@127.0.0.1:5672//: [Errno 61] Connection refused.
    Python @classmethod&@staticmethod 区别
    SyntaxError: non-default argument follows default argument
  • 原文地址:https://www.cnblogs.com/juniorMa/p/14363002.html
Copyright © 2020-2023  润新知