首页 > 其他分享 >聚焦IOC容器刷新环节prepareBeanFactory专项

聚焦IOC容器刷新环节prepareBeanFactory专项

时间:2024-07-24 09:30:07浏览次数:12  
标签:容器 beanFactory Spring BeanFactory 接口 Bean 注册 IOC prepareBeanFactory

目录

一、IOC容器的刷新环节快速回顾

二、prepareBeanFactory源码展示分析

三、设置基本属性深入分析

(一)设置类加载器

(二)设置表达式解析器

(三)设置属性编辑器

(四)设计目的分析

四、忽略自动装配深入分析

(一)详细分析和说明

EnvironmentAware

EmbeddedValueResolverAware

ResourceLoaderAware

ApplicationEventPublisherAware

MessageSourceAware

ApplicationContextAware

(二)设计目的分析

五、注册可解析的依赖深入分析

(一)详细分析和说明

注册 BeanFactory

注册 ResourceLoader

注册 ApplicationEventPublisher

注册 ApplicationContext

(二)设计目的分析

六、添加后置处理器深入分析

(一)添加 ApplicationContextAwareProcessor

(二)添加 ApplicationListenerDetector

(三)处理 LoadTimeWeaver

(四)设计目的分析

七、注册默认的环境变量 Bean深入分析

(一)注册环境变量 Bean

(二)注册系统属性 Bean

(三)注册系统环境变量 Bean

(四)设计目的分析

八、总结


干货分享,感谢您的阅读!

在很早之前我们单独写过一篇文章《分析SpringBoot启动配置原理》,具体可见:

解析SpringBoot启动配置原理icon-default.png?t=N7T8https://blog.csdn.net/xiaofeng10330111/article/details/130903779?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522171829487016800213028572%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fblog.%2522%257D&request_id=171829487016800213028572&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~blog~first_rank_ecpm_v1~rank_v31_ecpm-1-130903779-null-null.nonecase&utm_term=%E5%88%86%E6%9E%90SpringBoot%E5%90%AF%E5%8A%A8%E9%85%8D%E7%BD%AE%E5%8E%9F%E7%90%86&spm=1018.2226.3001.4450其中IOC容器的刷新环节可当重点分析,值得在读源码时进行深入分析,我们会从多个方向上再次进行分析回顾和学习。

一、IOC容器的刷新环节快速回顾

我们将AbstractApplicationContext的refresh方法源码提取并进行重点代码标注说明如下:

public abstract class AbstractApplicationContext implements ApplicationContext {

    @Override
    public void refresh() throws BeansException, IllegalStateException {
        synchronized (this.startupShutdownMonitor) {
            // 准备上下文环境,包括初始化工厂、后置处理器等
            prepareRefresh();

            // 创建并初始化 BeanFactory
            ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

            // 设置 BeanFactory 的类加载器、资源加载器等
            prepareBeanFactory(beanFactory);

            try {
                // 允许子类对 BeanFactory 进行进一步的自定义处理
                postProcessBeanFactory(beanFactory);

                // 调用 BeanFactoryPostProcessors 进行后置处理
                invokeBeanFactoryPostProcessors(beanFactory);

                // 注册 BeanPostProcessors,用于对 Bean 实例进行后置处理
                registerBeanPostProcessors(beanFactory);

                // 初始化消息源
                initMessageSource();

                // 初始化事件广播器
                initApplicationEventMulticaster();

                // 初始化其他特殊 Bean
                onRefresh();

                // 注册关闭钩子
                registerListeners();

                // 初始化所有剩余的单例 Bean
                finishBeanFactoryInitialization(beanFactory);

                // 完成上下文刷新
                finishRefresh();
            } catch (BeansException ex) {
                if (logger.isWarnEnabled()) {
                    logger.warn("Exception encountered during context initialization - " +
                            "cancelling refresh attempt: " + ex);
                }
                // 销毁已创建的 Bean,关闭容器
                destroyBeans();
                // 重置容器刷新标志,允许再次刷新
                cancelRefresh(ex);
                // 把异常重新抛出,允许调用者处理
                throw ex;
            } finally {
                // 重置已注册的 JVM 关闭钩子
                resetCommonCaches();
            }
        }
    }
}

以上内容请多次翻看并理解(如果忘记了最好在次读一下之前的原文博客进行基本的回顾),我们本次讲聚焦其中的prepareBeanFactory专项展开分析。

二、prepareBeanFactory源码展示分析

prepareBeanFactory 方法是 Spring 容器启动过程中的一个重要环节。它对 BeanFactory 进行一系列的配置和初始化工作,包括设置类加载器、表达式解析器、属性编辑器、注册特定的依赖、添加后置处理器等。通过这些配置,BeanFactory 可以更好地管理和创建 Bean,提供更强大的依赖注入和事件处理能力。

我们针对其主要的源码展示说明如下:

protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
    // 设置 BeanFactory 的类加载器为当前上下文的类加载器
    beanFactory.setBeanClassLoader(getClassLoader());

    // 设置 BeanFactory 的表达式解析器
    beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));

    // 设置 BeanFactory 的属性编辑器注册
    beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));

    // 添加 BeanPostProcessor(ApplicationContextAwareProcessor),用于处理特定的回调接口
    beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));

    // 设置忽略自动装配的接口
    beanFactory.ignoreDependencyInterface(EnvironmentAware.class);
    beanFactory.ignoreDependencyInterface(EmbeddedValueResolverAware.class);
    beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);
    beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);
    beanFactory.ignoreDependencyInterface(MessageSourceAware.class);
    beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);

    // 设置依赖解析,将特定接口的依赖解析到指定的实例
    beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);
    beanFactory.registerResolvableDependency(ResourceLoader.class, this);
    beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);
    beanFactory.registerResolvableDependency(ApplicationContext.class, this);

    // 注册早期的 PostProcessor 检查 BeanFactory 以便尽早进行特殊处理
    beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this));

    // 检查 LoadTimeWeaver 并设置到 BeanFactory 中(用于 AspectJ 织入)
    if (beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
        beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
        beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
    }

    // 注册默认的环境变量 Bean(如果没有被注册)
    if (!beanFactory.containsLocalBean(ENVIRONMENT_BEAN_NAME)) {
        beanFactory.registerSingleton(ENVIRONMENT_BEAN_NAME, getEnvironment());
    }
    if (!beanFactory.containsLocalBean(SYSTEM_PROPERTIES_BEAN_NAME)) {
        beanFactory.registerSingleton(SYSTEM_PROPERTIES_BEAN_NAME, getEnvironment().getSystemProperties());
    }
    if (!beanFactory.containsLocalBean(SYSTEM_ENVIRONMENT_BEAN_NAME)) {
        beanFactory.registerSingleton(SYSTEM_ENVIRONMENT_BEAN_NAME, getEnvironment().getSystemEnvironment());
    }
}

通过 prepareBeanFactory 方法的源码,可以看出其设计的合理性和分工明确。

观察该方法可以看到其主要涉及的几部分:

设置基本属性

  • 设置类加载器:beanFactory.setBeanClassLoader(getClassLoader());
  • 设置表达式解析器:beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));
  • 设置属性编辑器:beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));

忽略特定依赖接口

  • 忽略自动装配的接口,如 EnvironmentAwareResourceLoaderAware 等:beanFactory.ignoreDependencyInterface(...)

注册可解析的依赖

  • 将特定接口与实例关联,以便在自动装配时使用这些实例:beanFactory.registerResolvableDependency(...)

添加后置处理器

  • 添加 ApplicationContextAwareProcessorbeanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
  • 添加 ApplicationListenerDetectorbeanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this));
  • 处理 LoadTimeWeaverbeanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));

注册默认的环境变量 Bean

  • 注册环境变量、系统属性和系统环境变量:beanFactory.registerSingleton(...)

三、设置基本属性深入分析

(一)设置类加载器

beanFactory.setBeanClassLoader(getClassLoader());

直接功能为 BeanFactory 设置类加载器,确保在创建和加载 Bean 类时使用正确的类加载器。这对应用程序在不同的环境中运行时(例如在不同的容器中或使用不同的类加载策略时)尤为重要。

getClassLoader() 方法通常返回当前上下文(ApplicationContext)的类加载器。通过 setBeanClassLoader 方法,将这个类加载器设置给 BeanFactory,使得 BeanFactory 在加载类时能使用正确的类加载器。

(二)设置表达式解析器

beanFactory.setBeanExpressionResolver(
new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));

直接功能为BeanFactory 设置一个标准的表达式解析器,允许在 Spring 配置文件中使用表达式语言(例如 SpEL,Spring Expression Language)来进行动态值的解析和注入。

StandardBeanExpressionResolver 是 Spring 提供的一个默认实现,用于解析 #{} 表达式。通过 setBeanExpressionResolver 方法,将 StandardBeanExpressionResolver 实例设置给 BeanFactory,使其能够解析和处理配置中的表达式。

StandardBeanExpressionResolver 需要一个类加载器来加载和解析表达式中的类,这里使用的是 BeanFactory 的类加载器。

(三)设置属性编辑器

beanFactory.addPropertyEditorRegistrar(
new ResourceEditorRegistrar(this, getEnvironment()));

直接功能为BeanFactory 注册一个属性编辑器注册器(PropertyEditorRegistrar),确保在 Spring 容器中处理属性值转换时,能够使用正确的属性编辑器。这对于处理复杂类型的属性(例如,将字符串转换为资源类型)非常重要。

ResourceEditorRegistrar 是一个 PropertyEditorRegistrar 的实现,用于注册与资源相关的属性编辑器。ResourceEditorRegistrar 需要两个参数:ResourceLoaderEnvironment(这部分回顾可见重看Spring聚焦Environment分析-CSDN博客

  • this 代表当前的 ApplicationContext,它实现了 ResourceLoader 接口。
  • getEnvironment() 返回当前上下文的环境(Environment),用于获取系统属性和环境变量。

通过 addPropertyEditorRegistrar 方法,将 ResourceEditorRegistrar 实例添加到 BeanFactory 中,从而注册相应的属性编辑器。

(四)设计目的分析

prepareBeanFactory 方法中,设置基本属性部分的代码为 BeanFactory 的初始化奠定了基础。通过设置类加载器、表达式解析器和属性编辑器,确保 BeanFactory 能够正确地加载类、解析配置中的表达式以及处理属性值的转换。这些设置对于 BeanFactory 在创建和管理 Bean 实例时的正常运作至关重要。

类加载器设置保障 BeanFactory 在不同环境下的一致性和兼容性,使得 BeanFactory 能够在多模块或插件化的应用中正确加载类。

表达式解析器设置提供了在配置文件中使用动态表达式的能力,增强了配置的灵活性和动态性。例如,可以使用 #{systemProperties['user.dir']} 动态获取系统属性。

属性编辑器设置通过注册自定义的属性编辑器,确保在属性注入时能够进行复杂类型的转换。例如,可以将字符串路径转换为 Resource 类型,方便资源的加载和管理。

通过以上分析可以看出,prepareBeanFactory 中设置基本属性的部分为 BeanFactory 的后续操作提供了坚实的基础,确保其能够在各种复杂场景下正常工作。

四、忽略自动装配深入分析

beanFactory.ignoreDependencyInterface(EnvironmentAware.class); 
beanFactory.ignoreDependencyInterface(EmbeddedValueResolverAware.class); 
beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class); 
beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class); 
beanFactory.ignoreDependencyInterface(MessageSourceAware.class); 
beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);

(一)详细分析和说明

指定某些接口在自动装配过程中被忽略,防止这些接口被意外地自动装配到 Bean 中,这些接口通常由 Spring 框架内部使用,通过 Aware 接口注入 Spring 容器中的特定资源。

ignoreDependencyInterface 方法告诉 BeanFactory 在自动装配过程中忽略这些特定的接口。这些接口通常用于标识需要特定资源(如 EnvironmentResourceLoader 等)的 Bean,这些资源会在 Bean 初始化的过程中由 Spring 自动注入。忽略这些接口是为了确保它们不会通过常规的自动装配过程注入,而是通过 Spring 的特殊处理机制进行注入。

EnvironmentAware

beanFactory.ignoreDependencyInterface(EnvironmentAware.class);

实现 EnvironmentAware 接口的 Bean 可以通过 setEnvironment(Environment environment) 方法获取 Environment 对象。忽略原因Environment 对象由 Spring 容器管理,通过 prepareBeanFactory 方法中的其他机制进行注入,而不是通过常规的自动装配机制。

EmbeddedValueResolverAware

beanFactory.ignoreDependencyInterface(EmbeddedValueResolverAware.class);

实现 EmbeddedValueResolverAware 接口的 Bean 可以通过 setEmbeddedValueResolver(StringValueResolver resolver) 方法获取 StringValueResolver 对象,用于解析嵌入的字符串值(如 ${} 占位符)。忽略原因StringValueResolver 通常在 Spring 配置解析时使用,需要由 Spring 自动注入而不是通过自动装配。

ResourceLoaderAware

beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);

实现 ResourceLoaderAware 接口的 Bean 可以通过 setResourceLoader(ResourceLoader resourceLoader) 方法获取 ResourceLoader 对象,用于加载外部资源。忽略原因ResourceLoader 通常由 Spring 容器提供,用于统一资源加载机制,应由 Spring 自动注入。

ApplicationEventPublisherAware

beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);

实现ApplicationEventPublisherAware接口的 Bean 可以通过 setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) 方法获取ApplicationEventPublisher对象,用于发布应用事件。忽略原因ApplicationEventPublisher 是 Spring 事件发布机制的一部分,需要由 Spring 容器自动注入。

MessageSourceAware

beanFactory.ignoreDependencyInterface(MessageSourceAware.class); 

实现 MessageSourceAware接口的 Bean 可以通过 setMessageSource(MessageSource messageSource)方法获取MessageSource对象,用于国际化消息的解析。忽略原因MessageSource 由 Spring 管理,用于处理国际化消息,应由 Spring 自动注入。

ApplicationContextAware

beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);

实现 ApplicationContextAware 接口的 Bean 可以通过 setApplicationContext(ApplicationContext applicationContext) 方法获取 ApplicationContext 对象,进而访问 Spring 容器本身。忽略原因ApplicationContext 是 Spring 容器的核心接口,需要由 Spring 容器自动注入,而不是通过常规的自动装配机制。

(二)设计目的分析

prepareBeanFactory 方法中,忽略特定依赖接口的代码部分主要是为了确保这些特殊的 Aware 接口由 Spring 容器内部机制注入,而不是通过常规的自动装配机制注入。这些接口通常用于获取 Spring 容器中的特定资源(如 EnvironmentResourceLoaderApplicationContext 等),这些资源的注入需要由 Spring 框架来管理,以确保正确的依赖关系和资源管理。

通过忽略这些接口,可以防止它们在自动装配过程中被误注入,从而确保 Spring 容器的正确初始化和运行。

五、注册可解析的依赖深入分析

beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory); 
beanFactory.registerResolvableDependency(ResourceLoader.class, this); 
beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this); 
beanFactory.registerResolvableDependency(ApplicationContext.class, this);

(一)详细分析和说明

将特定接口与相应的实例关联,以便在自动装配时能够使用这些预定义的实例,确保在 Spring 容器中,这些核心接口可以在自动装配过程中被正确解析并注入相应的实例。这些接口通常是 Spring 框架自身需要管理和使用的。

registerResolvableDependency 方法允许将一个接口与一个特定的实例关联起来,当自动装配需要该接口的实现时,Spring 会自动使用预先注册的实例。

通过这种方式,可以确保这些关键的 Spring 内部接口在需要时能够被正确注入,而不需要额外的配置。

注册 BeanFactory

beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);

BeanFactory.class 接口与当前的 beanFactory 实例关联,确保在需要自动装配 BeanFactory 接口时,能够注入当前的 beanFactory 实例。这对于在 Bean 中需要访问或操作 BeanFactory 的场景非常有用。通过 registerResolvableDependency 方法,Spring 容器会将 BeanFactory 接口解析为当前的 beanFactory 实例。

注册 ResourceLoader

beanFactory.registerResolvableDependency(ResourceLoader.class, this);

ResourceLoader.class 接口与当前的 ApplicationContext 实例(this)关联,确保在需要自动装配 ResourceLoader 接口时,能够注入当前的 ApplicationContext 实例。ApplicationContext 本身实现了 ResourceLoader 接口,提供统一的资源加载机制。通过 registerResolvableDependency 方法,Spring 容器会将 ResourceLoader 接口解析为当前的 ApplicationContext 实例。

注册 ApplicationEventPublisher

beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);

ApplicationEventPublisher.class 接口与当前的 ApplicationContext 实例(this)关联,确保在需要自动装配 ApplicationEventPublisher 接口时,能够注入当前的 ApplicationContext 实例。ApplicationContext 本身实现了 ApplicationEventPublisher 接口,提供事件发布功能。通过 registerResolvableDependency 方法,Spring 容器会将 ApplicationEventPublisher 接口解析为当前的 ApplicationContext 实例。

注册 ApplicationContext

beanFactory.registerResolvableDependency(ApplicationContext.class, this);

ApplicationContext.class 接口与当前的 ApplicationContext 实例(this)关联,确保在需要自动装配 ApplicationContext 接口时,能够注入当前的 ApplicationContext 实例。这样可以使 Bean 直接访问 Spring 容器的功能。通过 registerResolvableDependency 方法,Spring 容器会将 ApplicationContext 接口解析为当前的 ApplicationContext 实例。

(二)设计目的分析

prepareBeanFactory 方法中,注册可解析的依赖部分的代码通过 registerResolvableDependency 方法,将一些关键的 Spring 内部接口与相应的实例关联起来。

  • 确保自动装配的准确性通过注册这些可解析的依赖,可以确保在自动装配过程中,这些核心接口能够被正确解析并注入预定义的实例,避免了手动配置的麻烦。
  • 提供核心接口的便捷访问这些接口(如 BeanFactoryResourceLoaderApplicationEventPublisherApplicationContext)通常在复杂应用中被频繁使用,通过这种方式可以简化开发过程,提供便捷的访问。
  • 增强 Spring 容器的灵活性这种设计使得 Spring 容器更加灵活和健壮,可以更好地管理和注入这些关键的依赖,提供更高的可维护性和可靠性。

prepareBeanFactory 方法中注册可解析的依赖部分,通过将关键的 Spring 内部接口与特定实例关联,确保这些接口在自动装配过程中能够被正确解析和注入。这不仅简化了配置,还增强了 Spring 容器的灵活性和可靠性。通过这种方式,开发者可以更方便地使用这些核心接口,提升开发效率和代码质量。

六、添加后置处理器深入分析

(一)添加 ApplicationContextAwareProcessor

beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));

BeanFactory 添加一个 ApplicationContextAwareProcessor 后置处理器,确保实现 ApplicationContextAware 接口的 Bean 能够获得 ApplicationContext 实例。

ApplicationContextAwareProcessor 实现了 BeanPostProcessor 接口,它会在 Bean 初始化的过程中处理实现 ApplicationContextAwareEnvironmentAwareResourceLoaderAwareApplicationEventPublisherAware 等接口的 Bean。

具体来说,ApplicationContextAwareProcessor 会在 Bean 初始化时调用相应的 setApplicationContextsetEnvironmentsetResourceLoadersetApplicationEventPublisher 方法,将当前的 ApplicationContextEnvironmentResourceLoaderApplicationEventPublisher 注入到 Bean 中。

(二)添加 ApplicationListenerDetector

beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this));

BeanFactory 添加一个 ApplicationListenerDetector 后置处理器,检测实现 ApplicationListener 接口的 Bean,并将其注册到 ApplicationEventMulticaster 中,以便监听应用事件。

ApplicationListenerDetector 实现了 BeanPostProcessor 接口,它会在 Bean 初始化之后检测 Bean 是否实现了 ApplicationListener 接口。

如果检测到某个 Bean 实现了 ApplicationListener 接口,ApplicationListenerDetector 会将该 Bean 注册到 ApplicationEventMulticaster 中,使其能够监听并处理应用事件。

(三)处理 LoadTimeWeaver

beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));

BeanFactory 添加一个 LoadTimeWeaverAwareProcessor 后置处理器,确保实现 LoadTimeWeaverAware 接口的 Bean 能够获得 LoadTimeWeaver 实例。

LoadTimeWeaverAwareProcessor 实现了 BeanPostProcessor 接口,它会在 Bean 初始化的过程中处理实现 LoadTimeWeaverAware 接口的 Bean。

具体来说,LoadTimeWeaverAwareProcessor 会在 Bean 初始化时调用 setLoadTimeWeaver 方法,将 LoadTimeWeaver 实例注入到 Bean 中。LoadTimeWeaver 用于在运行时动态地加载和织入类,这对于一些需要在运行时增强类的功能(例如 AOP)非常重要。

(四)设计目的分析

prepareBeanFactory 方法中,添加后置处理器部分的代码通过 addBeanPostProcessor 方法为 BeanFactory 添加了三个重要的后置处理器:ApplicationContextAwareProcessorApplicationListenerDetectorLoadTimeWeaverAwareProcessor

  • 确保关键接口的注入ApplicationContextAwareProcessor 确保了实现 Aware 接口的 Bean 能够获得 Spring 容器中的关键组件(如 ApplicationContextEnvironment 等)。LoadTimeWeaverAwareProcessor 确保了实现 LoadTimeWeaverAware 接口的 Bean 能够获得 LoadTimeWeaver 实例,用于运行时类加载和织入。
  • 增强事件处理能力ApplicationListenerDetector 确保了实现 ApplicationListener 接口的 Bean 能够注册到 ApplicationEventMulticaster 中,从而能够监听和处理应用事件。这对于事件驱动的应用程序设计非常重要。
  • 提高 Spring 容器的灵活性和可维护性:通过添加这些后置处理器,Spring 容器能够更好地管理和处理特殊类型的 Bean,提供更高的灵活性和可维护性。

prepareBeanFactory 方法中添加后置处理器部分,通过为 BeanFactory 添加 ApplicationContextAwareProcessorApplicationListenerDetectorLoadTimeWeaverAwareProcessor 三个后置处理器,确保了 Spring 容器能够正确处理实现特定接口的 Bean。这些后置处理器的添加,使得 Spring 容器能够灵活地管理 Bean 的依赖注入和事件处理。

七、注册默认的环境变量 Bean深入分析

beanFactory.registerSingleton("environment", getEnvironment()); 
beanFactory.registerSingleton("systemProperties", getEnvironment().getSystemProperties()); 
beanFactory.registerSingleton("systemEnvironment", getEnvironment().getSystemEnvironment());

BeanFactory 注册几个默认的单例 Bean,用于环境变量、系统属性和系统环境变量的访问。使这些关键的环境信息可以作为 Spring 容器中的 Bean 被其他组件注入和使用,方便应用程序对环境信息的获取和管理。

registerSingleton 方法用于将一个特定的实例注册为单例 Bean。注册的 Bean 可以通过依赖注入的方式在其他 Bean 中使用,提供对环境信息的便捷访问。

(一)注册环境变量 Bean

beanFactory.registerSingleton("environment", getEnvironment());

Environment 实例注册为名为 "environment" 的单例 Bean,提供对 Spring 环境对象的访问,允许其他 Bean 通过注入 Environment Bean 来获取和使用环境信息。

getEnvironment() 方法返回当前的 Environment 实例,Environment 接口提供了访问环境属性和配置文件的方法,是 Spring 环境抽象的重要组成部分。

通过 registerSingleton("environment", getEnvironment()),将 Environment 实例注册到 BeanFactory 中,名称为 "environment"。

(二)注册系统属性 Bean

beanFactory.registerSingleton("systemProperties", getEnvironment().getSystemProperties());

将系统属性映射 (Map<String, Object>) 注册为名为 "systemProperties" 的单例 Bean,提供对系统属性的访问,允许其他 Bean 通过注入 systemProperties Bean 来获取和使用系统属性。

getEnvironment().getSystemProperties() 方法返回一个包含系统属性的映射。通过 registerSingleton("systemProperties", getEnvironment().getSystemProperties()),将系统属性映射注册到 BeanFactory 中,名称为 "systemProperties"。

(三)注册系统环境变量 Bean

beanFactory.registerSingleton("systemEnvironment", getEnvironment().getSystemEnvironment());

将系统环境变量映射 (Map<String, Object>) 注册为名为 "systemEnvironment" 的单例 Bean,提供对系统环境变量的访问,允许其他 Bean 通过注入 systemEnvironment Bean 来获取和使用系统环境变量。

getEnvironment().getSystemEnvironment() 方法返回一个包含系统环境变量的映射。通过 registerSingleton("systemEnvironment", getEnvironment().getSystemEnvironment()),将系统环境变量映射注册到 BeanFactory 中,名称为 "systemEnvironment"。

(四)设计目的分析

prepareBeanFactory 方法中,注册默认的环境变量 Bean 部分的代码通过 registerSingleton 方法为 BeanFactory 注册了三个重要的单例 Bean:environmentsystemPropertiessystemEnvironment

  • 确保环境信息的便捷访问:通过注册 Environment、系统属性和系统环境变量为单例 Bean,Spring 容器中的其他 Bean 可以通过依赖注入轻松访问这些环境信息,提供了极大的便利性。
  • 统一环境信息的管理:将这些环境信息注册为单例 Bean,提供了一个统一的管理方式,使得应用程序中的所有组件可以共享同一个 Environment 实例和相同的系统属性、系统环境变量。
  • 提高配置和调试的灵活性:通过注入这些环境信息,我们可以在应用程序运行时动态访问和修改环境配置,有助于提高调试和配置的灵活性。

prepareBeanFactory 方法中注册默认的环境变量 Bean 部分,通过为 BeanFactory 注册 environmentsystemPropertiessystemEnvironment 三个单例 Bean,确保了 Spring 容器中的其他组件可以方便地访问和使用这些关键的环境信息。

八、总结

通过 prepareBeanFactory 方法,Spring 框架为 BeanFactory 配置了一系列关键属性和处理器,使其具备了处理复杂 Bean 依赖和初始化过程的能力。这一步骤为应用上下文的后续处理奠定了坚实的基础,确保 Spring 容器能够高效、灵活地管理 Bean 的生命周期和依赖注入。通过这种设计,Spring 框架不仅增强了 BeanFactory 的功能,还提高了应用程序的可维护性和可扩展性,体现了其强大的设计思想和实现技巧。

从源码级别,具体的实现上我们可以总结出如下表格:

处理部分描述作用
设置基本属性设置 BeanFactory 的类加载器、表达式解析器和属性编辑器。确保 BeanFactory 能正确地加载类、解析表达式和处理属性。
忽略特定依赖接口忽略自动装配的某些依赖接口,如 EnvironmentAwareResourceLoaderAware 等。避免这些依赖接口被自动装配,从而在特定条件下避免不必要的依赖注入。
注册可解析的依赖将一些关键接口与具体实例关联,以便在自动装配时使用这些实例。确保这些核心接口可以在自动装配过程中被正确解析并注入相应的实例。
添加后置处理器BeanFactory 添加后置处理器,如 ApplicationContextAwareProcessorApplicationListenerDetectorLoadTimeWeaverAwareProcessor确保在 Bean 初始化过程中处理特定类型的 Bean,如实现 ApplicationContextAwareApplicationListenerLoadTimeWeaverAware 接口的 Bean。
注册默认的环境变量 BeanBeanFactory 注册默认的单例 Bean,如环境变量、系统属性和系统环境变量。

使这些关键的环境信息可以作为 Spring 容器中的 Bean 被其他组件注入和使用。

标签:容器,beanFactory,Spring,BeanFactory,接口,Bean,注册,IOC,prepareBeanFactory
From: https://blog.csdn.net/xiaofeng10330111/article/details/140596544

相关文章

  • 面试题-Java 容器
    List和Set的区别是什么?Vector,ArrayList,LinkedList区别?ArrayList和LinkedList底层是怎么实现的?各自的特点是什么?HashSet和HashMap和的区别?TreeMap和TreeSet区别和实现原理HashMap,Hashtable的区别?HashMap,LinkedHashMap,TreeMap的区别?HashMap,和ConncurrentHashMap......
  • IOC&DI注解
    IOC1.声明bean的注解@Component声明bean的基础注解,不属于以下三类时使用此注解@Controller标注在控制器@Service标注在业务类上@Repository标注在数据访问类上,用的比较少组件扫描:@SpringBootApplication具有包扫描的作用,默认扫描当前包及其子包DI1.依赖注入的注......
  • CSS 容器查询 CSS Container Queries
    CSS容器查询的主要思想是将一个元素注册为“容器”,并在容器元素满足某些条件时将样式应用于其他元素。 容器查询通常被认为是响应式网页设计的一种现代方法,其中传统媒体查询长期以来一直是黄金标准-原因是我们可以创建由响应容器宽度而不是视口宽度的元素组成的布局。.par......
  • Java面试八股之详细阐述Spring的DI和IOC
    详细阐述Spring的DI和IOCSpring框架的两大核心特性之一就是控制反转(InversionofControl,IoC),另一个密切相关的是依赖注入(DependencyInjection,DI)。这两个概念是Spring实现松耦合、可测试和可管理软件组件的关键机制。控制反转(InversionofControl,IoC)概念:IoC是一种设......
  • .Net常见的IOC框架及AOP框架
    IOC框架Unity:微软patterns&practicest团队开发的IOC依赖注入框架,支持AOP横切关注点。MEF(ManagedExtensibilityFramework):是一个用来扩展.NET应用程序的框架,可开发插件系统。Spring.NET:依赖注入、面向方面编程(AOP)、数据访问抽象,、以及ASP.NET集成。Autofac:最流行的依赖注......
  • docker 容器调试技巧
    有时候docker容器可能因为映射不对,或者内部文件错误等等,会出现一启动就挂掉的情况,这种往往就是容器启动入口的程序有问题,但是因为一启动就挂,有时候日志啥的都看不到。这时候就可以通过command指令去覆盖掉默认Dockerfile里面的CMD定义的入口(EntryPoint定义的也类似)。覆......
  • 在K8S中,如果不能在容器内部使用netstat查看端口号的情况下,还有其他方式吗?
    在Kubernetes(K8S)中,如果Service访问出现问题,通常可以按照以下步骤进行详细的排查:1.检查Service的状态和配置操作:使用kubectldescribeservice<service-name>命令查看Service的详细描述,确保Service的类型(如ClusterIP,NodePort,LoadBalancer等)和端口映射(如port,targetPort,......
  • Docker 笔记 - Docker 容器重启策略 --restart 介绍和实战
    https://zhuanlan.zhihu.com/p/494370957 1.Docker容器的重启策略目的为了保证容器运行时健壮性(自愈),Docker提供了容器重启策略,即使用参数--restart,它可以让容器在退出时自动尝试重启。场景Docker容器的重启策略一般用于生产环境,开发环境和实验环境可以忽略。例如使......
  • 20、Python之容器:红楼主角都有谁?10行代码生成《红楼梦》词云图
    引言Python系列前面的文章中,我们介绍了Python中容器的基本使用,上一篇中,我们又重点介绍了Counter计数器的使用。这些介绍,应该足以应付日常的工作需求了。在今天的文章中,我想以词云图的生成这个综合案例,巩固一下前面关于容器、字典推导式、Counter的使用。同时,介绍两个比较好......
  • 一文带你了解——Spring IoC
    目录一、IoC介绍二、Bean存储2.1 @Controller(控制器存储)2.1.1获取bean对象的其他方式2.1.2Bean的命名约定2.2 @Service(服务存储)2.3 @Repository(仓库存储)2.4 @Component(组件存储)2.5 @Configuration(配置存储)2.6方法注解@Bean2.6.1方法注解的使用2......