返回顶部
首页 > 资讯 > 精选 >Spring容器刷新prepareRefresh第一步是什么
  • 825
分享到

Spring容器刷新prepareRefresh第一步是什么

2023-07-05 13:07:08 825人浏览 八月长安
摘要

本篇内容介绍了“spring容器刷新prepareRefresh第一步是什么”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!下面是这部分的涉及

本篇内容介绍了“spring容器刷新prepareRefresh第一步是什么”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!

下面是这部分的涉及到的源码中的关键部分:

public abstract class AbstractApplicationContext extends DefaultResourceLoader        implements ConfigurableApplicationContext {    private long startupDate;        private final AtomicBoolean active = new AtomicBoolean();        private final AtomicBoolean closed = new AtomicBoolean();        @Nullable    private ConfigurableEnvironment environment;    protected void prepareRefresh() {        // Switch to active.        this.startupDate = System.currentTimeMillis();        // 1. 初始化状态位        this.closed.set(false);        this.active.set(true);        if (logger.isDebugEnabled()) {            if (logger.isTraceEnabled()) {                logger.trace("Refreshing " + this);            } else {                logger.debug("Refreshing " + getDisplayName());            }        }        // 2. 留给子类的扩展方法        // Initialize any placeholder property sources in the context environment.        initPropertySources();        // 3. 验证必须的配置项是否存在        // Validate that all properties marked as required are resolvable:        // see ConfigurablePropertyResolver#setRequiredProperties        getEnvironment().validateRequiredProperties();        // 4. 处理早期事件        // Store pre-refresh ApplicationListeners...        if (this.earlyApplicationListeners == null) {            this.earlyApplicationListeners = new LinkedHashSet<>(this.applicationListeners);        } else {            // Reset local application listeners to pre-refresh state.            this.applicationListeners.clear();            this.applicationListeners.addAll(this.earlyApplicationListeners);        }        // Allow for the collection of early ApplicationEvents,        // to be published once the multicaster is available...        this.earlyApplicationEvents = new LinkedHashSet<>();    }}

1.初始化状态位

一上来就修改两个成员变量,active 改为 true, closed 改为 false

  • 成员变量 activetrue 表示当前 context 处于激活状态

  • 成员变量 closedtrue 表示当前 context 已经被关闭

这里修改了状态,后续有两个地方使用。

第一个地方是容器关闭的时候(避免重复关闭)

public abstract class AbstractApplicationContext extends DefaultResourceLoader        implements ConfigurableApplicationContext {    protected void doClose() {        // 当前是激活状态 && 还没有被关闭        // Check whether an actual close attempt is necessary...        if (this.active.get() && this.closed.compareAndSet(false, true)) {            // 这里省略 N 行代码            // 这里省略 N 行代码            // Switch to inactive.            this.active.set(false);        }    }}

第二个地方是和 BeanFactory 交互的时候作断言用的

public abstract class AbstractApplicationContext extends DefaultResourceLoader        implements ConfigurableApplicationContext {    protected void assertBeanFactoryActive() {        if (!this.active.get()) {            if (this.closed.get()) {                throw new IllegalStateException(getDisplayName() + " has been closed already");            } else {                throw new IllegalStateException(getDisplayName() + " has not been refreshed yet");            }        }    }}

几乎所有和 BeanFactory 交互的方法都需要调用 assertBeanFactoryActive 方法来检测容器的状态。AbstractApplicationContext 中有二三十个地方使用了该方法。

比如最常见的各种重载的 AbstractApplicationContext.getBean(java.lang.String) 方法都会在将方法调用委托给 getBeanFactory().getBean(name, args); 之前调用 assertBeanFactoryActive() 来检测容器状态;毕竟在一个已经关闭了的容器上 getBean() 是不正常的吧。

2.initPropertySources

这个方法主要是留给子类用来将 StubPropertySource(占位符) 替换为真实的 PropertySource

比如在 servlet 环境下,会将 ServletContextPropertySourceServletConfigPropertySource 加入(替换 Stub)到 Environment 中。

public abstract class AbstractRefreshableWEBApplicationContext extends AbstractRefreshableConfigApplicationContext        implements ConfigurableWebApplicationContext, ThemeSource {    @Override    protected void initPropertySources() {        ConfigurableEnvironment env = getEnvironment();        if (env instanceof ConfigurableWebEnvironment) {            // 这里实际上是调用了 WebApplicationContextUtils#initServletPropertySources            ((ConfigurableWebEnvironment) env).initPropertySources(this.servletContext, this.servletConfig);        }    }}public abstract class WebApplicationContextUtils {    public static void initServletPropertySources(MutablePropertySources sources,                                                  @Nullable ServletContext servletContext, @Nullable ServletConfig servletConfig) {        Assert.notNull(sources, "'propertySources' must not be null");        String name = StandardServletEnvironment.SERVLET_CONTEXT_PROPERTY_SOURCE_NAME;        // servletContextInitParams        if (servletContext != null && sources.get(name) instanceof StubPropertySource) {            sources.replace(name, new ServletContextPropertySource(name, servletContext));        }        name = StandardServletEnvironment.SERVLET_CONFIG_PROPERTY_SOURCE_NAME;        // servletConfigInitParams        if (servletConfig != null && sources.get(name) instanceof StubPropertySource) {            sources.replace(name, new ServletConfigPropertySource(name, servletConfig));        }    }}

当然,你可以在这里直接 修改/替换 Environment 中的任何 PropertySource

也就是说,可以在这里做类似于 spring-boot 中提供的 EnvironmentPostProcessor 能做的事情。

如果是 spring-boot 项目的话,还是推荐直接使用 EnvironmentPostProcessor。 而不是像下面这样再搞一个 ApplicationContext 的实现类。

public class PrepareRefreshTest {        @Test    void initPropertySourcesTest() {        final ApplicationContext applicationContext = new AnnotationConfigApplicationContext(PrepareRefreshTest.class) {            @Override            protected void initPropertySources() {                super.initPropertySources();                final ConfigurableEnvironment environment = getEnvironment();                final Map<String, Object> config = new HashMap<>();                config.put("osName", System.getProperty("os.name", "UNKNOWN"));                config.put("a.b.c.d", "haha");                environment.getPropertySources().addFirst(new MapPropertySource("demo-property-source", config));            }        };        final Environment environment = applicationContext.getEnvironment();        Assertions.assertEquals(System.getProperty("os.name"), environment.getProperty("osName"));        Assertions.assertEquals("haha", environment.getProperty("a.b.c.d"));    }}

3.validateRequiredProperties

这里主要是验证 ConfigurablePropertyResolver.setRequiredProperties(String... requiredProperties) 方法中指定的那些 必须出现的配置项 是不是都已经在 Environment 中了。

所谓的验证,逻辑也很简单:所有指定的配置项名称都遍历一遍,如果发现 Environment 中获取不到对应的配置项就直接抛出 MissingRequiredPropertiesException

public abstract class AbstractPropertyResolver implements ConfigurablePropertyResolver {    @Override    public void validateRequiredProperties() {        MissingRequiredPropertiesException ex = new MissingRequiredPropertiesException();        for (String key : this.requiredProperties) {            if (this.getProperty(key) == null) {                ex.addMissingRequiredProperty(key);            }        }        if (!ex.getMissingRequiredProperties().isEmpty()) {            throw ex;        }    }}

下面这段代码是验证 validateRequiredProperties() 方法的(同样的功能,可以使用 spring-boot 提供的 EnvironmentPostProcessor 来完成)。

public class PrepareRefreshTest {        @Test    void validateRequiredPropertiesTest() {        Assertions.assertThrows(MissingRequiredPropertiesException.class, () -> {                    final ApplicationContext applicationContext = new AnnotationConfigApplicationContext(PrepareRefreshTest.class) {                        @Override                        protected void initPropertySources() {                            super.initPropertySources();                            // 这里指定 Environment 中必须要有一个名为 "jdbc.url" 的配置项                            // 如果 Environment 中没有名为 "jdbc.url" 的配置项, 就会在 validateRequiredProperties() 方法中抛出 MissingRequiredPropertiesException                            getEnvironment().setRequiredProperties("jdbc.url");                        }                    };                }        );    }}

4.处理早期事件

什么叫做早期(early)事件?

spring 中的事件最终是委托给 ApplicationEventMulticaster(多播器) 发布的。 但现在是在 prepareRefresh 阶段,多播器 实例还没有初始化呢。 这时候要是有事件的话,就只能先将这种 "早期"事件保存下来,等到多播器初始化好之后再回过头来发布这种"早期"事件。

处理早期事件 这一步所作的事情就是 初始化 用来 临时 保存 "早期" 事件的两个集合

  • earlyApplicationEvents: 早期事件

  • earlyApplicationListeners: 早期事件监听器

等到后续的 initApplicationEventMulticaster() 之后会回过头来遍历 earlyApplicationEvents 发布事件。

详细内容会在 步骤8-initApplicationEventMulticaster()步骤10-registerListeners() 相关的文章中介绍。这里只介绍和 prepareRefresh 相关的内容。

public abstract class AbstractApplicationContext extends DefaultResourceLoader        implements ConfigurableApplicationContext {    private final Set<ApplicationListener<?>> applicationListeners = new LinkedHashSet<>();        @Nullable    private Set<ApplicationListener<?>> earlyApplicationListeners;        @Nullable    private Set<ApplicationEvent> earlyApplicationEvents;    protected void prepareRefresh() {        // Switch to active.        // 1. 初始化状态位        // ...        // 2. 留给子类的扩展方法        // ...        // 3. 验证必须的配置项是否存在        // ...        // 4. 处理早期事件        // Store pre-refresh ApplicationListeners...        if (this.earlyApplicationListeners == null) {            this.earlyApplicationListeners = new LinkedHashSet<>(this.applicationListeners);        } else {            // Reset local application listeners to pre-refresh state.            this.applicationListeners.clear();            this.applicationListeners.addAll(this.earlyApplicationListeners);        }        // Allow for the collection of early ApplicationEvents,        // to be published once the multicaster is available...        this.earlyApplicationEvents = new LinkedHashSet<>();    }}

“Spring容器刷新prepareRefresh第一步是什么”的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识可以关注编程网网站,小编将为大家输出更多高质量的实用文章!

--结束END--

本文标题: Spring容器刷新prepareRefresh第一步是什么

本文链接: https://lsjlt.com/news/352084.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • Spring容器刷新prepareRefresh第一步是什么
    本篇内容介绍了“Spring容器刷新prepareRefresh第一步是什么”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!下面是这部分的涉及...
    99+
    2023-07-05
  • Spring容器刷新prepareRefresh第一步
    目录关键源码1.初始化状态位2.initPropertySources3.validateRequiredProperties4.处理早期事件关键源码 这次的内容是上图中的第1步...
    99+
    2023-03-19
    Spring容器刷新 Spring prepareRefresh
  • Spring容器刷新obtainFreshBeanFactory的方法是什么
    本篇内容主要讲解“Spring容器刷新obtainFreshBeanFactory的方法是什么”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“Spring容器刷新obtainFreshBeanFa...
    99+
    2023-07-05
  • oracle快照刷新的步骤是什么
    Oracle快照刷新的步骤如下:1. 检查当前的快照刷新状态:使用以下命令查询当前快照刷新是否已启用:```SELECT n...
    99+
    2023-09-25
    oracle
  • Spring容器启动流程是什么
    本篇内容介绍了“Spring容器启动流程是什么”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!源码解析考虑到直接看源码是一个非常枯燥无味的过程...
    99+
    2023-06-15
  • spring容器启动过程是什么
    Spring容器的启动过程如下:1. 加载配置文件:Spring容器需要加载一个或多个配置文件,配置文件可以是XML文件、Java注...
    99+
    2023-09-14
    spring
  • Python容器索引和Linux的未来:什么是下一步?
    Python是一种广泛使用的编程语言,而容器则是一种快速、可靠和可重复部署的解决方案。Python容器索引是一个很有用的工具,它可以让用户轻松地搜索和使用Python容器。而在Linux的未来,容器将扮演着越来越重要的角色。那么,下一步是...
    99+
    2023-11-04
    容器 linux 索引
  • linux文件第一行增加内容的方法是什么
    要在Linux文件的第一行增加内容,可以使用以下方法之一:1. 使用文本编辑器打开文件,并在第一行插入所需的内容。例如,使用vi编辑...
    99+
    2023-09-16
    linux
  • docker容器部署redis步骤是什么
    这篇文章主要介绍“docker容器部署redis步骤是什么”,在日常操作中,相信很多人在docker容器部署redis步骤是什么问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”docker容器部署redis步骤...
    99+
    2023-06-21
  • 阿里云ecs创建以后第一个步骤是什么
    简介 阿里云ECS(Elastic ComputeService)是一种弹性计算服务,可以帮助用户快速搭建和管理云服务器。在创建ECS实例后,第一个步骤非常重要,它将决定后续的操作和配置。详细说明步骤一:登录到阿里云控制台首先,你需要登录到...
    99+
    2024-01-19
    第一个 阿里 步骤
  • Java中Spring容器的存储方式是什么?
    Spring是Java开发中的一个重要框架,它提供了很多功能,其中最重要的就是IOC(Inversion of Control)和AOP(Aspect Oriented Programming)两个核心技术。而Spring容器是实现这两种...
    99+
    2023-11-02
    存储 spring 容器
  • Spring容器初始化register与refresh方法是什么
    这篇文章主要讲解了“Spring容器初始化register与refresh方法是什么”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“Spring容器初始化register与refresh方法是...
    99+
    2023-07-02
  • PHP中的Spring容器是什么?如何使用数组?
    在PHP中,Spring容器是一个非常重要的概念。它可以帮助我们管理和组织PHP应用程序中的组件和对象。本文将介绍PHP中的Spring容器以及如何使用数组。 一、什么是Spring容器? Spring容器是一个可以管理和组织PHP应用程...
    99+
    2023-06-19
    spring 数组 容器
  • 为什么Python shell和Spring容器是完美的组合?
    Python shell和Spring容器是两个非常流行的工具,它们分别用于编写Python代码和Java代码。但是,你可能会想知道它们之间有什么联系,为什么它们是完美的组合呢?在本文中,我们将探讨这个问题,并演示一些代码示例。 首先,让我...
    99+
    2023-10-15
    shell spring 容器
  • MongoDB的初始化步骤有哪些以及其缓存刷新机制是什么
    MongoDB的初始化步骤有哪些以及其缓存刷新机制是什么,针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法。  当内存用尽开始往磁盘上刷脏页的时...
    99+
    2024-04-02
  • Linux 容器技术一览表是什么样的
    Linux 容器技术一览表是什么样的,很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。容器是现在非常火的概念,基本上技术圈里的人都在谈,但其实容器技术的概念可以追溯...
    99+
    2023-06-06
  • 向Spring IOC容器动态注册bean实现方式是什么
    本篇内容主要讲解“向Spring IOC容器动态注册bean实现方式是什么”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“向Spring IOC容器动态注册bean实现方式是什...
    99+
    2023-07-02
  • Spring IOC容器Bean的作用域及生命周期是什么
    本篇内容介绍了“Spring IOC容器Bean的作用域及生命周期是什么”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!bean作用域bean...
    99+
    2023-06-30
  • Spring源码解析容器初始化构造的方法是什么
    这篇“Spring源码解析容器初始化构造的方法是什么”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“Spring源码解析容器初...
    99+
    2023-07-02
  • Spring IOC容器Bean管理XML注入集合类型属性是什么
    这篇“Spring IOC容器Bean管理XML注入集合类型属性是什么”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇...
    99+
    2023-06-30
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作