聚焦IOC容器刷新环节obtainFreshBeanFactory初始化BeanFactory专项

部署运行你感兴趣的模型镜像

目录

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

二、创建并初始化BeanFactory-obtainFreshBeanFactory源码分析

(一)refreshBeanFactory

(二)getBeanFactory

三、Spring注解驱动配置方式来定义和管理Bean的obtainFreshBeanFactory

(一)常见注解回顾

@Component:标记一个类为Spring的组件,即一个Bean。

@Autowired:自动注入依赖

@Configuration:标记一个类为配置类,可以定义多个Bean

@Bean:声明一个Bean,由Spring容器管

@ComponentScan:指定要扫描的包,Spring会自动扫描这些包下的组件

(二)注解驱动中的具体实现obtainFreshBeanFactory

AnnotationConfigApplicationContext实现分析

 refreshBeanFactory

 getBeanFactory

四、Spring XML驱动 (XML-Driven) 配置方式来定义和管理Bean的obtainFreshBeanFactory

(一)基本配置和启动

(二)XML驱动 (XML-Driven) 具体实现obtainFreshBeanFactory

ClassPathXmlApplicationContext实现分析

 refreshBeanFactory

l oadBeanDefinitions

 getBeanFactory

五、obtainFreshBeanFactory总结


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

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

分析SpringBoot启动配置原理_spring启动加载顺序及原理-CSDN博客文章浏览阅读1.5w次,点赞14次,收藏36次。分析SpringBoot启动配置原理:给出整体初步分析和对应流程图,并从三方面进行展开分析(SpringApplication构造过程分析+SpringApplication启动过程分析+SpringBoot自动配置分析)_spring启动加载顺序及原理https://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();
            }
        }
    }
}

以上内容请多次翻看并理解(如果忘记了最好在次读一下之前的原文博客进行基本的回顾),我们本次讲聚焦其中的创建并初始化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)来访问BeangetBeanFactory 方法通过同步、状态检查和异常处理,确保了 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的同时注册注解配置类。注册过程通过调用 BeanDefinitionReaderregister 方法来实现。

这个类的存在使得在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 方法总结:

  1. 刷新 BeanFactory:方法首先调用 refreshBeanFactory 方法,该方法负责刷新 BeanFactory。在这个过程中,旧的 BeanFactory 实例将被销毁,新的 BeanFactory 实例将被创建和初始化,确保了每次获取 BeanFactory 时都可以获取到最新的实例,从而保持应用程序的状态和配置的一致性。

  2. 获取 BeanFactory:方法接着调用 getBeanFactory 方法,该方法返回已经刷新的 BeanFactory 实例。如果在刷新 BeanFactory 过程中发生异常,可能会抛出 BeansException,应用程序可以根据需要进行处理。

  3. 返回 BeanFactory:最后,方法将获取到的 BeanFactory 实例返回给调用者,以便它可以在应用程序中使用,BeanFactory 是整个 Spring 应用程序的核心,它负责管理应用程序中的所有 Bean 实例。

总的来说,obtainFreshBeanFactory 方法的作用是确保每次获取 BeanFactory 时都可以获取到最新的、已经刷新的 BeanFactory 实例,从而保证了应用程序的状态和配置的一致性。

您可能感兴趣的与本文相关的镜像

Llama Factory

Llama Factory

模型微调
LLama-Factory

LLaMA Factory 是一个简单易用且高效的大型语言模型(Large Language Model)训练与微调平台。通过 LLaMA Factory,可以在无需编写任何代码的前提下,在本地完成上百种预训练模型的微调

评论 1602
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

张彦峰ZYF

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值