最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Spring容器刷新prepareRefresh第一步

 更新時(shí)間:2023年03月19日 15:11:00   作者:今年三歲半  
這篇文章主要為大家介紹了Spring容器刷新prepareRefresh第一步示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪

關(guān)鍵源碼

這次的內(nèi)容是上圖中的第1步,容器刷新前的準(zhǔn)備工作?;旧隙际且恍┏跏蓟瘎?dòng)作。

下面是這部分的涉及到的源碼中的關(guān)鍵部分:

public abstract class AbstractApplicationContext extends DefaultResourceLoader
        implements ConfigurableApplicationContext {
    private long startupDate;
    /** Flag that indicates whether this context is currently active. */
    private final AtomicBoolean active = new AtomicBoolean();
    /** Flag that indicates whether this context has been closed already. */
    private final AtomicBoolean closed = new AtomicBoolean();
    /** Environment used by this context. */
    @Nullable
    private ConfigurableEnvironment environment;
    protected void prepareRefresh() {
        // Switch to active.
        this.startupDate = System.currentTimeMillis();
        // 1. 初始化狀態(tài)位
        this.closed.set(false);
        this.active.set(true);
        if (logger.isDebugEnabled()) {
            if (logger.isTraceEnabled()) {
                logger.trace("Refreshing " + this);
            } else {
                logger.debug("Refreshing " + getDisplayName());
            }
        }
        // 2. 留給子類的擴(kuò)展方法
        // Initialize any placeholder property sources in the context environment.
        initPropertySources();
        // 3. 驗(yàn)證必須的配置項(xiàng)是否存在
        // 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.初始化狀態(tài)位

一上來就修改兩個(gè)成員變量,active 改為 true, closed 改為 false

  • 成員變量 activetrue 表示當(dāng)前 context 處于激活狀態(tài)
  • 成員變量 closedtrue 表示當(dāng)前 context 已經(jīng)被關(guān)閉

這里修改了狀態(tài),后續(xù)有兩個(gè)地方使用。

第一個(gè)地方是容器關(guān)閉的時(shí)候(避免重復(fù)關(guān)閉)

public abstract class AbstractApplicationContext extends DefaultResourceLoader
        implements ConfigurableApplicationContext {
    protected void doClose() {
        // 當(dāng)前是激活狀態(tài) && 還沒有被關(guān)閉
        // 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);
        }
    }
}

第二個(gè)地方是和 BeanFactory 交互的時(shí)候作斷言用的

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 交互的方法都需要調(diào)用 assertBeanFactoryActive 方法來檢測(cè)容器的狀態(tài)。AbstractApplicationContext 中有二三十個(gè)地方使用了該方法。

比如最常見的各種重載的 AbstractApplicationContext.getBean(java.lang.String) 方法都會(huì)在將方法調(diào)用委托給 getBeanFactory().getBean(name, args); 之前調(diào)用 assertBeanFactoryActive() 來檢測(cè)容器狀態(tài);畢竟在一個(gè)已經(jīng)關(guān)閉了的容器上 getBean() 是不正常的吧。

2.initPropertySources

這個(gè)方法主要是留給子類用來將 StubPropertySource(占位符) 替換為真實(shí)的 PropertySource。

比如在 servlet 環(huán)境下,會(huì)將 ServletContextPropertySourceServletConfigPropertySource 加入(替換 Stub)到 Environment 中。

public abstract class AbstractRefreshableWebApplicationContext extends AbstractRefreshableConfigApplicationContext
        implements ConfigurableWebApplicationContext, ThemeSource {
    @Override
    protected void initPropertySources() {
        ConfigurableEnvironment env = getEnvironment();
        if (env instanceof ConfigurableWebEnvironment) {
            // 這里實(shí)際上是調(diào)用了 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));
        }
    }
}

當(dāng)然,你可以在這里直接 修改/替換 Environment 中的任何 PropertySource

也就是說,可以在這里做類似于 spring-boot 中提供的 EnvironmentPostProcessor 能做的事情。

如果是 spring-boot 項(xiàng)目的話,還是推薦直接使用 EnvironmentPostProcessor。 而不是像下面這樣再搞一個(gè) ApplicationContext 的實(shí)現(xiàn)類。

public class PrepareRefreshTest {
    /**
     * 重寫 initPropertySources(),給 Environment 中新增兩個(gè)自定義的配置項(xiàng) "osName" 和 "a.b.c.d"
     */
    @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

這里主要是驗(yàn)證 ConfigurablePropertyResolver.setRequiredProperties(String... requiredProperties) 方法中指定的那些 必須出現(xiàn)的配置項(xiàng) 是不是都已經(jīng)在 Environment 中了。

所謂的驗(yàn)證,邏輯也很簡單:所有指定的配置項(xiàng)名稱都遍歷一遍,如果發(fā)現(xiàn) Environment 中獲取不到對(duì)應(yīng)的配置項(xiàng)就直接拋出 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;
        }
    }
}

下面這段代碼是驗(yàn)證 validateRequiredProperties() 方法的(同樣的功能,可以使用 spring-boot 提供的 EnvironmentPostProcessor 來完成)。

public class PrepareRefreshTest {
    /**
     * 驗(yàn)證 getEnvironment().validateRequiredProperties(); 的功能
     * <p>
     * 拋出 MissingRequiredPropertiesException 異常(Environment 中缺少必須出現(xiàn)的配置項(xiàng)"jdbc.url")
     */
    @Test
    void validateRequiredPropertiesTest() {
        Assertions.assertThrows(MissingRequiredPropertiesException.class, () -> {
                    final ApplicationContext applicationContext = new AnnotationConfigApplicationContext(PrepareRefreshTest.class) {
                        @Override
                        protected void initPropertySources() {
                            super.initPropertySources();
                            // 這里指定 Environment 中必須要有一個(gè)名為 "jdbc.url" 的配置項(xiàng)
                            // 如果 Environment 中沒有名為 "jdbc.url" 的配置項(xiàng), 就會(huì)在 validateRequiredProperties() 方法中拋出 MissingRequiredPropertiesException
                            getEnvironment().setRequiredProperties("jdbc.url");
                        }
                    };
                }
        );
    }
}

4.處理早期事件

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

spring 中的事件最終是委托給 ApplicationEventMulticaster(多播器) 發(fā)布的。 但現(xiàn)在是在 prepareRefresh 階段,多播器 實(shí)例還沒有初始化呢。 這時(shí)候要是有事件的話,就只能先將這種 "早期"事件保存下來,等到多播器初始化好之后再回過頭來發(fā)布這種"早期"事件。

處理早期事件 這一步所作的事情就是 初始化 用來 臨時(shí) 保存 "早期" 事件的兩個(gè)集合:

  • earlyApplicationEvents: 早期事件
  • earlyApplicationListeners: 早期事件監(jiān)聽器

等到后續(xù)的 initApplicationEventMulticaster() 之后會(huì)回過頭來遍歷 earlyApplicationEvents 發(fā)布事件。

詳細(xì)內(nèi)容會(huì)在 步驟8-initApplicationEventMulticaster()步驟10-registerListeners() 相關(guān)的文章中介紹。這里只介紹和 prepareRefresh 相關(guān)的內(nèi)容。

public abstract class AbstractApplicationContext extends DefaultResourceLoader
        implements ConfigurableApplicationContext {
    private final Set<ApplicationListener<?>> applicationListeners = new LinkedHashSet<>();
    /** Local listeners registered before refresh. */
    @Nullable
    private Set<ApplicationListener<?>> earlyApplicationListeners;
    /** ApplicationEvents published before the multicaster setup. */
    @Nullable
    private Set<ApplicationEvent> earlyApplicationEvents;
    protected void prepareRefresh() {
        // Switch to active.
        // 1. 初始化狀態(tài)位
        // ...
        // 2. 留給子類的擴(kuò)展方法
        // ...
        // 3. 驗(yàn)證必須的配置項(xiàng)是否存在
        // ...
        // 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第一步的詳細(xì)內(nèi)容,更多關(guān)于Spring容器刷新的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • Java高性能本地緩存框架Caffeine的實(shí)現(xiàn)

    Java高性能本地緩存框架Caffeine的實(shí)現(xiàn)

    本文主要介紹了Java高性能本地緩存框架Caffeine的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-02-02
  • 一文帶你了解Spring中Bean名稱加載機(jī)制

    一文帶你了解Spring中Bean名稱加載機(jī)制

    這篇文章主要給大家介紹了Spring Framework如何從使用注解定義的Bean元數(shù)據(jù)中獲取到Bean的名稱,文中通過代碼示例給大家介紹的非常詳細(xì),具有一定的參考價(jià)值,需要的朋友可以參考下
    2024-01-01
  • 利用Java實(shí)現(xiàn)天氣預(yù)報(bào)播報(bào)功能

    利用Java實(shí)現(xiàn)天氣預(yù)報(bào)播報(bào)功能

    這篇文章主要為大家介紹了如何利用Java語言實(shí)現(xiàn)天氣預(yù)報(bào)播報(bào)功能,文中的示例代碼講解詳細(xì),對(duì)我們學(xué)習(xí)Java有一定的幫助,需要的可以參考一下
    2022-06-06
  • SpringBoot自動(dòng)裝配原理解析

    SpringBoot自動(dòng)裝配原理解析

    Spring Boot自動(dòng)裝配是指在Spring Boot應(yīng)用啟動(dòng)時(shí),根據(jù)類路徑下的jar包依賴、Bean定義、各種配置文件等信息,自動(dòng)配置Spring應(yīng)用上下文的Bean,本文給大家詳細(xì)解析了SpringBoot自動(dòng)裝配原理,需要的朋友可以參考下
    2024-11-11
  • SpringBoot 中實(shí)現(xiàn)跨域的5種方式小結(jié)

    SpringBoot 中實(shí)現(xiàn)跨域的5種方式小結(jié)

    這篇文章主要介紹了SpringBoot 中實(shí)現(xiàn)跨域的5種方式小結(jié),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2021-02-02
  • SpringSecurity oAuth2.0的四種模式(小結(jié))

    SpringSecurity oAuth2.0的四種模式(小結(jié))

    本文主要介紹了SpringSecurity oAuth2.0的四種模式,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-02-02
  • java 中冒泡、二分、快速算法詳解

    java 中冒泡、二分、快速算法詳解

    這篇文章主要介紹了java 中冒泡、二分、快速算法詳解的相關(guān)資料,需要的朋友可以參考下
    2017-06-06
  • 關(guān)于TreeMap自定義排序規(guī)則的兩種方式

    關(guān)于TreeMap自定義排序規(guī)則的兩種方式

    這篇文章主要介紹了關(guān)于TreeMap自定義排序規(guī)則的兩種方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2024-08-08
  • 淺談Spring Boot 異常處理篇

    淺談Spring Boot 異常處理篇

    本篇文章主要介紹了淺談Spring Boot 異常處理篇,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2017-08-08
  • IDEA新建bootstrap.yml文件不顯示葉子圖標(biāo)的問題

    IDEA新建bootstrap.yml文件不顯示葉子圖標(biāo)的問題

    這篇文章主要介紹了IDEA新建bootstrap.yml文件不顯示葉子圖標(biāo)的問題及解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-07-07

最新評(píng)論

浮梁县| 宾川县| 普格县| 民和| 巫溪县| 文登市| 阿巴嘎旗| 彩票| 鹤壁市| 抚州市| 股票| 吉隆县| 密山市| 桑日县| 田林县| 阳泉市| 理塘县| 来凤县| 清新县| 平顶山市| 察雅县| 清原| 崇文区| 平泉县| 万盛区| 大荔县| 子长县| 海南省| 汝城县| 宜阳县| 连山| 岚皋县| 鸡东县| 修水县| 广丰县| 淮北市| 古交市| 保亭| 普兰店市| 辛集市| 沙湾县|