• spring实现基于注解的@Bean配置原理


    spring的  @Bean @import 等都是注解式的配置,简化了通过xml形式的配置,它们是如何生效的?

    注意@Componnet @Controller  @Service @Repotory @configration 这几个配置类既可以在容器启动时通过ClassPathBeanDefinitionScanner指定包名扫描进容器; 也可以通过后置处理器在ComponentScanAnnotationParser配合@ComponnetScan注解指定包和属性在回调中扫描进容器。

     chatgpt免费体验:http://www.chat136.com

    chatgpt学习:http://me.chat136.com

    而@Bean @import只能通过后置处理器实现bean的装载。ClassPathBeanDefinitionScanner只是装载有@Componnet注解的bean。

    而由于@Controller  @Service @Repotory @configration也是@Componnet的复合注解所以也可以通过scan方法中扫描注入。

    @import不管普通类还是配置类都是通过后置处理器加到容器中。所以比如springboot中大量运用@import来加载 @configration和@bean的类。

    1. Application构造函数

    public AnnotationConfigApplicationContext(String... basePackages) {
    
       this();
       scan(basePackages);
       refresh();
    }

    通过ConfigurationClassPostProcessor这个bean工厂后置处理器实现加载进spring的,ConfigurationClassPostProcessor是spring容器的底层组件实现了BeanFactoryPostProcessor接口注意不是BeanPostProcessor接口,这个接口的类在refresh方法容器的自定义bean初始化之前会被容器回调从而可以修改或增加bean定义, 是通过ApplicationContext构造函数时加载进容器的,下面看一下spring的源码从AnnotationConfigApplicationContext开始。

    2. 上面this()无参构造函数会通过一系列调用链到这个方法org.springframework.context.annotation.AnnotationConfigUtils#registerAnnotationConfigProcessors(org.springframework.beans.factory.support.BeanDefinitionRegistry, java.lang.Object)

     registerAnnotationConfigProcessors方法会注册spring底层的一些组件,包括前面实现自动扫描的ConfigurationClassPostProcessor这个后置处理器。

    public static Set registerAnnotationConfigProcessors(
          BeanDefinitionRegistry registry, @Nullable Object source) {
    
       DefaultListableBeanFactory beanFactory = unwrapDefaultListableBeanFactory(registry);
       if (beanFactory != null) {
          if (!(beanFactory.getDependencyComparator() instanceof AnnotationAwareOrderComparator)) {
             beanFactory.setDependencyComparator(AnnotationAwareOrderComparator.INSTANCE);
          }
          if (!(beanFactory.getAutowireCandidateResolver() instanceof ContextAnnotationAutowireCandidateResolver)) {
             beanFactory.setAutowireCandidateResolver(new ContextAnnotationAutowireCandidateResolver());
          }
       }
    
       Set beanDefs = new LinkedHashSet<>(4);
    
       //这是注册ConfigurationClassPostProcessor进容器
       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));
       }
    
       if (!registry.containsBeanDefinition(AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME)) {
          RootBeanDefinition def = new RootBeanDefinition(AutowiredAnnotationBeanPostProcessor.class);
          def.setSource(source);
          beanDefs.add(registerPostProcessor(registry, def, AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME));
       }
    
       if (!registry.containsBeanDefinition(REQUIRED_ANNOTATION_PROCESSOR_BEAN_NAME)) {
          RootBeanDefinition def = new RootBeanDefinition(RequiredAnnotationBeanPostProcessor.class);
          def.setSource(source);
          beanDefs.add(registerPostProcessor(registry, def, REQUIRED_ANNOTATION_PROCESSOR_BEAN_NAME));
       }
    
       // Check for JSR-250 support, and if present add the CommonAnnotationBeanPostProcessor.
       if (jsr250Present && !registry.containsBeanDefinition(COMMON_ANNOTATION_PROCESSOR_BEAN_NAME)) {
          RootBeanDefinition def = new RootBeanDefinition(CommonAnnotationBeanPostProcessor.class);
          def.setSource(source);
          beanDefs.add(registerPostProcessor(registry, def, COMMON_ANNOTATION_PROCESSOR_BEAN_NAME));
       }
    
       // Check for JPA support, and if present add the PersistenceAnnotationBeanPostProcessor.
       if (jpaPresent && !registry.containsBeanDefinition(PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME)) {
          RootBeanDefinition def = new RootBeanDefinition();
          try {
             def.setBeanClass(ClassUtils.forName(PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME,
                   AnnotationConfigUtils.class.getClassLoader()));
          }
          catch (ClassNotFoundException ex) {
             throw new IllegalStateException(
                   "Cannot load optional framework class: " + PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME, ex);
          }
          def.setSource(source);
          beanDefs.add(registerPostProcessor(registry, def, PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME));
       }
    
       if (!registry.containsBeanDefinition(EVENT_LISTENER_PROCESSOR_BEAN_NAME)) {
          RootBeanDefinition def = new RootBeanDefinition(EventListenerMethodProcessor.class);
          def.setSource(source);
          beanDefs.add(registerPostProcessor(registry, def, EVENT_LISTENER_PROCESSOR_BEAN_NAME));
       }
       if (!registry.containsBeanDefinition(EVENT_LISTENER_FACTORY_BEAN_NAME)) {
          RootBeanDefinition def = new RootBeanDefinition(DefaultEventListenerFactory.class);
          def.setSource(source);
          beanDefs.add(registerPostProcessor(registry, def, EVENT_LISTENER_FACTORY_BEAN_NAME));
       }
    
       return beanDefs;
    }

    3. 看一下AbstractApplictionContext的refresh方法

    @Override
    public void refresh() throws BeansException, IllegalStateException {
       synchronized (this.startupShutdownMonitor) {
          // Prepare this context for refreshing.
          prepareRefresh();
    
          // Tell the subclass to refresh the internal bean factory.
          ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
    
          // Prepare the bean factory for use in this context.
          prepareBeanFactory(beanFactory);
    
          try {
             // Allows post-processing of the bean factory in context subclasses.
             postProcessBeanFactory(beanFactory);
    
             // Invoke factory processors registered as beans in the context.这里会回回调所有的       BeanFactoryPostProcess ,包括ConfigurationClassPostProcessor
             invokeBeanFactoryPostProcessors(beanFactory);
    
             // Register bean processors that intercept bean creation.
             registerBeanPostProcessors(beanFactory);
    
             // Initialize message source for this context.
             initMessageSource();
    
             // Initialize event multicaster for this context.
             initApplicationEventMulticaster();
    
             // Initialize other special beans in specific context subclasses.
             onRefresh();
    
             // Check for listener beans and register them.
             registerListeners();
    
             // Instantiate all remaining (non-lazy-init) singletons.
             finishBeanFactoryInitialization(beanFactory);
    
             // Last step: publish corresponding event.
             finishRefresh();
          }
    
          catch (BeansException ex) {
             if (logger.isWarnEnabled()) {
                logger.warn("Exception encountered during context initialization - " +
                      "cancelling refresh attempt: " + ex);
             }
    
             // Destroy already created singletons to avoid dangling resources.
             destroyBeans();
    
             // Reset 'active' flag.
             cancelRefresh(ex);
    
             // Propagate exception to caller.
             throw ex;
          }
    
          finally {
             // Reset common introspection caches in Spring's core, since we
             // might not ever need metadata for singleton beans anymore...
             resetCommonCaches();
          }
       }
    }

    4. 下面看一下ConfigurationClassPostProcessor具体是怎么实现基于注解的bean加载的

    org.springframework.context.annotation.ConfigurationClassPostProcessor#postProcessBeanDefinitionRegistry 这个方法会被spring在refresh()里面自动回调

    @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);
    }

    org.springframework.context.annotation.ConfigurationClassPostProcessor#processConfigBeanDefinitions

    public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
       List configCandidates = new ArrayList<>();
       String[] candidateNames = registry.getBeanDefinitionNames();//获取当前容器所有的bean的名称,这是bean还没初始化
    
       for (String beanName : candidateNames) {
          BeanDefinition beanDef = registry.getBeanDefinition(beanName);//获取beanDeinition,包含bean的配置信息如注解,方法,构造函数,class信息都放在BeanDefinition里
          if (ConfigurationClassUtils.isFullConfigurationClass(beanDef) ||
                ConfigurationClassUtils.isLiteConfigurationClass(beanDef)) {//检查是否是配置bean即包含@Configration,@Componet  @ComponentScan @Import @ImportSouce 注解(@Controller @Service注解式是@Component的复合注解),如果没有就跳过
             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  //这个parse类重要,里面存有处理后生成的class信息,处理方法也封装进这个类里,这里传入上面configcadidates列表,这个类内部的方法处理完毕后,结果返回beandifiniton列表再加载进容器
       ConfigurationClassParser parser = new ConfigurationClassParser(
             this.metadataReaderFactory, this.problemReporter, this.environment,
             this.resourceLoader, this.componentScanBeanNameGenerator, registry);
    
       Set candidates = new LinkedHashSet<>(configCandidates);
       Set alreadyParsed = new HashSet<>(configCandidates.size());
       do {
          parser.parse(candidates);//处理上面得到的canditates
          parser.validate();//验证
          // 这个parser.getConfigurationClasses() 是返回处理后的配置类信息,即把@Configration @Componet @Bean等解析为一个个BeanDifition的基础信息
          Set 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);//把处理得到Bean定义信息装载进容器
          alreadyParsed.addAll(configClasses);
    
          candidates.clear();//判断是否有新的类装进容器了,有就检查进行下个循环
          if (registry.getBeanDefinitionCount() > candidateNames.length) {//这里的循环意思是每次装载完处理生成的bean定义信息后,重新检查容器是否还有待处理的配置类,因为上一次装载进容器的可能是新的配置类,比如a配置类在上一批次装载了b配置类进容器,a配置类已经处理完了,但新装载的b配置类还没处理过,要重新检查容器继续处理b配置类,直到素有的配置类处理完毕,就是所有包含@Configration @Component等的类都处理完成了 不会再加载新的类
             String[] newCandidateNames = registry.getBeanDefinitionNames();
             Set oldCandidateNames = new HashSet<>(Arrays.asList(candidateNames));
             Set 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())) {// 这里检查是否是配置类即包含@Configration @Component等注解
                      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();
       }
    }

    5.下面看一下 parser.parse(candidates)这个方法是怎么实现的

    该方法会调到这里,下面的几个方法都是在parser类里定义的。

    public void parse(Set configCandidates) {
       this.deferredImportSelectors = new LinkedList<>();
    //这个循环是逐个处理外面传进来的配置类信息
       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);
          }
       }
    
       processDeferredImportSelectors();
    }
     
    
    protected final void parse(AnnotationMetadata metadata, String beanName) throws IOException {
    processConfigurationClass(new ConfigurationClass(metadata, beanName));
    }

    protected void processConfigurationClass(ConfigurationClass configClass) throws IOException {
    //这里ConfigurationClass 是封装了上面待处理的配置类beandifinition信息
      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);
       do {//这里sourceClass返回的待处理配置类的父类即循环递归处理父类信息
          sourceClass = doProcessConfigurationClass(configClass, sourceClass);
       }
       while (sourceClass != null);
       //这里是加入处理完成的配置类信息列表configurationClasse  这个列表是该类全局共享的属性,后面会返回给外部调用方
       this.configurationClasses.put(configClass, configClass);
    }
    org.springframework.context.annotation.ConfigurationClassParser#doProcessConfigurationClass
    
    @Nullable
    protected final SourceClass doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass)
          throws IOException {
    
       // Recursively process any member (nested) classes first
       processMemberClasses(configClass, sourceClass);//递归处理处理成员内部类,里面回调外层的      
                                                                     processConfigurationClass方法。
       // 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 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 //这里使用componnetScanParser扫描@Component注解直接装进容器,而componentScanParser内部使用的是ClassPathBeanDefinitionScanner类,该类构造函数指定扫描类型为@Component的bean,   再判断bean是否是配置类即如果含有是@Configration @Import等注解标注的配置类 递归调用parse方法。
             Set 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);//这里处理@import标签
    
       // Process any @ImportResource annotations
       AnnotationAttributes importResource =
             AnnotationConfigUtils.attributesFor(sourceClass.getMetadata(), ImportResource.class);
       if (importResource != null) {
          String[] resources = importResource.getStringArray("locations");
          Classextends BeanDefinitionReader> readerClass = importResource.getClass("reader");
          for (String resource : resources) {
             String resolvedResource = this.environment.resolveRequiredPlaceholders(resource);
             configClass.addImportedResource(resolvedResource, readerClass);
          }
       }
    
       // Process individual @Bean methods
       Set 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();
          }
       }
    //上面的这几个方法都是parser类里定义的,执行结束后 parser类里其实已经填充了处理后的信息,这里相当于设计模式解析器模式
       // No superclass -> processing is complete
       return null;
    }
    

    解析结束,下面是把bean定义载入进容器,从而实现基于注解的配置

    Set configurationModel是parse类解析后得到的bean定义信息org.springframework.context.annotation.ConfigurationClassBeanDefinitionReader#loadBeanDefinitions
    public void loadBeanDefinitions(Set configurationModel) {
       TrackedConditionEvaluator trackedConditionEvaluator = new TrackedConditionEvaluator();
       for (ConfigurationClass configClass : configurationModel) {
          loadBeanDefinitionsForConfigurationClass(configClass, trackedConditionEvaluator);
       }
    }

     /**

     * 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) {
    
       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()) {
            //载入通过@import标签引入的bean
          registerBeanDefinitionForImportedConfigurationClass(configClass);
       }
       for (BeanMethod beanMethod : configClass.getBeanMethods()) {
            //载入通过通过@bean方式引入的bean
          loadBeanDefinitionsForBeanMethod(beanMethod);
       }
        //载入@importResources     
       loadBeanDefinitionsFromImportedResources(configClass.getImportedResources());
    // 这个也是@import
       loadBeanDefinitionsFromRegistrars(configClass.getImportBeanDefinitionRegistrars());
    }

    至此@bean配置类装载进了容器。 

  • 相关阅读:
    WPF工控组态软件之冷却塔和空气压缩机开发
    蓝桥杯 微生物增殖 C语言
    linux ping IP地址与telnet 测试IP端口
    HTML - 请你谈一谈img标签图片和background背景图片的区别
    Netty架构设计
    第二十四章 数据检测类型
    第九章 字符串处理函数
    centos 7.9 源码安装htop
    SRM系统可以为企业带来什么价值?
    Unity & PS Linear Workflow - Unity 和 PS 的线性工作流实践 - 简单配置示例(后续补上渲染差异图)
  • 原文地址:https://blog.csdn.net/heikeb/article/details/126571825