关于java:Spring源码之Configuration

41次阅读

共计 28033 个字符,预计需要花费 71 分钟才能阅读完成。

Spring 源码之 @Configuration

@Configuration 注解提供了全新的 bean 创立形式。最后 spring 通过 xml 配置文件初始化 bean 并实现依赖注入工作。从 spring3.0 开始,在 spring framework 模块中提供了这个注解,搭配 @Bean 等注解,能够齐全不依赖 xml 配置,在运行时实现 bean 的创立和初始化工作。例如:

public interface IBean {

}

public class AppBean implements IBean{

}

// @Configuration 申明了 AppConfig 是一个配置类
@Configuration 
// 显式扫描需应用组件
@ComponentScan("xxx.xxx")
public class AppConfig {
    // @Bean 注解申明了一个 bean,bean 名称默认为办法名 appBean
    // 默认状况下 bean 的名称和办法名称雷同
    @Bean 
    IBean appBean(){return new AppBean();
    }
}

@Configuration 注解应用

Configuration.java

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
// @Component 元注解,因而能够被 @ComponentScan 扫描并解决
@Component
public @interface Configuration {@AliasFor(annotation = Component.class)
    String value() default "";}

在这里意识几个注解: @Controller, @Service, @Repository, @Component

  • @Controller: 表明一个注解的类是一个 ”Controller”,也就是控制器,能够把它了解为 MVC 模式的 Controller 这个角色。这个注解是一个非凡的 @Component,容许实现类通过类门路的扫描扫描到。它通常与 @RequestMapping 注解一起应用。
  • @Service: 表明这个带注解的类是一个 ”Service”,也就是服务层,能够把它了解为 MVC 模式中的 Service 层这个角色,这个注解也是一个非凡的 @Component,容许实现类通过类门路的扫描扫描到
  • @Repository: 表明这个注解的类是一个 ”Repository”, 团队实现了 JavaEE 模式中像是作为 ”Data Access Object” 可能作为 DAO 来应用,当与 PersistenceExceptionTranslationPostProcessor 联合应用时,这样正文的类有资格取得 Spring 转换的目标。这个注解也是 @Component 的一个非凡实现,容许实现类可能被主动扫描到
  • @Component: 表明这个正文的类是一个组件,当应用基于正文的配置和类门路扫描时,这些类被视为自动检测的候选者。
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Controller {@AliasFor(annotation = Component.class)
    String value() default "";}

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Service {@AliasFor(annotation = Component.class)
    String value() default "";}

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Repository {@AliasFor(annotation = Component.class)
    String value() default "";}

咱们能够看到 @Controller, @Service, @Repository 这三个注解上都有 @Component 这个注解

也就是说,下面四个注解标记的类都可能通过 @ComponentScan 扫描到,下面四个注解最大的区别就是应用的场景和语义不一样,比方你定义一个 Service 类想要被 Spring 进行治理,你应该把它定义为 @Service 而不是 @Controller 因为咱们从语义上讲,@Service 更像是一个服务的类,而不是一个控制器的类,@Component 通常被称作组件,它能够标注任何你没有严格予以阐明的类,比如说是一个配置类,它不属于 MVC 模式的任何一层,这个时候你更习惯于把它定义为 @Component。@Controller,@Service,@Repository 的注解上都有 @Component,所以这三个注解都能够用 @Component 进行替换。

配置类束缚

  • 配置类必须为显式申明的类,而不能通过工厂类办法返回实例。容许运行时类加强。
  • 配置类不容许标记 final。
  • 配置类必须全局可见(不容许定义在办法本地外部类中)
  • 嵌套配置类必须申明为 static 外部类
  • @Bean 办法不能够再创立新的配置类(所有实例都当做 bean 解决,不解析相干配置注解)

@Configuration 源码

ApplicationContext 的 refresh 办法

Spring 容器启动时,即 ApplicationContext 接口实现类的对象实例执行 refresh 办法时,在 Bean 初始化实现之前,有一个扩大点,用来操作 BeanFactory,来扩大对应的性能,比方往 BeanFactory 中注册 BeanDefintion:

public void refresh() throws BeansException, IllegalStateException {synchronized (this.startupShutdownMonitor) {
        // 筹备刷新的上下文 环境
        prepareRefresh();
        // 初始化 BeanFactory,并进行 XML 文件读取
        ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
        // 对 beanFactory 进行各种性能填充
        prepareBeanFactory(beanFactory);
        try {postProcessBeanFactory(beanFactory);
            // 激活各种 beanFactory 处理器
            invokeBeanFactoryPostProcessors(beanFactory);
            // 注册拦挡 Bean 创立的 Bean 处理器,这里只是注册,真正的调用切实 getBean 时候
            registerBeanPostProcessors(beanFactory);
            // 为上下文初始化 Message 源,即不同语言的音讯体,国际化解决
            initMessageSource();
            // 初始化利用音讯播送器,并放入“applicationEventMulticaster”bean 中
            initApplicationEventMulticaster();
            // 留给子类来初始化其它的 Bean
            onRefresh();
            // 在所有注册的 bean 中查找 Listener bean,注册到音讯播送器中
            registerListeners();
            // 初始化剩下的单实例(非惰性的)finishBeanFactoryInitialization(beanFactory);
            // 实现刷新过程,告诉生命周期处理器 lifecycleProcessor 刷新过程,同时收回 ContextRefreshEvent 告诉他人
            finishRefresh();}
        catch (BeansException ex) {if (logger.isWarnEnabled()) {
                logger.warn("Exception encountered during context initialization -" +
                        "cancelling refresh attempt:" + ex);
            }
            destroyBeans();
            cancelRefresh(ex);
            throw ex;
        }
        finally {resetCommonCaches();
        }
    }
}

invokeBeanFactoryPostProcessors:

public static void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) {

    // Invoke BeanDefinitionRegistryPostProcessors first, if any.
    // 1、首先调用 BeanDefinitionRegistryPostProcessors
    Set<String> processedBeans = new HashSet<>();

    // beanFactory 是 BeanDefinitionRegistry 类型
    if (beanFactory instanceof BeanDefinitionRegistry) {BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;
        // 定义 BeanFactoryPostProcessor
        List<BeanFactoryPostProcessor> regularPostProcessors = new ArrayList<>();
        // 定义 BeanDefinitionRegistryPostProcessor 汇合
        List<BeanDefinitionRegistryPostProcessor> registryProcessors = new ArrayList<>();

        // 循环手动注册的 beanFactoryPostProcessors
        for (BeanFactoryPostProcessor postProcessor : beanFactoryPostProcessors) {
            // 如果是 BeanDefinitionRegistryPostProcessor 的实例话, 则调用其 postProcessBeanDefinitionRegistry 办法, 对 bean 进行注册操作
            if (postProcessor instanceof BeanDefinitionRegistryPostProcessor) {
                // 如果是 BeanDefinitionRegistryPostProcessor 类型, 则间接调用其 postProcessBeanDefinitionRegistry
                BeanDefinitionRegistryPostProcessor registryProcessor = (BeanDefinitionRegistryPostProcessor) postProcessor;
                registryProcessor.postProcessBeanDefinitionRegistry(registry);
                registryProcessors.add(registryProcessor);
            }
            // 否则则将其当做一般的 BeanFactoryPostProcessor 解决, 间接退出 regularPostProcessors 汇合, 以备后续解决
            else {regularPostProcessors.add(postProcessor);
            }
        }
        // 略....
    }

    // 2、如果不是 BeanDefinitionRegistry 的实例, 那么间接调用其回调函数即可 -->postProcessBeanFactory
    else {
        // Invoke factory processors registered with the context instance.
        invokeBeanFactoryPostProcessors(beanFactoryPostProcessors, beanFactory);
    }
    // 略....
}

而 ConfigurationClassPostProcessor.java

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);
   // 解析 Java 类配置 bean
   processConfigBeanDefinitions(registry);
}

processConfigBeanDefinitions(registry):

public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {List<BeanDefinitionHolder> configCandidates = new ArrayList<>();
  // 所有曾经注册的 bean 
   String[] candidateNames = registry.getBeanDefinitionNames();
   // 遍历 bean 定义信息
   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);
         }
      }
    //1. 如果以后的 bean 是 Javabean 配置类(含有 @Configuration 注解的类),则退出到汇合 configCandidates 中,else if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) {configCandidates.add(new BeanDefinitionHolder(beanDef, beanName));
      }
   }

   // Return immediately if no @Configuration classes were found
  // 没有 @Configuration 注解的类,间接退出
   if (configCandidates.isEmpty()) {return;}

   // 多个 Java 配置类,按 @Ordered 注解排序
   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 解析器,能够解析 @Congiguration 配置类
   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 {
   //2. 解析 Java 配置类
      parser.parse(candidates);
   // 次要校验配置类不能应用 final 修饰符(CGLIB 代理是生成一个子类,因而原先的类不能应用 final 润饰)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());
      }
    //3. 加载 bean 定义信息,次要实现将 @bean @Configuration @Import @ImportResource @ImportRegistrar 注册为 bean
      this.reader.loadBeanDefinitions(configClasses);
      alreadyParsed.addAll(configClasses);
      // 清空已解决的配置类
      candidates.clear();
   // 再次获取容器中 bean 定义数量  如果大于 之前获取的 bean 定义数量,则阐明有新的 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);
        // 新注册的 bean 如果也是 @Configuration 配置类, 则增加到数据,期待解析
               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();}
}

processConfigBeanDefinitions 整个办法能够大体划分为三个阶段:

  1. 从容器中获取和 Configuration 有关系的 BeanDefinition
  2. 以该 BeanDefinition 为终点,进行解析操作,失去解析后果集
  3. 将解析到的后果集加载到容器中,即结构成一个 BeanDefinition 放到容器中待初始化

ConfigurationClassUtils.checkConfigurationClassCandidate 判断类是否与 @Configuration 无关

public static boolean checkConfigurationClassCandidate(BeanDefinition beanDef, MetadataReaderFactory metadataReaderFactory) {String className = beanDef.getBeanClassName();
    if (className == null || beanDef.getFactoryMethodName() != null) {return false;}
    // 获取注解元数据信息
    AnnotationMetadata metadata;
    if (beanDef instanceof AnnotatedBeanDefinition &&
            className.equals(((AnnotatedBeanDefinition) beanDef).getMetadata().getClassName())) {metadata = ((AnnotatedBeanDefinition) beanDef).getMetadata();}
    else if (beanDef instanceof AbstractBeanDefinition && ((AbstractBeanDefinition) beanDef).hasBeanClass()) {Class<?> beanClass = ((AbstractBeanDefinition) beanDef).getBeanClass();
        metadata = new StandardAnnotationMetadata(beanClass, true);
    }
    else {
        try {MetadataReader metadataReader = metadataReaderFactory.getMetadataReader(className);
            metadata = metadataReader.getAnnotationMetadata();}
        catch (IOException ex) {return false;}
    }
    // 查找以后注解是否是与 @Configuration 相干
    // 该办法还会判断该注解上的注解是否有 @Configuration,始终往上寻找
    // 因为有的注解为复合注解
    if (isFullConfigurationCandidate(metadata)) {beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, CONFIGURATION_CLASS_FULL);
    }
    // 查找以后注解上是否有 ComponentScan、Component、Import、ImportResource 注解
    // 如果没有则查找 Bean 注解,同上,始终往上查找
    else if (isLiteConfigurationCandidate(metadata)) {beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, CONFIGURATION_CLASS_LITE);
    }
    else {return false;}
    return true;
}

isFullConfigurationCandidate

    public static boolean isFullConfigurationCandidate(AnnotationMetadata metadata) {return metadata.isAnnotated(Configuration.class.getName());
    }

isLiteConfigurationCandidate

    public static boolean isLiteConfigurationCandidate(AnnotationMetadata metadata) {
        // Do not consider an interface or an annotation...
        if (metadata.isInterface()) {return false;}

        // Any of the typical annotations found?
        for (String indicator : candidateIndicators) {if (metadata.isAnnotated(indicator)) {return true;}
        }

        // Finally, let's look for @Bean methods...
        try {return metadata.hasAnnotatedMethods(Bean.class.getName());
        }
        catch (Throwable ex) {if (logger.isDebugEnabled()) {logger.debug("Failed to introspect @Bean methods on class [" + metadata.getClassName() + "]:" + ex);
            }
            return false;
        }
    }

    private static final Set<String> candidateIndicators = new HashSet<>(8);

    static {candidateIndicators.add(Component.class.getName());
        candidateIndicators.add(ComponentScan.class.getName());
        candidateIndicators.add(Import.class.getName());
        candidateIndicators.add(ImportResource.class.getName());
    }

解析 Java 配置类 parser.parse(candidates)

parser.parse(candidates)办法最终调用 processConfigurationClass 办法来解决 @Configuration 配置类,ConfigurationClassParser. processConfigurationClass()办法实现代码如下

    protected void processConfigurationClass(ConfigurationClass configClass) 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);
        do {
      //【真正解析配置类】sourceClass = doProcessConfigurationClass(configClass, sourceClass);
        }
        while (sourceClass != null);
        // 再次增加到到汇合中
        this.configurationClasses.put(configClass, configClass);
    }

doProcessConfigurationClass 办法次要实现从配置类中解析所有 bean,包含解决外部类,父类以及各种注解

ConfigurationClassParser. doProcessConfigurationClass()解析配置类逻辑如下:

@Nullable
    protected final SourceClass doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass)
            throws IOException {if (configClass.getMetadata().isAnnotated(Component.class.getName())) {// Recursively process any member (nested) classes first
      // 递归解决任何成员(嵌套)类
            processMemberClasses(configClass, sourceClass);
        }

        // Process any @PropertySource annotations
    // 解决 @PropertySource 注解
        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");
            }
        }

        // 解决 @ComponentScan 
   // 获取 @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
        // 按 @CmponentScan 注解扫描 bean
                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
        // 遍历扫描出的 bean 定义是否是配置类 bean
                for (BeanDefinitionHolder holder : scannedBeanDefinitions) {BeanDefinition bdCand = holder.getBeanDefinition().getOriginatingBeanDefinition();
                    if (bdCand == null) {bdCand = holder.getBeanDefinition();
                    }
          // 若果扫描出的 bean 定义是配置类(含有 @COnfiguration), 则持续调用 parse 办法,外部再次调用 doProcessConfigurationClas(), 递归解析
                    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));
        }

        // 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;
    }

@ComponentScan

@ComponentScan 注解解析过程

Set<BeanDefinitionHolder> scannedBeanDefinitions =
                        this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName());

@ComponentScan 注解解析,从下面的代码能够看出 @ComponentScan 注解解析通过调用 ComponentScanAnnotationParser 的 parse 办法实现,而 parse()办法外部解决了一些 scanner 属性 (过滤器设置) 和 basePackages 包名解决,最终通过调用 ClassPathBeanDefinitionScanner.doScan 办法实现扫面工作

    protected Set<BeanDefinitionHolder> doScan(String... basePackages) {Assert.notEmpty(basePackages, "At least one base package must be specified");
        Set<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet<>();
        for (String basePackage : basePackages) {
      // 依据 basePackage 加载包下所有 java 文件,并扫描出所有 bean 组件
            Set<BeanDefinition> candidates = findCandidateComponents(basePackage);
      // 遍历 beandefition
            for (BeanDefinition candidate : candidates) {
        // 解析作用域 Scope
                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);
                }
        // 通用注解解析到 candidate 构造中,次要是解决 Lazy, primary, DependsOn, Role ,Description 这五个注解
                if (candidate instanceof AnnotatedBeanDefinition) {AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);
                }
        // 查看以后 bean 是否曾经注册,不存在则注册
                if (checkCandidate(beanName, candidate)) {BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);
                    definitionHolder =
                            AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
                    beanDefinitions.add(definitionHolder);
          // 注册到 ioc 容器中,次要是一些 @Component 组件,@Bean 注解办法并没有在此处注册,beanname 和 beandefinition 键值对
                    registerBeanDefinition(definitionHolder, this.registry);
                }
            }
        }
        return beanDefinitions;
    }

而 bean 定义信息扫描 Set<BeanDefinition> candidates = findCandidateComponents(basePackage); 最终调用的是 ClassPathScanningCandidateComponentProvider.scanCandidateComponents

    private Set<BeanDefinition> scanCandidateComponents(String basePackage) {Set<BeanDefinition> candidates = new LinkedHashSet<>();
        try {// @ComponentScan("com.gyt.study")包门路解决:packageSearchPath = classpath*:com/gyt/study/**/*.class
            String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX +
                    resolveBasePackage(basePackage) + '/' + this.resourcePattern;
      // // 获取以后包下所有的 class 文件
            Resource[] resources = getResourcePatternResolver().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 = getMetadataReaderFactory().getMetadataReader(resource);
            // 依照 scanner 过滤器过滤,比方配置类自身将被过滤掉,没有 @Component 等组件注解的类将过滤掉
               // 蕴含 @Component 注解的组件将创立 BeanDefinition
                        if (isCandidateComponent(metadataReader)) {ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader);
                            sbd.setSource(resource);
                            if (isCandidateComponent(sbd)) {if (debugEnabled) {logger.debug("Identified candidate component class:" + resource);
                                }
                                candidates.add(sbd);
                            }
                            else {if (debugEnabled) {logger.debug("Ignored because not a concrete top-level class:" + resource);
                                }
                            }
                        }
                        else {if (traceEnabled) {logger.trace("Ignored because not matching any filter:" + resource);
                            }
                        }
                    }
                    catch (Throwable ex) {
                        throw new BeanDefinitionStoreException("Failed to read candidate component class:" + resource, ex);
                    }
                }
                else {if (traceEnabled) {logger.trace("Ignored because not readable:" + resource);
                    }
                }
            }
        }
        catch (IOException ex) {throw new BeanDefinitionStoreException("I/O failure during classpath scanning", ex);
        }
        return candidates;
    }

@Bean

Set<MethodMetadata> beanMethods = retrieveBeanMethodMetadata(sourceClass); 办法实现了 @Bean 办法的解析,但并未将实现 bean 实例的创立。

    private Set<MethodMetadata> retrieveBeanMethodMetadata(SourceClass sourceClass) {AnnotationMetadata original = sourceClass.getMetadata();
    // 获取所有 @Bean 注解的办法
        Set<MethodMetadata> beanMethods = original.getAnnotatedMethods(Bean.class.getName());
    // 如果配置类中有多个 @Bean 注解的办法,则排序
        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 办法,当调用完 parse 办法之后,能失去一批 ConfigurationClass 汇合,然而这时候只是获取到,而容器中还没有对应的注册信息,那么接下来就是对这批汇合进行注册解决

ConfigurationClassBeanDefinitionReader.loadBeanDefinitions()办法的性能就是将之前解析出的 configClasses 配置类信息中所有配置相干的信息增加到 spring 的 bean 定义,次要是配置类中的 @Bean 注解办法,配置类 @ImportResource 和 @Import(实现 ImportBeanDefinitionRegistrar 接口方式)的 bean 注册

ConfigurationClassBeanDefinitionReader.loadBeanDefinitions()办法 实现逻辑如下:

    /**
     * Read {@code configurationModel}, registering bean definitions
     * with the registry based on its contents.
     */
    public void loadBeanDefinitions(Set<ConfigurationClass> 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;
        }

    // 与 @Import 注解相干
        if (configClass.isImported()) {registerBeanDefinitionForImportedConfigurationClass(configClass);
        }
    // 将 @Bean 办法注册为 bean
        for (BeanMethod beanMethod : configClass.getBeanMethods()) {loadBeanDefinitionsForBeanMethod(beanMethod);
        }

        loadBeanDefinitionsFromImportedResources(configClass.getImportedResources());
        loadBeanDefinitionsFromRegistrars(configClass.getImportBeanDefinitionRegistrars());
    }

loadBeanDefinitionsForBeanMethod

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

    // 获取 @Bean 注解的元数据信息
    AnnotationAttributes bean = AnnotationConfigUtils.attributesFor(metadata, Bean.class);
    Assert.state(bean != null, "No @Bean annotation attributes");

    // Consider name and any aliases
    // 获取 @Bean 注解是否有 name 属性,如 @Bean(name = "myBean")
    List<String> names = new ArrayList<>(Arrays.asList(bean.getStringArray("name")));
    // 默认 bean 的名称和办法名称雷同, 然而如果设置了 name,就取 name 作为 beanName
    String beanName = (!names.isEmpty() ? names.remove(0) : methodName);

    // 创立一个 BeanMethod 的 BeanDefinition
    ConfigurationClassBeanDefinition beanDef = new ConfigurationClassBeanDefinition(configClass, metadata);
    beanDef.setResource(configClass.getResource());
    beanDef.setSource(this.sourceExtractor.extractSource(metadata, configClass.getResource()));

    // 设置工厂办法
    // 前期 Bean 的实例化,getBean 的时候,会判断 BeanMethod 是否存在 FactoryMethod,如果存在,就应用反射调用工厂办法,返回工厂办法中的对象
    if (metadata.isStatic()) {
        // static @Bean method
        beanDef.setBeanClassName(configClass.getMetadata().getClassName());
        beanDef.setFactoryMethodName(methodName);
    }
    else {
        // instance @Bean method
        beanDef.setFactoryBeanName(configClass.getBeanName());
        beanDef.setUniqueFactoryMethodName(methodName);
    }
    //....
    this.registry.registerBeanDefinition(beanName, beanDefToRegister);
}

Component 注解的派生性原理

https://www.cnblogs.com/liuen…

模式注解

Stereotype Annotation俗称为模式注解。Spring 外围局部提供了几种内建的 模式注解 , 如@Component,@Repository,@Service,@Controller,@Configuration 等。这些注解均 派生于 @Component

因为Java 语言规定,Annotation 不容许继承, 没有类派生子类的个性, 因而Spring 采纳元标注的形式实现注解之间的派生

@Component 派生性

@Component 注解作为 Spring 容器托管的通用模式组件,任何被 @Component 标注的组件均为组件扫描的候选对象。

ClassPathBeanDefinitionScanner#doScan(String... basePackages) 调用时, 它利用 basePackages 参数迭代执行的findCandidateComponents(String basePackage), 每次执行后果都生成候选的 BeanDefinition 汇合, 即 candidates 变量。

源码如上
默认状况下,ClassPathScanningCandidateComponentProvider 结构参数 useDefaultFilters 为 true, 并且显示传递给父类结构参数。该办法给属性includeFilters 削减了 @Component 类型 AnnotationTypeFilter 的 TypeFilter。

registerDefaultFilters

    protected void registerDefaultFilters() {this.includeFilters.add(new AnnotationTypeFilter(Component.class));
        ClassLoader cl = ClassPathScanningCandidateComponentProvider.class.getClassLoader();
        try {
            this.includeFilters.add(new AnnotationTypeFilter(((Class<? extends Annotation>) ClassUtils.forName("javax.annotation.ManagedBean", cl)), false));
            logger.trace("JSR-250'javax.annotation.ManagedBean'found and supported for component scanning");
        }
        catch (ClassNotFoundException ex) {// JSR-250 1.1 API (as included in Java EE 6) not available - simply skip.
        }
        try {
            this.includeFilters.add(new AnnotationTypeFilter(((Class<? extends Annotation>) ClassUtils.forName("javax.inject.Named", cl)), false));
            logger.trace("JSR-330'javax.inject.Named'annotation found and supported for component scanning");
        }
        catch (ClassNotFoundException ex) {// JSR-330 API not available - simply skip.}
    }

ClassPathBeanDefinitionScanner 默认过滤器引入标注 @Component,@Repository,@Service 或者 @Controller 等类。同理, 它也可能标注所有 @Component 的 "派生" 注解。

扩大

利用 ClassPathBeanDefinitionScanner 类配合 includeFiltersexcludeFilters定制化批量注册 Bean 到 Spring 容器中。经常能够通过注解形式来蕴含或者排除候选类。

TypeFilter 罕用实现

  • AnnotationTypeFilter: 注解类型过滤器
  • AssignableTypeFilter: 确定此对象示意的类或者接口是否为给定类或者接口雷同。
  • RegexPatternTypeFilter: 判断给定的类名是否合乎指定正则表达式。

@AliasFor

@AliasFor 用法:* 用到注解 属性上,示意两个属性相互为别名,相互为别名的属性值必须雷同,若设置成不同,则会报错
 * 注解是能够继承的,然而注解是不能继承父注解的属性的, 也就是说, 我在类扫描的时候, 拿到的注解的属性值, 仍然是父注解的属性值, 而不是你定义的注解的属性值
 * 所以此时能够在子注解对应的属性上加上 @AliasFor
 * 

总结

解决逻辑理了一遍后,看一下 ConfigurationClassPostProcessor 处理器解析 @configuration 配置类次要过程:

1. Spring 容器初始化时注册默认后置处理器 ConfigurationClassPostProcessor

2. Spring 容器初始化执行 refresh()办法中调用 ConfigurationClassPostProcessor

3. ConfigurationClassPostProcessor 处理器借助 ConfigurationClassParser 实现配置类解析

4. ConfigurationClassParser 配置内解析过程中实现嵌套的 MemberClass、@PropertySource 注解、@ComponentScan 注解(扫描 package 下的所有 Class 并进行迭代解析,次要是 @Component 组件解析及注册)、@ImportResource、@Bean 等解决

5. 实现 @Bean 注册,@ImportResource 指定 bean 的注册以及 @Import(实现 ImportBeanDefinitionRegistrar 接口方式)的 bean 注册

6. 有 @Bean 注解的办法在解析的时候作为 ConfigurationClass 的一个属性,最初还是会转换成 BeanDefinition 进行解决,而实例化的时候会作为一个工厂办法进行 Bean 的创立

正文完
 0