程序员最近都爱上了这个网站  程序员们快来瞅瞅吧!  it98k网:it98k.com

本站消息

站长简介/公众号

  出租广告位,需要合作请联系站长


+关注
已关注

分类  

暂无分类

标签  

暂无标签

日期归档  

2023-06(3)

spring 源码解读五 ConfigurationClassPostProcessor

发布于2021-05-30 01:05     阅读(901)     评论(0)     点赞(9)     收藏(5)


ConfigurationClassPostProcessor 是spring注解注入bean的核心类,ConfigurationClassPostProcessor implements BeanDefinitionRegistryPostProcessor

因此 ConfigurationClassPostProcessor是 BeanDefinitionRegistryPostProcessor 的子类,在执行 BeanFactoryPostProcessor的时候回首先执行到 postProcessBeanDefinitionRegistry这个方法

ConfigurationClassPostProcessor -> postProcessBeanDefinitionRegistry
  1. /**
  2. * Derive further bean definitions from the configuration classes in the registry.
  3. */
  4. @Override
  5. public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
  6. int registryId = System.identityHashCode(registry);
  7. if (this.registriesPostProcessed.contains(registryId)) {
  8. throw new IllegalStateException(
  9. "postProcessBeanDefinitionRegistry already called on this post-processor against " + registry);
  10. }
  11. if (this.factoriesPostProcessed.contains(registryId)) {
  12. throw new IllegalStateException(
  13. "postProcessBeanFactory already called on this post-processor against " + registry);
  14. }
  15. this.registriesPostProcessed.add(registryId);
  16. processConfigBeanDefinitions(registry);
  17. }

ConfigurationClassPostProcessor -> processConfigBeanDefinitions(registry);

  1. /**
  2. * Build and validate a configuration model based on the registry of
  3. * {@link Configuration} classes.
  4. */
  5. public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
  6. //遍历之后所有需要处理的BeanDefinition放在这里
  7. List<BeanDefinitionHolder> configCandidates = new ArrayList<>();
  8. // 这里 registry.getBeanDefinitionNames() 这个方法需要重点讲解
  9. // 这里获取到的实际上是 DefaultListableBeanFactory 里面的 BeanDefinitionNames
  10. // 那么问题来了 DefaultListableBeanFactory 里面的 BeanDefinitionNames是哪里来的呢
  11. // 答案是 <context:component-scan base-package="com.spring.debug.beanPostProcess"></context:component-scan> 这个注解扫描到的
  12. // 那么问题又来了既然 context:component-scan 这个注解可以扫描到那么还要 ConfigurationClassPostProcessor干啥
  13. // 答案是 <context:component-scan 这个注解只会扫描到 base-package 这个包下面的类中定义了有 @Component 这个注解的类
  14. // 包括 @Component @Configuration @Controller @Service 等包括有 @Component 这个注解的的注解类
  15. // 并且如果包含了 @Component 这个注解的类里面定义了其他的注解类 <context:component-scan 这个标签也不会扫描到
  16. // 因此 ConfigurationClassPostProcessor 处理的是 <context:component-scan处理不到的类,即注解类里面嵌套的注解类
  17. String[] candidateNames = registry.getBeanDefinitionNames();
  18. for (String beanName : candidateNames) {
  19. BeanDefinition beanDef = registry.getBeanDefinition(beanName);
  20. //这里根据 beanDef 里面是否有 configurationClass 这个标记来判断 此beanDef 是否已经被处理过了
  21. if (beanDef.getAttribute(ConfigurationClassUtils.CONFIGURATION_CLASS_ATTRIBUTE) != null) {
  22. if (logger.isDebugEnabled()) {
  23. logger.debug("Bean definition has already been processed as a configuration class: " + beanDef);
  24. }
  25. }
  26. //这个方法有意思的
  27. //首先判断了下 beanDef 的类型
  28. //其次判断了下 beanDef 上有没有 @Configuration注解,如果有设置 configurationClass为 full,否则设置为lite
  29. //如果为 full 这在创建对象时则创建代理对象, 否则则走spring正常创建对象的逻辑,具体逻辑可以看 postProcessBeanFactory
  30. else if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) {
  31. //这里将 beanDef 包装成 BeanDefinitionHolder并加入到
  32. configCandidates.add(new BeanDefinitionHolder(beanDef, beanName));
  33. }
  34. }
  35. // Return immediately if no @Configuration classes were found
  36. if (configCandidates.isEmpty()) {
  37. return;
  38. }
  39. // Sort by previously determined @Order value, if applicable
  40. configCandidates.sort((bd1, bd2) -> {
  41. int i1 = ConfigurationClassUtils.getOrder(bd1.getBeanDefinition());
  42. int i2 = ConfigurationClassUtils.getOrder(bd2.getBeanDefinition());
  43. return Integer.compare(i1, i2);
  44. });
  45. // Detect any custom bean name generation strategy supplied through the enclosing application context
  46. SingletonBeanRegistry sbr = null;
  47. if (registry instanceof SingletonBeanRegistry) {
  48. sbr = (SingletonBeanRegistry) registry;
  49. if (!this.localBeanNameGeneratorSet) {
  50. BeanNameGenerator generator = (BeanNameGenerator) sbr.getSingleton(
  51. AnnotationConfigUtils.CONFIGURATION_BEAN_NAME_GENERATOR);
  52. if (generator != null) {
  53. this.componentScanBeanNameGenerator = generator;
  54. this.importBeanNameGenerator = generator;
  55. }
  56. }
  57. }
  58. if (this.environment == null) {
  59. this.environment = new StandardEnvironment();
  60. }
  61. // Parse each @Configuration class
  62. //这里创建了一个解析具体bean标签的处理类
  63. ConfigurationClassParser parser = new ConfigurationClassParser(
  64. this.metadataReaderFactory, this.problemReporter, this.environment,
  65. this.resourceLoader, this.componentScanBeanNameGenerator, registry);
  66. //所有解析到的 BeanDefinition定义信息放到 candidates 中
  67. Set<BeanDefinitionHolder> candidates = new LinkedHashSet<>(configCandidates);
  68. //所有已经放到BeanFactory的BeanDefinition定义信息放到 alreadyParsed 中
  69. Set<ConfigurationClass> alreadyParsed = new HashSet<>(configCandidates.size());
  70. do {
  71. //具体解析标签的类
  72. parser.parse(candidates);
  73. parser.validate();
  74. // 解析完成的 BeanDefinition定义信息 先放到 parser.getConfigurationClasses()
  75. // 然后再放到 configClasses
  76. Set<ConfigurationClass> configClasses = new LinkedHashSet<>(parser.getConfigurationClasses());
  77. configClasses.removeAll(alreadyParsed);
  78. // Read the model and create bean definitions based on its content
  79. if (this.reader == null) {
  80. this.reader = new ConfigurationClassBeanDefinitionReader(
  81. registry, this.sourceExtractor, this.resourceLoader, this.environment,
  82. this.importBeanNameGenerator, parser.getImportRegistry());
  83. }
  84. //将解析到的 BeanDefinition定义信息放到 BeanFactory中
  85. this.reader.loadBeanDefinitions(configClasses);
  86. alreadyParsed.addAll(configClasses);
  87. candidates.clear();
  88. if (registry.getBeanDefinitionCount() > candidateNames.length) {
  89. String[] newCandidateNames = registry.getBeanDefinitionNames();
  90. Set<String> oldCandidateNames = new HashSet<>(Arrays.asList(candidateNames));
  91. Set<String> alreadyParsedClasses = new HashSet<>();
  92. for (ConfigurationClass configurationClass : alreadyParsed) {
  93. alreadyParsedClasses.add(configurationClass.getMetadata().getClassName());
  94. }
  95. for (String candidateName : newCandidateNames) {
  96. if (!oldCandidateNames.contains(candidateName)) {
  97. BeanDefinition bd = registry.getBeanDefinition(candidateName);
  98. if (ConfigurationClassUtils.checkConfigurationClassCandidate(bd, this.metadataReaderFactory) &&
  99. !alreadyParsedClasses.contains(bd.getBeanClassName())) {
  100. candidates.add(new BeanDefinitionHolder(bd, candidateName));
  101. }
  102. }
  103. }
  104. candidateNames = newCandidateNames;
  105. }
  106. }
  107. while (!candidates.isEmpty());
  108. // Register the ImportRegistry as a bean in order to support ImportAware @Configuration classes
  109. if (sbr != null && !sbr.containsSingleton(IMPORT_REGISTRY_BEAN_NAME)) {
  110. sbr.registerSingleton(IMPORT_REGISTRY_BEAN_NAME, parser.getImportRegistry());
  111. }
  112. if (this.metadataReaderFactory instanceof CachingMetadataReaderFactory) {
  113. // Clear cache in externally provided MetadataReaderFactory; this is a no-op
  114. // for a shared cache since it'll be cleared by the ApplicationContext.
  115. ((CachingMetadataReaderFactory) this.metadataReaderFactory).clearCache();
  116. }
  117. }

下面我们重点关注下 ConfigurationClassParser的 parse(candidates); 方法

ConfigurationClassParser -> parse(Set<BeanDefinitionHolder> configCandidates)
  1. public void parse(Set<BeanDefinitionHolder> configCandidates) {
  2. for (BeanDefinitionHolder holder : configCandidates) {
  3. BeanDefinition bd = holder.getBeanDefinition();
  4. try {
  5. if (bd instanceof AnnotatedBeanDefinition) {
  6. parse(((AnnotatedBeanDefinition) bd).getMetadata(), holder.getBeanName());
  7. }
  8. else if (bd instanceof AbstractBeanDefinition && ((AbstractBeanDefinition) bd).hasBeanClass()) {
  9. parse(((AbstractBeanDefinition) bd).getBeanClass(), holder.getBeanName());
  10. }
  11. else {
  12. parse(bd.getBeanClassName(), holder.getBeanName());
  13. }
  14. }
  15. catch (BeanDefinitionStoreException ex) {
  16. throw ex;
  17. }
  18. catch (Throwable ex) {
  19. throw new BeanDefinitionStoreException(
  20. "Failed to parse configuration class [" + bd.getBeanClassName() + "]", ex);
  21. }
  22. }
  23. this.deferredImportSelectorHandler.process();
  24. }

ConfigurationClassParser -> parse(AnnotationMetadata metadata, String beanName)

ConfigurationClassParser ->processConfigurationClass(ConfigurationClass configClass, Predicate<String> filter)

  1. protected void processConfigurationClass(ConfigurationClass configClass, Predicate<String> filter) throws IOException {
  2. if (this.conditionEvaluator.shouldSkip(configClass.getMetadata(), ConfigurationPhase.PARSE_CONFIGURATION)) {
  3. return;
  4. }
  5. ConfigurationClass existingClass = this.configurationClasses.get(configClass);
  6. if (existingClass != null) {
  7. if (configClass.isImported()) {
  8. if (existingClass.isImported()) {
  9. existingClass.mergeImportedBy(configClass);
  10. }
  11. // Otherwise ignore new imported config class; existing non-imported class overrides it.
  12. return;
  13. }
  14. else {
  15. // Explicit bean definition found, probably replacing an import.
  16. // Let's remove the old one and go with the new one.
  17. this.configurationClasses.remove(configClass);
  18. this.knownSuperclasses.values().removeIf(configClass::equals);
  19. }
  20. }
  21. // Recursively process the configuration class and its superclass hierarchy.
  22. SourceClass sourceClass = asSourceClass(configClass, filter);
  23. do {
  24. sourceClass = doProcessConfigurationClass(configClass, sourceClass, filter);
  25. }
  26. while (sourceClass != null);
  27. this.configurationClasses.put(configClass, configClass);
  28. }

我们还是直奔主题  ConfigurationClassParser -> doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass, Predicate<String> filter)

  1. /**
  2. * Apply processing and build a complete {@link ConfigurationClass} by reading the
  3. * annotations, members and methods from the source class. This method can be called
  4. * multiple times as relevant sources are discovered.
  5. * @param configClass the configuration class being build
  6. * @param sourceClass a source class
  7. * @return the superclass, or {@code null} if none found or previously processed
  8. */
  9. @Nullable
  10. protected final SourceClass doProcessConfigurationClass(
  11. ConfigurationClass configClass, SourceClass sourceClass, Predicate<String> filter)
  12. throws IOException {
  13. // 解析 @Component 注解的类,这里面会递归执行到 @Component注解的类里面是否还有注解类
  14. if (configClass.getMetadata().isAnnotated(Component.class.getName())) {
  15. // Recursively process any member (nested) classes first
  16. processMemberClasses(configClass, sourceClass, filter);
  17. }
  18. // Process any @PropertySource annotations
  19. // 解析 @PropertySources 注解的类
  20. for (AnnotationAttributes propertySource : AnnotationConfigUtils.attributesForRepeatable(
  21. sourceClass.getMetadata(), PropertySources.class,
  22. org.springframework.context.annotation.PropertySource.class)) {
  23. if (this.environment instanceof ConfigurableEnvironment) {
  24. processPropertySource(propertySource);
  25. }
  26. else {
  27. logger.info("Ignoring @PropertySource annotation on [" + sourceClass.getMetadata().getClassName() +
  28. "]. Reason: Environment must implement ConfigurableEnvironment");
  29. }
  30. }
  31. // Process any @ComponentScan annotations
  32. // 解析 @ComponentScans @ComponentScan 注解的类
  33. Set<AnnotationAttributes> componentScans = AnnotationConfigUtils.attributesForRepeatable(
  34. sourceClass.getMetadata(), ComponentScans.class, ComponentScan.class);
  35. if (!componentScans.isEmpty() &&
  36. !this.conditionEvaluator.shouldSkip(sourceClass.getMetadata(), ConfigurationPhase.REGISTER_BEAN)) {
  37. for (AnnotationAttributes componentScan : componentScans) {
  38. // The config class is annotated with @ComponentScan -> perform the scan immediately
  39. //这里会扫描 ComponentScans basePackages 定义的包下面的所有类是否有被 @Component 修饰
  40. // 将ComponentScans basePackages 定义的包下面的所有被 @Component 修饰的类都解析过来
  41. Set<BeanDefinitionHolder> scannedBeanDefinitions =
  42. this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName());
  43. // Check the set of scanned definitions for any further config classes and parse recursively if needed
  44. for (BeanDefinitionHolder holder : scannedBeanDefinitions) {
  45. BeanDefinition bdCand = holder.getBeanDefinition().getOriginatingBeanDefinition();
  46. if (bdCand == null) {
  47. bdCand = holder.getBeanDefinition();
  48. }
  49. if (ConfigurationClassUtils.checkConfigurationClassCandidate(bdCand, this.metadataReaderFactory)) {
  50. parse(bdCand.getBeanClassName(), holder.getBeanName());
  51. }
  52. }
  53. }
  54. }
  55. // Process any @Import annotations
  56. // 解析 @Import注解,spring boot 自动注入大量的用到了这玩意儿
  57. processImports(configClass, sourceClass, getImports(sourceClass), filter, true);
  58. // Process any @ImportResource annotations
  59. AnnotationAttributes importResource =
  60. AnnotationConfigUtils.attributesFor(sourceClass.getMetadata(), ImportResource.class);
  61. if (importResource != null) {
  62. String[] resources = importResource.getStringArray("locations");
  63. Class<? extends BeanDefinitionReader> readerClass = importResource.getClass("reader");
  64. for (String resource : resources) {
  65. String resolvedResource = this.environment.resolveRequiredPlaceholders(resource);
  66. configClass.addImportedResource(resolvedResource, readerClass);
  67. }
  68. }
  69. // Process individual @Bean methods
  70. //解析@Bean注解
  71. // 这里有个问题
  72. /**
  73. //1、@Configuration
  74. //2、@Component
  75. public class PersonConfiguration1 {
  76. @Bean
  77. private PersonConfiguration2 personConfiguration2(){
  78. return new PersonConfiguration2();
  79. }
  80. }
  81. 这里这段代码不论是用 1、@Configuration 还是用 2、@Component 最后得到的 PersonConfiguration2 都是单例的
  82. 但是使用 1、@Configuration 注解的 PersonConfiguration1 会被注入成一个代理类
  83. 所以网上说的使用 @Configuration 配置的类必须要被代理是为了解决 bean 的单例问题肯定是错的
  84. 不论是用 @Configuration 还是用 2、@Component 里面定义的 @Bean 注解最终都是走的 FactoryMethod 方法被实例化的
  85. * **/
  86. Set<MethodMetadata> beanMethods = retrieveBeanMethodMetadata(sourceClass);
  87. for (MethodMetadata methodMetadata : beanMethods) {
  88. configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));
  89. }
  90. // Process default methods on interfaces
  91. /**
  92. public interface MyInterfaces {
  93. @Bean
  94. PersonConfiguration1 personConfiguration1();
  95. }
  96. * **/
  97. // 如果接口中也定义有@Bean 则走这里解析
  98. processInterfaces(configClass, sourceClass);
  99. // Process superclass, if any
  100. if (sourceClass.getMetadata().hasSuperClass()) {
  101. String superclass = sourceClass.getMetadata().getSuperClassName();
  102. if (superclass != null && !superclass.startsWith("java") &&
  103. !this.knownSuperclasses.containsKey(superclass)) {
  104. this.knownSuperclasses.put(superclass, configClass);
  105. // Superclass found, return its annotation metadata and recurse
  106. return sourceClass.getSuperClass();
  107. }
  108. }
  109. // No superclass -> processing is complete
  110. return null;
  111. }

经过上面 ConfigurationClassPostProcessor 的 postProcessBeanDefinitionRegistry 的方法处理所有需要spring容器进行实例化的BeanDefinition都已经被放到了BeanFactory中

后面 ConfigurationClassPostProcessor 还有一个 postProcessBeanFactory 方法,这个方法主要就是给 标注了 @Configuration的注解类生成一个代理的class类,在后面实例化的时候调用代理类的class类生成代理对象

请大家关注下博客谢谢

原文链接:https://blog.csdn.net/luhaichuan88/article/details/117256406



所属网站分类: 技术文章 > 博客

作者:快起来搬砖啦

链接:http://www.javaheidong.com/blog/article/208032/ace4886caadf1555c52a/

来源:java黑洞网

任何形式的转载都请注明出处,如有侵权 一经发现 必将追究其法律责任

9 0
收藏该文
已收藏

评论内容:(最多支持255个字符)