在Spring框架中,prepareBeanFactory
方法的主要作用是配置和准备 BeanFactory
实例,以确保其能够正确处理和管理应用中的所有Bean。这个方法通常在 AbstractApplicationContext
类及其子类中被调用,主要用于在BeanFactory实例创建之后对其进行必要的设置和配置。
prepareBeanFactory的作用
prepareBeanFactory
方法主要用于:
- 设置ClassLoader:为BeanFactory设置类加载器,以确保其能够正确加载类。
- 添加特定的BeanPostProcessor:为BeanFactory添加一些默认的Bean后处理器,这些处理器在Bean实例化后进行一些定制操作。
- 注册忽略的依赖接口:注册一些依赖忽略的接口,如环境、资源加载器等。
- 注册内置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); // ... 其他依赖对象
注册一些内置的依赖对象,如
BeanFactory
、ResourceLoader
等,确保它们可以被自动注入到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应用上下文能够正常工作的基础。