交流
商城
MCN
登入
注册
首页
提问
分享
讨论
建议
公告
动态
发表新帖
发表新帖
第5-1 章:ConfigurationClassPostProcessor
分享
未结
0
959
李延
LV6
2021-05-21
悬赏:20积分
# 作用 通过注解加载BeanDefintion # 初始化与调用 我们通过之前解析知道我们使用的上下文是AnnotationConfigApplicationContext。我们看一下它的构造函数 ```java public AnnotationConfigApplicationContext(DefaultListableBeanFactory beanFactory) { super(beanFactory); this.reader = new AnnotatedBeanDefinitionReader(this); this.scanner = new ClassPathBeanDefinitionScanner(this); } ``` 其中new出了AnnotatedBeanDefinitionReader对象,更近其构造函数 ```java public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry) { this(registry, getOrCreateEnvironment(registry)); } public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry, Environment environment) { Assert.notNull(registry, "BeanDefinitionRegistry must not be null"); Assert.notNull(environment, "Environment must not be null"); this.registry = registry; this.conditionEvaluator = new ConditionEvaluator(registry, environment, null); AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry); } ``` 在最后有调用AnnotationConfigUtils.registerAnnotationConfigProcessors方法。在这个方法中有下面的代码 ```java if (!registry.containsBeanDefinition(CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)) { RootBeanDefinition def = new RootBeanDefinition(ConfigurationClassPostProcessor.class); def.setSource(source); beanDefs.add(registerPostProcessor(registry, def, CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)); } ``` 我们发现在这里,将ConfigurationClassPostProcessor的Bean定义注册到registry中。 而剩下的代码就是在refresh中了,通过之前章节分析中我们知道在刷新上下文前。spring会从beanFactory中获取所有的BeanDefinitionRegistryPostProcessor。并执行postProcessBeanDefinitionRegistry方法。 # 源码解析 在这个方法中没有复杂的继承关系,所以直接解析具体的方法。我们从postProcessBeanDefinitionRegistry开始 ```java @Override public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) { 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); processConfigBeanDefinitions(registry); } ``` 在方法开始前通过registryId判断当前BeanDefinitionRegistry是否已经加载,如果没有被加载过才进行一下一步加载。 ```java public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) { List<BeanDefinitionHolder> configCandidates = new ArrayList<>(); //获取所有的bean名称 String[] candidateNames = registry.getBeanDefinitionNames(); //筛选出来有Configuration注解的类,为我们当前的扫面bean for (String beanName : candidateNames) { BeanDefinition beanDef = registry.getBeanDefinition(beanName); if (beanDef.getAttribute(ConfigurationClassUtils.CONFIGURATION_CLASS_ATTRIBUTE) != null) { 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)); } } //如果没有找到就返回 if (configCandidates.isEmpty()) { return; } // 排序 configCandidates.sort((bd1, bd2) -> { int i1 = ConfigurationClassUtils.getOrder(bd1.getBeanDefinition()); int i2 = ConfigurationClassUtils.getOrder(bd2.getBeanDefinition()); return Integer.compare(i1, i2); }); // 设置BeanNameGenerator SingletonBeanRegistry sbr = null; if (registry instanceof SingletonBeanRegistry) { sbr = (SingletonBeanRegistry) registry; if (!this.localBeanNameGeneratorSet) { BeanNameGenerator generator = (BeanNameGenerator) sbr.getSingleton( AnnotationConfigUtils.CONFIGURATION_BEAN_NAME_GENERATOR); if (generator != null) { this.componentScanBeanNameGenerator = generator; this.importBeanNameGenerator = generator; } } } //设置 environment if (this.environment == null) { this.environment = new StandardEnvironment(); } // 创建 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 { StartupStep processConfig = this.applicationStartup.start("spring.context.config-classes.parse"); //开始解析 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 //通过ConfigurationClassBeanDefinitionReader对象注册bean定义 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); processConfig.tag("classCount", () -> String.valueOf(configClasses.size())).end(); candidates.clear(); //在新加入的bean定义中如果还有配置类,则继续循环解析 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 if (sbr != null && !sbr.containsSingleton(IMPORT_REGISTRY_BEAN_NAME)) { sbr.registerSingleton(IMPORT_REGISTRY_BEAN_NAME, parser.getImportRegistry()); } if (this.metadataReaderFactory instanceof CachingMetadataReaderFactory) { // Clear cache in externally provided MetadataReaderFactory; this is a no-op // for a shared cache since it'll be cleared by the ApplicationContext. ((CachingMetadataReaderFactory) this.metadataReaderFactory).clearCache(); } } ``` 上面代码主要逻辑有: - 首先获取了所有的bean定义。 - 在所有的bean中筛选出我们需要的bean定义,主要依据就是包含@Configuration注解。 - 下一步就是创建ConfigurationClassParser对象,并调用parse方法解析数据。 - 使用ConfigurationClassBeanDefinitionReader对象注册解析结果 我们这里先跟进parse方法,之后再解析ConfigurationClassBeanDefinitionReader ## ConfigurationClassParser 我们直接看这个类的parse方法 ```java public void parse(Set<BeanDefinitionHolder> configCandidates) { for (BeanDefinitionHolder holder : configCandidates) { BeanDefinition bd = holder.getBeanDefinition(); try { if (bd instanceof AnnotatedBeanDefinition) { parse(((AnnotatedBeanDefinition) bd).getMetadata(), holder.getBeanName()); } else if (bd instanceof AbstractBeanDefinition && ((AbstractBeanDefinition) bd).hasBeanClass()) { parse(((AbstractBeanDefinition) bd).getBeanClass(), holder.getBeanName()); } else { parse(bd.getBeanClassName(), holder.getBeanName()); } } catch (BeanDefinitionStoreException ex) { throw ex; } catch (Throwable ex) { throw new BeanDefinitionStoreException( "Failed to parse configuration class [" + bd.getBeanClassName() + "]", ex); } } this.deferredImportSelectorHandler.process(); } ``` 我们看到主要分为两步 1. 根据不同参数,调用不同的parse方法,我们当前为AnnotatedBeanDefinition,所以以这个为主。 2. 调用deferredImportSelectorHandler的方法。这一步主要是加载延迟的ImportSelector。具体作用我们在解析完第一步后说明。 ### parse 我们继续跟进parse方法 ```java protected final void parse(AnnotationMetadata metadata, String beanName) throws IOException { processConfigurationClass(new ConfigurationClass(metadata, beanName), DEFAULT_EXCLUSION_FILTER); } protected void processConfigurationClass(ConfigurationClass configClass, Predicate<String> filter) throws IOException { if (this.conditionEvaluator.shouldSkip(configClass.getMetadata(), ConfigurationPhase.PARSE_CONFIGURATION)) { return; } ConfigurationClass existingClass = this.configurationClasses.get(configClass); if (existingClass != null) { if (configClass.isImported()) { if (existingClass.isImported()) { existingClass.mergeImportedBy(configClass); } // 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); } ``` 在这里我们看到首先是封装为ConfigurationClass对象,并调用processConfigurationClass方法。在processConfigurationClass方法中: 一开始是通过configurationClasses判断当前类是否已经处理过。因为对于类的扫描有import的情况,可能多次导入同一个类,之后是调用doProcessConfigurationClass方法。 其中doProcessConfigurationClass方法是在do-while循环内,而这个循环是对当前扫描类的父类的处理。之后是将已经处理情况添加到configurationClasses中。 我们继续看doProcessConfigurationClass方法 ```java @Nullable protected final SourceClass doProcessConfigurationClass( ConfigurationClass configClass, SourceClass sourceClass, Predicate<String> filter) throws IOException { if (configClass.getMetadata().isAnnotated(Component.class.getName())) { // Recursively process any member (nested) classes first processMemberClasses(configClass, sourceClass, filter); } // 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.info("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), filter, 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)); } // Process default methods on interfaces processInterfaces(configClass, sourceClass); // Process superclass, if any if (sourceClass.getMetadata().hasSuperClass()) { String superclass = sourceClass.getMetadata().getSuperClassName(); if (superclass != null && !superclass.startsWith("java") && !this.knownSuperclasses.containsKey(superclass)) { this.knownSuperclasses.put(superclass, configClass); // Superclass found, return its annotation metadata and recurse return sourceClass.getSuperClass(); } } // No superclass -> processing is complete return null; } ``` 在这一步中,我们终于看到了我们要找的内容了,对于不同注解的处理。具体可以分为以下几步: - 递归处理内部类 - 处理@PropertySources注解 - 处理@ComponentScans注解 - 处理@Import注解 - 处理@ImportResource注解 - 处理@Bean注解 - 最后判断是否包含父类,如果有返回父类 下面我们分别说明这几种不同情况 #### 递归处理内部类 在这一步中,我们看到首先判断是否包含Component注解,这个注解也是我们常用的Service注解。之后调用processMemberClasses方法,代码如下: ```java /** * Register member (nested) classes that happen to be configuration classes themselves. */ private void processMemberClasses(ConfigurationClass configClass, SourceClass sourceClass, Predicate<String> filter) throws IOException { //获取所有内部类 Collection<SourceClass> memberClasses = sourceClass.getMemberClasses(); if (!memberClasses.isEmpty()) { List<SourceClass> candidates = new ArrayList<>(memberClasses.size()); for (SourceClass memberClass : memberClasses) { if (ConfigurationClassUtils.isConfigurationCandidate(memberClass.getMetadata()) && !memberClass.getMetadata().getClassName().equals(configClass.getMetadata().getClassName())) { candidates.add(memberClass); } } OrderComparator.sort(candidates); for (SourceClass candidate : candidates) { if (this.importStack.contains(configClass)) { this.problemReporter.error(new CircularImportProblem(configClass, this.importStack)); } else { this.importStack.push(configClass); try { processConfigurationClass(candidate.asConfigClass(configClass), filter); } finally { this.importStack.pop(); } } } } } ``` 我们看到这里是一个递归的过程,查询到所有子类,并调用processConfigurationClass方法,而processConfigurationClass方法就是我们之前的进入的方法 #### PropertySources 我们先看一下这部分代码 ```java // 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.info("Ignoring @PropertySource annotation on [" + sourceClass.getMetadata().getClassName() + "]. Reason: Environment must implement ConfigurableEnvironment"); } } ``` 首先获取到PropertySources和PropertySource注解的属性,其中PropertySources是PropertySource的集合。遍历每个属性调用processPropertySource。 ```java private void processPropertySource(AnnotationAttributes propertySource) throws IOException { String name = propertySource.getString("name"); if (!StringUtils.hasLength(name)) { name = null; } //获取编码 String encoding = propertySource.getString("encoding"); if (!StringUtils.hasLength(encoding)) { encoding = null; } // 获取路径 String[] locations = propertySource.getStringArray("value"); Assert.isTrue(locations.length > 0, "At least one @PropertySource(value) location is required"); boolean ignoreResourceNotFound = propertySource.getBoolean("ignoreResourceNotFound"); // 获取PropertySourceFactory 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); 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; } } } } ``` #### ComponentScans ComponentScans是 组件扫描,表示扫描指定路径下的class。而默认指定的路径为 **/*.class 。这也就说明spring为什么会自动扫描main方法下的所有类,具体代码如下: ```java // Process any @ComponentScan annotations //获取到ComponentScan所有属性 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 //扫描指定路径下的符合要求的bean,并注册到beanDefinitionRegist内 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(); } //如果是配置类也就是包含Configuration、Component、ComponentScan、Import、ImportResource注解时,递归parse if (ConfigurationClassUtils.checkConfigurationClassCandidate(bdCand, this.metadataReaderFactory)) { parse(bdCand.getBeanClassName(), holder.getBeanName()); } } } } ``` 我们看到一共分为3步: 1. 获取类上所有的ComponentScan注解属性 2. 将获取结果交给componentScanParser,判断是否有符合要求的类,并将其注入到注册表中。 3. 递归parse方法,用于解析其他逐渐 而componentScanParser类与ClassPathBeanDefinitionScanner类关系比较紧密,我们将这两类放在一起解析 #### Import ```java processImports(configClass, sourceClass, getImports(sourceClass), filter, true); ``` 在执行processImports前,先调用了getImports方法.我们知道@Import的值为class数组,这一步就是获取值的内容。我们直接看processImports方法 ```java private void processImports(ConfigurationClass configClass, SourceClass currentSourceClass, Collection<SourceClass> importCandidates, Predicate<String> exclusionFilter, boolean checkForCircularImports) { //候选有值时继续 if (importCandidates.isEmpty()) { return; } // 维护一个栈,判断重复执行一个情况 if (checkForCircularImports && isChainedImportOnStack(configClass)) { this.problemReporter.error(new CircularImportProblem(configClass, this.importStack)); } else { //入栈 this.importStack.push(configClass); try { for (SourceClass candidate : importCandidates) { //如果导入的是ImportSelector子类 if (candidate.isAssignable(ImportSelector.class)) { // Candidate class is an ImportSelector -> delegate to it to determine imports //示例化 Class<?> candidateClass = candidate.loadClass(); ImportSelector selector = ParserStrategyUtils.instantiateClass(candidateClass, ImportSelector.class, this.environment, this.resourceLoader, this.registry); Predicate<String> selectorFilter = selector.getExclusionFilter(); if (selectorFilter != null) { exclusionFilter = exclusionFilter.or(selectorFilter); } //如果是延迟加载交给deferredImportSelectorHandler处理 if (selector instanceof DeferredImportSelector) { this.deferredImportSelectorHandler.handle(configClass, (DeferredImportSelector) selector); } //非延迟加载,直接执行 else { String[] importClassNames = selector.selectImports(currentSourceClass.getMetadata()); Collection<SourceClass> importSourceClasses = asSourceClasses(importClassNames, exclusionFilter); processImports(configClass, currentSourceClass, importSourceClasses, exclusionFilter, false); } } //如果是ImportBeanDefinitionRegistrar子类,手段导入BeanDefintion。这里只是将其记录在configClass对象内,在后面调用 else if (candidate.isAssignable(ImportBeanDefinitionRegistrar.class)) { // Candidate class is an ImportBeanDefinitionRegistrar -> // delegate to it to register additional bean definitions Class<?> candidateClass = candidate.loadClass(); ImportBeanDefinitionRegistrar registrar = ParserStrategyUtils.instantiateClass(candidateClass, ImportBeanDefinitionRegistrar.class, this.environment, this.resourceLoader, this.registry); configClass.addImportBeanDefinitionRegistrar(registrar, currentSourceClass.getMetadata()); } //普通类调用processConfigurationClass方法,就是当成一个@Configuration注解处理 else { // Candidate class not an ImportSelector or ImportBeanDefinitionRegistrar -> // process it as an @Configuration class this.importStack.registerImport( currentSourceClass.getMetadata(), candidate.getMetadata().getClassName()); processConfigurationClass(candidate.asConfigClass(configClass), exclusionFilter); } } } catch (BeanDefinitionStoreException ex) { throw ex; } catch (Throwable ex) { throw new BeanDefinitionStoreException( "Failed to process import candidates for configuration class [" + configClass.getMetadata().getClassName() + "]", ex); } finally { this.importStack.pop(); } } } ``` 通过上面代码我们可以将@Import注解根据值不同,分为3种不同情况 1. ImportSelector子类。 这种情况会调用其selectImports方法返回指定的class路径,并加载这些class。其他有一种DeferredImportSelector子类。延迟加载,交给DeferredImportSelector对象,在parse方法执行完成后加载 2. ImportBeanDefinitionRegistrar子类。 这个类就是让用户自己注册bean定义,这里只是记录,在之后加载。 3. 最后是普通类,作为Configuration处理。 #### ImportResource ImportResource主要导入xml配置,在这里只是将其加载到configClass中 ```java // 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 ```java // Process individual @Bean methods Set<MethodMetadata> beanMethods = retrieveBeanMethodMetadata(sourceClass); for (MethodMetadata methodMetadata : beanMethods) { configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass)); } ``` 我们看到首先通过retrieveBeanMethodMetadata读取到有Bean的方法,之后将其记录在configClass中。 ### deferredImportSelectorHandler.process 回到parse方法,当执行完parse后,后面就执行了deferredImportSelectorHandler.process。我们前面也看到了我们将DeferredImportSelector对象加入到了deferredImportSelectorHandler对象,这一步就是具体执行。我们下面看源码 ```java public void process() { List<DeferredImportSelectorHolder> deferredImports = this.deferredImportSelectors; this.deferredImportSelectors = null; try { if (deferredImports != null) { DeferredImportSelectorGroupingHandler handler = new DeferredImportSelectorGroupingHandler(); deferredImports.sort(DEFERRED_IMPORT_COMPARATOR); deferredImports.forEach(handler::register); handler.processGroupImports(); } } finally { this.deferredImportSelectors = new ArrayList<>(); } } ``` 我们看到先是创建DeferredImportSelectorGroupingHandler对象,后又循环将deferredImports添加到这个对象。我们先看一下register方法: ```java public void register(DeferredImportSelectorHolder deferredImport) { Class<? extends Group> group = deferredImport.getImportSelector().getImportGroup(); DeferredImportSelectorGrouping grouping = this.groupings.computeIfAbsent( (group != null ? group : deferredImport), key -> new DeferredImportSelectorGrouping(createGroup(group))); grouping.add(deferredImport); this.configurationClasses.put(deferredImport.getConfigurationClass().getMetadata(), deferredImport.getConfigurationClass()); } ``` 我们看到deferredImport后被分到不同的group中,而processGroupImports也是按照不同组一次调用 ```java public void processGroupImports() { for (DeferredImportSelectorGrouping grouping : this.groupings.values()) { Predicate<String> exclusionFilter = grouping.getCandidateFilter(); grouping.getImports().forEach(entry -> { ConfigurationClass configurationClass = this.configurationClasses.get(entry.getMetadata()); try { 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); } }); } } ``` ### parser.parse 总结 到目前为止,我们解析完成了都各种注解的解析,但很多都是将就结果保存在configClass中,具体如何获取到BeanDefinition并进行注册还没有进行,我们继续下面解析 ## ConfigurationClassBeanDefinitionReader 我们直接进入loadBeanDefinitions方法,看一下如何将解析结果进行注册的 ```java 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; } //有@Import 情况 if (configClass.isImported()) { registerBeanDefinitionForImportedConfigurationClass(configClass); } //有 @Bean情况 for (BeanMethod beanMethod : configClass.getBeanMethods()) { loadBeanDefinitionsForBeanMethod(beanMethod); } //解析 @ImportResources loadBeanDefinitionsFromImportedResources(configClass.getImportedResources()); //@Import注解导入ImportBeanDefinitionRegistrar类时 loadBeanDefinitionsFromRegistrars(configClass.getImportBeanDefinitionRegistrars()); } ``` 我们看到上面就是之前解析注解时的4种不同情况。我们这里关注的就是最后2个方法 ### loadBeanDefinitionsFromImportedResources ```java private void loadBeanDefinitionsFromImportedResources( Map<String, Class<? extends BeanDefinitionReader>> importedResources) { Map<Class<?>, BeanDefinitionReader> readerInstanceCache = new HashMap<>(); importedResources.forEach((resource, readerClass) -> { // Default reader selection necessary? if (BeanDefinitionReader.class == readerClass) { if (StringUtils.endsWithIgnoreCase(resource, ".groovy")) { // When clearly asking for Groovy, that's what they'll get... readerClass = GroovyBeanDefinitionReader.class; } else if (shouldIgnoreXml) { throw new UnsupportedOperationException("XML support disabled"); } 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 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); }); } ``` 我们看到最后是加载通过BeanDefinitionRegistry对象加载xml。具体就不再详细说明 ### loadBeanDefinitionsFromRegistrars ```java private void loadBeanDefinitionsFromRegistrars(Map<ImportBeanDefinitionRegistrar, AnnotationMetadata> registrars) { registrars.forEach((registrar, metadata) -> registrar.registerBeanDefinitions(metadata, this.registry, this.importBeanNameGenerator)); } ``` 循环调用 registrar.registerBeanDefinitions。而 registrar就是我们之前通过@Import导入的
回帖
消灭零回复
提交回复
热议榜
java 相关知识分享
8
好的程序员与不好的程序员
6
写给工程师的十条精进原则
5
spring boot以jar包运行配置的logback日志文件没生成
5
一步一步分析SpringBoot启动源码(一)
5
MockMvc测试
5
【吐槽向】是不是有个吐槽的板块比较好玩
4
logstash jdbc同步mysql多表数据到elasticsearch
3
IntelliJ IDEA 优质License Server
3
.gitignore忽略规则
3
SpringBoot启动源码分析
3
一步一步分析SpringBoot启动源码(三)
3
2
一步一步分析SpringBoot启动源码(二)
2
积分不够将无法发表新帖
2
官方产品
Meta-Boot - 基于MCN
MCN - 快速构建SpringBoot应用
微信扫码关注公众号