目录
二、创建并初始化BeanFactory-obtainFreshBeanFactory源码分析
三、Spring注解驱动配置方式来定义和管理Bean的obtainFreshBeanFactory
@Component:标记一个类为Spring的组件,即一个Bean。
@Configuration:标记一个类为配置类,可以定义多个Bean
@ComponentScan:指定要扫描的包,Spring会自动扫描这些包下的组件
(二)注解驱动中的具体实现obtainFreshBeanFactory
AnnotationConfigApplicationContext实现分析
四、Spring XML驱动 (XML-Driven) 配置方式来定义和管理Bean的obtainFreshBeanFactory
(二)XML驱动 (XML-Driven) 具体实现obtainFreshBeanFactory
ClassPathXmlApplicationContext实现分析
干货分享,感谢您的阅读!
在很早之前我们单独写过一篇文章《分析SpringBoot启动配置原理》,具体可见:
一、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();
}
}
}
}
以上内容请多次翻看并理解(如果忘记了最好在次读一下之前的原文博客进行基本的回顾),我们本次讲聚焦其中的创建并初始化BeanFactory - obtainFreshBeanFactory专项。

二、创建并初始化BeanFactory-obtainFreshBeanFactory源码分析
obtainFreshBeanFactory 方法是获取一个新鲜的、经过完全初始化的 BeanFactory 实例的关键步骤。
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
this.refreshBeanFactory();
return this.getBeanFactory();
}
源码很简单,通过调用 refreshBeanFactory 来刷新和初始化 BeanFactory,然后通过 getBeanFactory 返回最新的 BeanFactory 实例,确保依赖注入容器一致性和正确性的一个重要机制。
(一)refreshBeanFactory
refreshBeanFactory 是一个抽象方法,由子类实现,该方法负责刷新和初始化 BeanFactory 实例。
以AbstractRefreshableApplicationContext为基本分析(我们在源码基础上增加对应的注释解释):
@Override
protected final void refreshBeanFactory() throws BeansException {
// 检查当前上下文是否已经存在一个 BeanFactory 实例
if (hasBeanFactory()) {
// 销毁所有在该 BeanFactory 中管理的单例 Bean
// 这一步确保了资源的释放和干净的状态
destroyBeans();
// 关闭当前的 BeanFactory 实例,释放其持有的资源
closeBeanFactory();
}
try {
// 创建一个新的 DefaultListableBeanFactory 实例
DefaultListableBeanFactory beanFactory = createBeanFactory();
// 设置 BeanFactory 的序列化ID
// getId() 返回当前应用上下文的ID,通常是唯一标识符
beanFactory.setSerializationId(getId());
// 定制 BeanFactory 的配置
// 子类可以重写这个方法来修改 BeanFactory 的默认设置
// 例如启用或禁用循环依赖检测、设置自动装配模式等
customizeBeanFactory(beanFactory);
// 从配置源(如 XML 文件、注解等)中加载 Bean 定义
// 并将它们注册到 BeanFactory 中
loadBeanDefinitions(beanFactory);
// 将新创建和初始化的 BeanFactory 实例保存到当前应用上下文中,以便后续使用
this.beanFactory = beanFactory;
} catch (IOException ex) {
// 捕获 IOException 异常并抛出 ApplicationContextException
// 这通常与加载 Bean 定义过程中出现的 I/O 错误相关
// 抛出异常有助于在启动时检测配置问题
throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
}
}
refreshBeanFactory 方法通过以下几个步骤确保每次刷新应用上下文时,都能正确初始化BeanFactory:
- 销毁旧的BeanFactory:确保资源被正确释放,避免内存泄漏和Bean状态不一致。
- 创建新的BeanFactory:每次刷新时都创建一个全新的
DefaultListableBeanFactory实例,以确保干净的状态。 - 定制和加载Bean定义:通过定制BeanFactory和加载Bean定义,将应用上下文中的配置(XML、注解等)转换为可管理的Bean实例。
- 保存BeanFactory:将新创建的BeanFactory实例保存到上下文中,以便后续使用。
整体保证了Spring应用上下文在每次刷新时都能重新加载并初始化所有Bean定义,确保应用能够按照最新的配置运行,同时通过销毁旧的BeanFactory来避免资源浪费和潜在的内存泄漏问题。
(二)getBeanFactory
getBeanFactory 方法返回当前的 BeanFactory 实例,在 refreshBeanFactory 方法执行之后调用,以确保返回的是最新的 BeanFactory 实例。
以AbstractRefreshableApplicationContext为基本分析(我们在源码基础上增加对应的注释解释):
public final ConfigurableListableBeanFactory getBeanFactory() {
// 使用 beanFactoryMonitor 对象进行同步,以确保线程安全
synchronized(this.beanFactoryMonitor) {
// 检查 beanFactory 是否为 null
if (this.beanFactory == null) {
// 如果 beanFactory 为 null,抛出 IllegalStateException
// 提示调用 'refresh' 方法以初始化 BeanFactory
throw new IllegalStateException("BeanFactory not initialized or already closed - call 'refresh' before accessing beans via the ApplicationContext");
} else {
// 如果 beanFactory 已经被初始化,返回当前的 beanFactory 实例
return this.beanFactory;
}
}
}
在实际应用中,getBeanFactory 方法主要用于框架内部,确保 BeanFactory 的状态在应用上下文的生命周期内保持一致。开发者通常不直接调用这个方法,而是通过 ApplicationContext 提供的更高层次的接口(如 getBean)来访问Bean。getBeanFactory 方法通过同步、状态检查和异常处理,确保了 BeanFactory 的安全访问和正确使用,是Spring应用上下文管理中的一个关键方法。
三、Spring注解驱动配置方式来定义和管理Bean的obtainFreshBeanFactory
注解驱动 (Annotation-Driven)配置是通过在Java类中使用注解来声明Bean和它们的依赖关系,这种方式更加简洁和直观,与现代Java开发风格结合。
(一)常见注解回顾
@Component:标记一个类为Spring的组件,即一个Bean。
@Component
public class ZYFService {
// ...
}
@Autowired:自动注入依赖
@Component
public class ZYFService {
@Autowired
private ZYFRepository zyfRepository;
// ...
}
@Configuration:标记一个类为配置类,可以定义多个Bean
@Configuration
public class AppConfig {
@Bean
public ZYFService zyfService() {
return new ZYFService();
}
}
@Bean:声明一个Bean,由Spring容器管
@Configuration
public class AppConfig {
@Bean
public ZYFService zyfService() {
return new ZYFService();
}
}
@ComponentScan:指定要扫描的包,Spring会自动扫描这些包下的组件
@Configuration
@ComponentScan(basePackages = "org.zyf.javabasic")
public class AppConfig {
// ...
}
(二)注解驱动中的具体实现obtainFreshBeanFactory
在注解驱动的配置中,AnnotationConfigApplicationContext 是一个常用的实现,它继承了 GenericApplicationContext,并在其中实现了注解扫描和Bean定义的加载。
AnnotationConfigApplicationContext实现分析
refreshBeanFactory
AnnotationConfigApplicationContext 通过调用父类的 refreshBeanFactory 方法来实现BeanFactory的刷新和初始化。它会扫描指定的包,解析注解,注册Bean定义。
public class AnnotationConfigApplicationContext extends GenericApplicationContext {
// ...
@Override
protected void refreshBeanFactory() throws IllegalStateException, BeansException {
// 调用父类的refreshBeanFactory方法
super.refreshBeanFactory();
// 注册配置类
register(this.annotatedClasses);
}
private void register(Class<?>... annotatedClasses) {
for (Class<?> annotatedClass : annotatedClasses) {
this.reader.register(annotatedClass);
}
}
// ...
}
AnnotationConfigApplicationContext 类主要用于支持基于注解的配置。它通过继承 GenericApplicationContext重写 refreshBeanFactory 方法,在刷新BeanFactory的同时注册注解配置类。注册过程通过调用 BeanDefinitionReader 的 register 方法来实现。
这个类的存在使得在Spring应用中可以方便地使用基于注解的配置方式,而不仅仅局限于XML配置,通过在注解配置类中使用 @Configuration、@ComponentScan 等注解更加灵活和方便地配置应用程序的组件。
getBeanFactory
在 GenericApplicationContext 中实现,它继承自 AbstractApplicationContext,直接返回当前上下文的BeanFactory实例。
public class GenericApplicationContext extends AbstractApplicationContext {
// ...
@Override
public ConfigurableListableBeanFactory getBeanFactory() {
return this.beanFactory;
}
// ...
}
返回当前应用上下文的BeanFactory实例,以便其他部分可以获取并使用这些Bean。
注解驱动的 refreshBeanFactory 方法通过注解扫描器(如 ClassPathBeanDefinitionScanner)来解析注解并注册Bean定义,而 getBeanFactory 方法则确保返回的是最新初始化的BeanFactory实例。
四、Spring XML驱动 (XML-Driven) 配置方式来定义和管理Bean的obtainFreshBeanFactory
XML驱动配置是通过XML文件来定义Bean及其依赖关系,在早期的Spring应用中非常流行。
(一)基本配置和启动
示例配置文件
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="zyfService" class="org.zyf.javabasic.bean.ZYFService">
<property name="zyfRepository" ref="zyfRepository"/>
</bean>
<bean id="zyfRepository" class="org.zyf.javabasic.bean.ZYFRepository"/>
</beans>
启动XML驱动配置:要启用XML驱动配置,通常在应用程序上下文中加载配置文件
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
ZYFService zyfService = context.getBean(ZYFService.class);
(二)XML驱动 (XML-Driven) 具体实现obtainFreshBeanFactory
在XML驱动的配置中,ClassPathXmlApplicationContext 是一个常用的实现,它继承了 AbstractXmlApplicationContext,并在其中实现了从XML文件加载Bean定义的功能。
ClassPathXmlApplicationContext实现分析
refreshBeanFactory
ClassPathXmlApplicationContext 通过调用父类的 refreshBeanFactory 方法来实现BeanFactory的刷新和初始化。它会从指定的XML文件中加载Bean定义。
public class ClassPathXmlApplicationContext extends AbstractXmlApplicationContext {
// ...
private final String[] configLocations;
public ClassPathXmlApplicationContext(String configLocation) throws BeansException {
this(new String[] {configLocation}, true, null);
}
public ClassPathXmlApplicationContext(String[] configLocations) throws BeansException {
this(configLocations, true, null);
}
public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent)
throws BeansException {
super(parent);
this.configLocations = configLocations;
if (refresh) {
refresh();
}
}
@Override
protected String[] getConfigLocations() {
return this.configLocations;
}
}
l oadBeanDefinitions
在 AbstractXmlApplicationContext 中,loadBeanDefinitions 方法从XML文件中加载Bean定义:
@Override
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
// Create a new XmlBeanDefinitionReader for the given BeanFactory.
XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
// Configure the bean definition reader with this context's
// resource loading environment.
beanDefinitionReader.setEnvironment(this.getEnvironment());
beanDefinitionReader.setResourceLoader(this);
beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));
// Load the bean definitions from the given XML file.
loadBeanDefinitions(beanDefinitionReader);
}
protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {
Resource[] configResources = getConfigResources();
if (configResources != null) {
reader.loadBeanDefinitions(configResources);
}
String[] configLocations = getConfigLocations();
if (configLocations != null) {
reader.loadBeanDefinitions(configLocations);
}
}
getBeanFactory
在 GenericApplicationContext 中实现,它继承自 AbstractApplicationContext,直接返回当前上下文的BeanFactory实例。
public class GenericApplicationContext extends AbstractApplicationContext {
// ...
@Override
public ConfigurableListableBeanFactory getBeanFactory() {
return this.beanFactory;
}
// ...
}
返回当前应用上下文的BeanFactory实例,以便其他部分可以获取并使用这些Bean。
在XML驱动的配置中,refreshBeanFactory 方法通过 XmlBeanDefinitionReader 从XML文件中解析Bean定义并注册到BeanFactory中,而 getBeanFactory 方法则确保返回的是最新初始化的BeanFactory实例。
五、obtainFreshBeanFactory总结
obtainFreshBeanFactory 方法总结:
-
刷新 BeanFactory:方法首先调用
refreshBeanFactory方法,该方法负责刷新 BeanFactory。在这个过程中,旧的 BeanFactory 实例将被销毁,新的 BeanFactory 实例将被创建和初始化,确保了每次获取 BeanFactory 时都可以获取到最新的实例,从而保持应用程序的状态和配置的一致性。 -
获取 BeanFactory:方法接着调用
getBeanFactory方法,该方法返回已经刷新的 BeanFactory 实例。如果在刷新 BeanFactory 过程中发生异常,可能会抛出BeansException,应用程序可以根据需要进行处理。 -
返回 BeanFactory:最后,方法将获取到的 BeanFactory 实例返回给调用者,以便它可以在应用程序中使用,BeanFactory 是整个 Spring 应用程序的核心,它负责管理应用程序中的所有 Bean 实例。
总的来说,obtainFreshBeanFactory 方法的作用是确保每次获取 BeanFactory 时都可以获取到最新的、已经刷新的 BeanFactory 实例,从而保证了应用程序的状态和配置的一致性。
748





