Spring源码之prepareBeanFactory()

在Spring框架中,prepareBeanFactory 方法的主要作用是配置和准备 BeanFactory 实例,以确保其能够正确处理和管理应用中的所有Bean。这个方法通常在 AbstractApplicationContext 类及其子类中被调用,主要用于在BeanFactory实例创建之后对其进行必要的设置和配置。

prepareBeanFactory的作用

prepareBeanFactory 方法主要用于:

  1. 设置ClassLoader:为BeanFactory设置类加载器,以确保其能够正确加载类。
  2. 添加特定的BeanPostProcessor:为BeanFactory添加一些默认的Bean后处理器,这些处理器在Bean实例化后进行一些定制操作。
  3. 注册忽略的依赖接口:注册一些依赖忽略的接口,如环境、资源加载器等。
  4. 注册内置Bean:向BeanFactory注册一些特殊的内置Bean,如环境(Environment)、系统属性(System Properties)等。

prepareBeanFactory的源码

以下是 prepareBeanFactory 方法的源码示例及详细注释:

protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
    // 设置BeanFactory的类加载器,通常是应用上下文的类加载器
    beanFactory.setBeanClassLoader(getClassLoader());
    
    // 设置表达式解析器
    beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));
    
    // 设置属性编辑器注册器
    beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));
    
    // 添加一些BeanPostProcessor,用于处理Bean的生命周期回调
    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);

    // 添加一些特定的BeanPostProcessor
    beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this));
    
    // 如果beanFactory包含某些特殊的Bean定义,则进行相关设置
    if (beanFactory.containsBean(ConfigurationConstants.CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)) {
        beanFactory.addBeanPostProcessor((BeanPostProcessor) beanFactory.getBean(ConfigurationConstants.CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME));
    }

    // 设置临时ClassLoader
    if (beanFactory.getTempClassLoader() == null) {
        beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
    }

    // 注册默认的环境变量和系统属性
    if (!beanFactory.containsBean(Environment.SYSTEM_ENVIRONMENT_BEAN_NAME)) {
        beanFactory.registerSingleton(Environment.SYSTEM_ENVIRONMENT_BEAN_NAME, getEnvironment().getSystemEnvironment());
    }
    if (!beanFactory.containsBean(Environment.SYSTEM_PROPERTIES_BEAN_NAME)) {
        beanFactory.registerSingleton(Environment.SYSTEM_PROPERTIES_BEAN_NAME, getEnvironment().getSystemProperties());
    }
}

详细解释

  • 设置类加载器

    beanFactory.setBeanClassLoader(getClassLoader());
    

    这一步将当前应用上下文的类加载器设置为BeanFactory的类加载器,确保BeanFactory能够正确加载类。这意味着BeanFactory将使用应用上下文的类加载器来加载所有Bean定义中的类。这么做的原因是为了保持一致性,确保所有的类都是通过同一个类加载器加载的,避免类加载器问题。

  • 设置表达式解析器

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

    设置一个标准的表达式解析器,用于解析Spring表达式语言(SpEL)。

  • 添加属性编辑器注册器

    beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));
    
    • 为BeanFactory添加一个属性编辑器注册器,以便能够解析特定类型的属性(如资源类型)。
    • 在Spring应用中,很多时候需要将配置文件中的字符串值转换为更复杂的对象类型。属性编辑器就是为了解决这个问题而引入的。prepareBeanFactory 方法通过添加一个属性编辑器注册器,来实现这种类型转换。
      PropertyEditorRegistrar 是Spring中的一个接口,用于注册属性编辑器。实现了这个接口的类可以向BeanFactory注册自定义的属性编辑器。
      
      ResourceEditorRegistrar:
      ResourceEditorRegistrar 是一个实现了 PropertyEditorRegistrar 接口的类,专门用于将Spring的资源类型(如 Resource、URL、File)的字符串表示形式转换为实际的资源对象。它会将这些属性编辑器注册到BeanFactory中。
      
      为什么需要属性编辑器?:
      在Spring配置文件(如XML配置或注解配置)中,很多属性都是以字符串形式存在的。然而,在运行时,这些属性可能需要被转换为其他类型,例如:
      
      将文件路径字符串转换为 java.io.File 对象。
      将URL字符串转换为 java.net.URL 对象。
      将classpath路径字符串转换为Spring的 org.springframework.core.io.Resource 对象。
      通过使用属性编辑器,这些转换可以自动完成,简化了配置的复杂性。
      
  • 添加BeanPostProcessor

    beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
    

    添加一个 ApplicationContextAwareProcessor,这个处理器会在Bean实例化后检查其是否实现了某些回调接口(如 ApplicationContextAware),并相应地注入上下文对象。

    ApplicationContextAwareProcessor 是一个 BeanPostProcessor,用于在Bean实例化后进行检查,看看该Bean是否实现了以下几个接口之一:
    
    ApplicationContextAware
    ResourceLoaderAware
    ApplicationEventPublisherAware
    MessageSourceAware
    如果某个Bean实现了上述的任意一个接口,ApplicationContextAwareProcessor 会在适当的时候调用该接口的方法,并注入对应的Spring上下文对象(如 ApplicationContext、ResourceLoader、ApplicationEventPublisher、MessageSource)。
    
    作用细节
    检测和注入回调接口:在Bean实例化之后,ApplicationContextAwareProcessor 会检查Bean是否实现了 ApplicationContextAware 或其他类似接口。
    如果实现了,它会自动调用这些接口的方法,并将相应的上下文对象注入到Bean中。这里的上下文对象其实就是容器自身的对象。
    
    确保上下文感知:通过这种机制,Bean可以获得对Spring容器的引用,从而能够访问容器中的其他Bean、资源和环境信息。
    这对某些需要访问Spring容器内信息的Bean非常有用。
    
  • 忽略自动装配的接口

    beanFactory.ignoreDependencyInterface(EnvironmentAware.class);
    // ... 其他忽略的接口
    

    忽略一些特定的依赖接口,避免这些接口被自动注入。

    Spring框架能够控制和优化自动装配过程,确保那些不需要或不应该被自动装配的依赖接口不会干扰Bean的正常创建和初始化。这种机制有助于简化配置,减少潜在的冲突,并确保Spring容器能更好地管理和控制特定类型的依赖关系。

  • 注册解析依赖对象

    beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);
    // ... 其他依赖对象
    

    注册一些内置的依赖对象,如 BeanFactoryResourceLoader 等,确保它们可以被自动注入到Bean中。
    用于向容器注册可解析的依赖关系。通过调用这个方法,可以告诉Spring容器某些依赖关系的解析方式,并提供默认的依赖实现。这样,Spring容器在需要解析这些依赖关系时就知道应该如何处理,以及在无法找到特定的依赖实现时应该采取什么措施。

    用于向 BeanFactory 注册可解析的依赖关系。这个方法的主要目的是为了告诉Spring容器某些依赖关系的解析方式,以便在需要时能够提供适当的依赖对象。
      详细解释
      1. 注册可解析的依赖关系
      通过调用 beanFactory.registerResolvableDependency() 方法,可以向Spring容器注册某些依赖关系为可解析的。这些依赖关系通常是一些Spring容器或应用程序的核心组件,它们不需要由容器负责创建,而是由外部提供或由容器提供。
      
      2. 告知Spring容器如何解析依赖
      调用 beanFactory.registerResolvableDependency() 方法告诉Spring容器在需要解析这些依赖关系时应该如何处理。这样,Spring在创建Bean时就知道了这些依赖关系不需要被容器创建,而是应该由外部或容器自身提供。
      
      3. 提供默认的依赖实现
      在某些情况下,可能希望在Spring容器无法找到特定的依赖实现时,提供一个默认的实现。通过注册可解析的依赖关系,可以确保在这种情况下Spring容器不会抛出异常,而是能够继续正常运行。
    
  • 添加特殊的BeanPostProcessor

    beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this));
    

    添加一个 ApplicationListenerDetector,用于检测并处理 ApplicationListener 类型的Bean。

  • 设置临时ClassLoader

    if (beanFactory.getTempClassLoader() == null) {
        beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
    }
    

    如果没有设置临时ClassLoader,则创建并设置一个,用于类型匹配。

  • 注册默认环境变量和系统属性

    if (!beanFactory.containsBean(Environment.SYSTEM_ENVIRONMENT_BEAN_NAME)) {
        beanFactory.registerSingleton(Environment.SYSTEM_ENVIRONMENT_BEAN_NAME, getEnvironment().getSystemEnvironment());
    }
    if (!beanFactory.containsBean(Environment.SYSTEM_PROPERTIES_BEAN_NAME)) {
        beanFactory.registerSingleton(Environment.SYSTEM_PROPERTIES_BEAN_NAME, getEnvironment().getSystemProperties());
    }
    

    向BeanFactory注册系统环境变量和系统属性,使其可以在应用中使用。

总结

prepareBeanFactory 方法在Spring应用上下文初始化过程中起着至关重要的作用。它通过设置类加载器、添加BeanPostProcessor、注册忽略的依赖接口和内置Bean等,确保 BeanFactory 能够正确初始化并管理Spring应用中的所有Bean。这个方法的正确执行是Spring应用上下文能够正常工作的基础。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值