ConfigurationClassBeanDefinitionReader 是如何工作的 ?

来源:互联网 发布:qq飞车改装数据 编辑:程序博客网 时间:2024/06/06 17:04

功能

读取一组已经被完整解析的配置类ConfigurationClass,基于它们所携带的信息向给定bean容器BeanDefinitionRegistry注册其中所有的bean定义。

应用位置

SpringApplication.run()=>refreshContext(ConfigurableApplicationContext context)    => EmbeddedWebApplicationContext.refresh()        => AbstractApplicationContext.refresh()        =>invokeBeanFactoryPostProcessors()            => PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors()                => ConfigurationClassPostProcessor.processConfigBeanDefinitions()                    => ConfigurationClassBeanDefinitionReader.loadBeanDefinitions()

对外提供的服务方法

// 这是该类对外提供的唯一的服务方法入口void loadBeanDefinitions(Set<ConfigurationClass> configurationModel)

源码分析

/** * Reads a given fully-populated set of ConfigurationClass instances, registering bean * definitions with the given BeanDefinitionRegistry based on its contents. *  * 读取一组带有完整解析数据的ConfigurationClass集合,基于他们所携带的信息向给定BeanDefinitionRegistry * 注册其中所有的bean定义。 *  * This class was modeled after the BeanDefinitionReader hierarchy, but does * not implement/extend any of its artifacts as a set of configuration classes is not a * Resource. * * @author Chris Beams * @author Juergen Hoeller * @author Phillip Webb * @author Sam Brannen * @since 3.0 * @see ConfigurationClassParser */class ConfigurationClassBeanDefinitionReader {    private static final Log logger = LogFactory.getLog(ConfigurationClassBeanDefinitionReader.class);    private static final ScopeMetadataResolver scopeMetadataResolver = new AnnotationScopeMetadataResolver();    private final BeanDefinitionRegistry registry;    private final SourceExtractor sourceExtractor;    private final ResourceLoader resourceLoader;    private final Environment environment;    private final BeanNameGenerator importBeanNameGenerator;    private final ImportRegistry importRegistry;    //对@Conditional注解求值的工具类    private final ConditionEvaluator conditionEvaluator;    /**     * Create a new ConfigurationClassBeanDefinitionReader instance that will be used     * to populate the given BeanDefinitionRegistry.     *       * 创建一个新的往指定的BeanDefinitionRegistry填充bean定义的     * ConfigurationClassBeanDefinitionReader 实例     */    ConfigurationClassBeanDefinitionReader(BeanDefinitionRegistry registry, SourceExtractor sourceExtractor,            ResourceLoader resourceLoader, Environment environment, BeanNameGenerator importBeanNameGenerator,            ImportRegistry importRegistry) {        this.registry = registry;        this.sourceExtractor = sourceExtractor;        this.resourceLoader = resourceLoader;        this.environment = environment;        this.importBeanNameGenerator = importBeanNameGenerator;        this.importRegistry = importRegistry;        this.conditionEvaluator = new ConditionEvaluator(registry, environment, resourceLoader);    }    /**     * Read configurationModel, registering bean definitions     * with the registry based on its contents.     * configurationModel 是一组ConfigurationClass,表示一组配置类,该方法从中读取bean定义     * 并注册到bean容器     */    public void loadBeanDefinitions(Set<ConfigurationClass> configurationModel) {        TrackedConditionEvaluator trackedConditionEvaluator = new TrackedConditionEvaluator();        for (ConfigurationClass configClass : configurationModel) {            //遍历处理参数configurationModel中的每个配置类            loadBeanDefinitionsForConfigurationClass(configClass, trackedConditionEvaluator);        }    }    /**     * Read a particular ConfigurationClass, registering bean definitions     * for the class itself and all of its Bean methods.     * 从指定的一个配置类ConfigurationClass中提取bean定义信息并注册bean定义到bean容器 :     * 1. 配置类本身要注册为bean定义     * 2. 配置类中的@Bean注解方法要注册为配置类     */    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);        }        // 从配置类导入的bean定义资源中获取bean定义信息并注册到容器        // 比如导入的xml或者groovy bean定义文件        loadBeanDefinitionsFromImportedResources(configClass.getImportedResources());        // 从配置类导入的ImportBeanDefinitionRegistrar中获取bean定义信息并注册到容器        loadBeanDefinitionsFromRegistrars(configClass.getImportBeanDefinitionRegistrars());    }    /**     * Register the Configuration class itself as a bean definition.     * 配置类本身作为bean定义注册到容器     */    private void registerBeanDefinitionForImportedConfigurationClass(ConfigurationClass configClass) {        AnnotationMetadata metadata = configClass.getMetadata();        AnnotatedGenericBeanDefinition configBeanDef = new AnnotatedGenericBeanDefinition(metadata);        ScopeMetadata scopeMetadata = scopeMetadataResolver.resolveScopeMetadata(configBeanDef);        configBeanDef.setScope(scopeMetadata.getScopeName());        String configBeanName = this.importBeanNameGenerator.generateBeanName(configBeanDef, this.registry);        AnnotationConfigUtils.processCommonDefinitionAnnotations(configBeanDef, metadata);        BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(configBeanDef, configBeanName);        definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);        this.registry.registerBeanDefinition(definitionHolder.getBeanName(), definitionHolder.getBeanDefinition());        configClass.setBeanName(configBeanName);        if (logger.isDebugEnabled()) {            logger.debug("Registered bean definition for imported class '" + configBeanName + "'");        }    }    /**     * Read the given BeanMethod, registering bean definitions     * with the BeanDefinitionRegistry based on its contents.     * @Bean注解的配置类方法作为bean定义注册到bean容器     */    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;        }        // Consider name and any aliases        AnnotationAttributes bean = AnnotationConfigUtils.attributesFor(metadata, Bean.class);        List<String> names = new ArrayList<String>(Arrays.asList(bean.getStringArray("name")));        String beanName = (!names.isEmpty() ? names.remove(0) : methodName);        // Register aliases even when overridden        for (String alias : names) {            this.registry.registerAlias(beanName, alias);        }        // Has this effectively been overridden before (e.g. via XML)?        if (isOverriddenByExistingDefinition(beanMethod, beanName)) {            if (beanName.equals(beanMethod.getConfigurationClass().getBeanName())) {                throw new BeanDefinitionStoreException(beanMethod.getConfigurationClass().getResource().getDescription(),                        beanName, "Bean name derived from @Bean method '" + beanMethod.getMetadata().getMethodName() +                        "' clashes with bean name for containing configuration class; please make those names unique!");            }            return;        }        ConfigurationClassBeanDefinition beanDef = new ConfigurationClassBeanDefinition(configClass, metadata);        beanDef.setResource(configClass.getResource());        beanDef.setSource(this.sourceExtractor.extractSource(metadata, configClass.getResource()));        if (metadata.isStatic()) {            // static @Bean method 静态@Bean方法            beanDef.setBeanClassName(configClass.getMetadata().getClassName());            beanDef.setFactoryMethodName(methodName);        }        else {            // instance @Bean method 实例成员@Bean方法            beanDef.setFactoryBeanName(configClass.getBeanName());            beanDef.setUniqueFactoryMethodName(methodName);        }        beanDef.setAutowireMode(RootBeanDefinition.AUTOWIRE_CONSTRUCTOR);        beanDef.setAttribute(RequiredAnnotationBeanPostProcessor.SKIP_REQUIRED_CHECK_ATTRIBUTE, Boolean.TRUE);        AnnotationConfigUtils.processCommonDefinitionAnnotations(beanDef, metadata);        Autowire autowire = bean.getEnum("autowire");        if (autowire.isAutowire()) {            beanDef.setAutowireMode(autowire.value());        }        String initMethodName = bean.getString("initMethod");        if (StringUtils.hasText(initMethodName)) {            beanDef.setInitMethodName(initMethodName);        }        String destroyMethodName = bean.getString("destroyMethod");        if (destroyMethodName != null) {            beanDef.setDestroyMethodName(destroyMethodName);        }        // Consider scoping        ScopedProxyMode proxyMode = ScopedProxyMode.NO;        AnnotationAttributes attributes = AnnotationConfigUtils.attributesFor(metadata, Scope.class);        if (attributes != null) {            beanDef.setScope(attributes.getString("value"));            proxyMode = attributes.getEnum("proxyMode");            if (proxyMode == ScopedProxyMode.DEFAULT) {                proxyMode = ScopedProxyMode.NO;            }        }        // Replace the original bean definition with the target one, if necessary        BeanDefinition beanDefToRegister = beanDef;        if (proxyMode != ScopedProxyMode.NO) {            BeanDefinitionHolder proxyDef = ScopedProxyCreator.createScopedProxy(                    new BeanDefinitionHolder(beanDef, beanName), this.registry,                    proxyMode == ScopedProxyMode.TARGET_CLASS);            beanDefToRegister = new ConfigurationClassBeanDefinition(                    (RootBeanDefinition) proxyDef.getBeanDefinition(), configClass, metadata);        }        if (logger.isDebugEnabled()) {            logger.debug(String.format("Registering bean definition for @Bean method %s.%s()",                    configClass.getMetadata().getClassName(), beanName));        }        this.registry.registerBeanDefinition(beanName, beanDefToRegister);    }    protected boolean isOverriddenByExistingDefinition(BeanMethod beanMethod, String beanName) {        if (!this.registry.containsBeanDefinition(beanName)) {            return false;        }        BeanDefinition existingBeanDef = this.registry.getBeanDefinition(beanName);        // Is the existing bean definition one that was created from a configuration class?        // -> allow the current bean method to override, since both are at second-pass level.        // However, if the bean method is an overloaded case on the same configuration class,        // preserve the existing bean definition.        if (existingBeanDef instanceof ConfigurationClassBeanDefinition) {            ConfigurationClassBeanDefinition ccbd = (ConfigurationClassBeanDefinition) existingBeanDef;            return ccbd.getMetadata().getClassName().equals(                    beanMethod.getConfigurationClass().getMetadata().getClassName());        }        // A bean definition resulting from a component scan can be silently overridden        // by an @Bean method, as of 4.2...        if (existingBeanDef instanceof ScannedGenericBeanDefinition) {            return false;        }        // Has the existing bean definition bean marked as a framework-generated bean?        // -> allow the current bean method to override it, since it is application-level        if (existingBeanDef.getRole() > BeanDefinition.ROLE_APPLICATION) {            return false;        }        // At this point, it's a top-level override (probably XML), just having been parsed        // before configuration class processing kicks in...        if (this.registry instanceof DefaultListableBeanFactory &&                !((DefaultListableBeanFactory) this.registry).isAllowBeanDefinitionOverriding()) {            throw new BeanDefinitionStoreException(beanMethod.getConfigurationClass().getResource().getDescription(),                    beanName, "@Bean definition illegally overridden by existing bean definition: " + existingBeanDef);        }        if (logger.isInfoEnabled()) {            logger.info(String.format("Skipping bean definition for %s: a definition for bean '%s' " +                    "already exists. This top-level bean definition is considered as an override.",                    beanMethod, beanName));        }        return true;    }    private void loadBeanDefinitionsFromImportedResources(            Map<String, Class<? extends BeanDefinitionReader>> importedResources) {        Map<Class<?>, BeanDefinitionReader> readerInstanceCache = new HashMap<Class<?>, BeanDefinitionReader>();        for (Map.Entry<String, Class<? extends BeanDefinitionReader>> entry : importedResources.entrySet()) {            String resource = entry.getKey();            Class<? extends BeanDefinitionReader> readerClass = entry.getValue();            // Default reader selection necessary?            if (BeanDefinitionReader.class == readerClass) {                if (StringUtils.endsWithIgnoreCase(resource, ".groovy")) {                    // When clearly asking for Groovy, that's what they'll get...                    // 如果是groovy bean定义文件采用如下读取类                    readerClass = GroovyBeanDefinitionReader.class;                }                else {                    // Primarily ".xml" files but for any other extension as well                    // 如果是xml bean定义文件采用如下读取类                    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            // 从导入的文件中读取bean定义并注册到bean容器            reader.loadBeanDefinitions(resource);        }    }    // 对参数中所有ImportBeanDefinitionRegistrar实例,逐一调用其方法registerBeanDefinitions()    private void loadBeanDefinitionsFromRegistrars(Map<ImportBeanDefinitionRegistrar, AnnotationMetadata> registrars) {        for (Map.Entry<ImportBeanDefinitionRegistrar, AnnotationMetadata> entry : registrars.entrySet()) {            entry.getKey().registerBeanDefinitions(entry.getValue(), this.registry);        }    }    /**     * RootBeanDefinition marker subclass used to signify that a bean definition     * was created from a configuration class as opposed to any other configuration source.     * Used in bean overriding cases where it's necessary to determine whether the bean     * definition was created externally.     */    @SuppressWarnings("serial")    private static class ConfigurationClassBeanDefinition extends RootBeanDefinition implements AnnotatedBeanDefinition {        private final AnnotationMetadata annotationMetadata;        private final MethodMetadata factoryMethodMetadata;        public ConfigurationClassBeanDefinition(ConfigurationClass configClass, MethodMetadata beanMethodMetadata) {            this.annotationMetadata = configClass.getMetadata();            this.factoryMethodMetadata = beanMethodMetadata;            setLenientConstructorResolution(false);        }        public ConfigurationClassBeanDefinition(                RootBeanDefinition original, ConfigurationClass configClass, MethodMetadata beanMethodMetadata) {            super(original);            this.annotationMetadata = configClass.getMetadata();            this.factoryMethodMetadata = beanMethodMetadata;        }        private ConfigurationClassBeanDefinition(ConfigurationClassBeanDefinition original) {            super(original);            this.annotationMetadata = original.annotationMetadata;            this.factoryMethodMetadata = original.factoryMethodMetadata;        }        @Override        public AnnotationMetadata getMetadata() {            return this.annotationMetadata;        }        @Override        public MethodMetadata getFactoryMethodMetadata() {            return this.factoryMethodMetadata;        }        @Override        public boolean isFactoryMethod(Method candidate) {            return (super.isFactoryMethod(candidate) && BeanAnnotationHelper.isBeanAnnotated(candidate));        }        @Override        public ConfigurationClassBeanDefinition cloneBeanDefinition() {            return new ConfigurationClassBeanDefinition(this);        }    }    /**     * 用于跟踪某个配置类是否需要被忽略     * Evaluate @Conditional annotations, tracking results and taking into     * account 'imported by'.     */    private class TrackedConditionEvaluator {        private final Map<ConfigurationClass, Boolean> skipped = new HashMap<ConfigurationClass, Boolean>();        public boolean shouldSkip(ConfigurationClass configClass) {            Boolean skip = this.skipped.get(configClass);            if (skip == null) {                if (configClass.isImported()) {                    boolean allSkipped = true;                    for (ConfigurationClass importedBy : configClass.getImportedBy()) {                        if (!shouldSkip(importedBy)) {                            allSkipped = false;                            break;                        }                    }                    if (allSkipped) {                        // The config classes that imported this one were all skipped, therefore we are skipped...                        skip = true;                    }                }                if (skip == null) {                    skip = conditionEvaluator.shouldSkip(configClass.getMetadata(), ConfigurationPhase.REGISTER_BEAN);                }                this.skipped.put(configClass, skip);            }            return skip;        }    }}