91超碰碰碰碰久久久久久综合_超碰av人澡人澡人澡人澡人掠_国产黄大片在线观看画质优化_txt小说免费全本

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Spring Boot外部化配置實戰解析

發布時間:2020-07-16 16:29:55 來源:網絡 閱讀:3016 作者:宜信技術 欄目:軟件技術

一、流程分析

1.1 入口程序

在 SpringApplication#run(String... args) 方法中,外部化配置關鍵流程分為以下四步

public ConfigurableApplicationContext 

run(String... args) {

    ...

    SpringApplicationRunListeners listeners = getRunListeners(args); // 1

    listeners.starting();

    try {

        ApplicationArguments applicationArguments = new DefaultApplicationArguments(

            args);

        ConfigurableEnvironment environment = prepareEnvironment(listeners,

                                                                 applicationArguments); // 2

        configureIgnoreBeanInfo(environment);

        Banner printedBanner = printBanner(environment);

        context = createApplicationContext();

        exceptionReporters = getSpringFactoriesInstances(

            SpringBootExceptionReporter.class,

            new Class[] { ConfigurableApplicationContext.class }, context);

        prepareContext(context, environment, listeners, applicationArguments,

                       printedBanner); // 3

        refreshContext(context); // 4

        afterRefresh(context, applicationArguments);

        stopWatch.stop();

        if (this.logStartupInfo) {

            new StartupInfoLogger(this.mainApplicationClass)

                .logStarted(getApplicationLog(), stopWatch);

        }

        listeners.started(context);

        callRunners(context, applicationArguments);

    }

    ...

}

1.2 關鍵流程思維導圖

Spring Boot外部化配置實戰解析

1.3 關鍵流程詳解

對入口程序中標記的四步,分析如下

1.3.1 SpringApplication#getRunListeners

加載 META-INF/spring.factories

獲取 SpringApplicationRunListener

的實例集合,存放的對象是 EventPublishingRunListener 類型 以及自定義的 SpringApplicationRunListener 實現類型

Spring Boot外部化配置實戰解析

1.3.2 SpringApplication#prepareEnvironment

prepareEnvironment 方法中,主要的三步如下

private ConfigurableEnvironment 

prepareEnvironment(SpringApplicationRunListeners listeners,

    ApplicationArguments applicationArguments) {

    // Create and configure the environment

    ConfigurableEnvironment environment = getOrCreateEnvironment(); // 2.1

    configureEnvironment(environment, applicationArguments.getSourceArgs()); // 2.2

    listeners.environmentPrepared(environment); // 2.3

    ...

    return environment;

}
1) getOrCreateEnvironment 方法

在 WebApplicationType.SERVLET web應用類型下,會創建 StandardServletEnvironment,本文以 StandardServletEnvironment 為例,類的層次結構如下

Spring Boot外部化配置實戰解析

當創建 StandardServletEnvironment,StandardServletEnvironment 父類 AbstractEnvironment 調用 customizePropertySources 方法,會執行 StandardServletEnvironment#customizePropertySources和 StandardEnvironment#customizePropertySources ,源碼如下AbstractEnvironment

public AbstractEnvironment() {

    customizePropertySources(this.propertySources);

    if (logger.isDebugEnabled()) {

        logger.debug("Initialized " + getClass().getSimpleName() + " with PropertySources " + this.propertySources);

    }

}

StandardServletEnvironment#customizePropertySources

/** Servlet context init parameters property source name: {@value} */

public static final 

StringSERVLET_CONTEXT_PROPERTY_SOURCE_NAME = "servletContextInitParams";

/** Servlet config init parameters property source name: {@value} */

public static final String 

SERVLET_CONFIG_PROPERTY_SOURCE_NAME = "servletConfigInitParams";

/** JNDI property source name: {@value} */

public static final String 

JNDI_PROPERTY_SOURCE_NAME = "jndiProperties";

@Override

protected void customizePropertySources(MutablePropertySources propertySources) {

    propertySources.addLast(new StubPropertySource(SERVLET_CONFIG_PROPERTY_SOURCE_NAME));

    propertySources.addLast(new StubPropertySource(SERVLET_CONTEXT_PROPERTY_SOURCE_NAME));

    if (JndiLocatorDelegate.isDefaultJndiEnvironmentAvailable()) {

        propertySources.addLast(new JndiPropertySource(JNDI_PROPERTY_SOURCE_NAME));

    }

    super.customizePropertySources(propertySources);

}

StandardEnvironment#customizePropertySources

/** System environment property source name: {@value} */

public static final String 

SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME = "systemEnvironment";

/** JVM system properties property source name: {@value} */

public static final String 

SYSTEM_PROPERTIES_PROPERTY_SOURCE_NAME = "systemProperties";

@Override

protected void customizePropertySources(MutablePropertySources propertySources) {

    propertySources.addLast(new MapPropertySource(SYSTEM_PROPERTIES_PROPERTY_SOURCE_NAME, getSystemProperties()));

    propertySources.addLast(new SystemEnvironmentPropertySource(SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME,getSystemEnvironment());

}

PropertySources 順序:

  • servletConfigInitParams

  • servletContextInitParams

  • jndiProperties

  • systemProperties

  • systemEnvironment

PropertySources 與 PropertySource 關系為 1 對 N

2) configureEnvironment 方法

調用 configurePropertySources(environment, args), 在方法里面設置 Environment 的 PropertySources , 包含 defaultProperties 和

SimpleCommandLinePropertySource(commandLineArgs),PropertySources 添加 defaultProperties 到最后,添加

SimpleCommandLinePropertySource(commandLineArgs)到最前面

PropertySources 順序:

  • commandLineArgs

  • servletConfigInitParams

  • servletContextInitParams

  • jndiProperties

  • systemProperties

  • systemEnvironment

  • defaultProperties
3) listeners.environmentPrepared 方法

會按優先級順序遍歷執行 SpringApplicationRunListener#environmentPrepared,比如 EventPublishingRunListener 和 自定義的 SpringApplicationRunListener

EventPublishingRunListener 發布

ApplicationEnvironmentPreparedEvent 事件

  • ConfigFileApplicationListener 監聽

ApplicationEvent 事件 、處理 ApplicationEnvironmentPreparedEvent 事件,加載所有 EnvironmentPostProcessor 包括自己,然后按照順序進行方法回調

---ConfigFileApplicationListener#postProcessEnvironment方法回調 ,然后addPropertySources 方法調用

RandomValuePropertySource#addToEnvironment,在 systemEnvironment 后面添加 random,然后添加配置文件的屬性源(詳見源碼ConfigFileApplicationListener.Loader#load()

擴展點

  • 自定義 SpringApplicationRunListener ,重寫 environmentPrepared 方法

  • 自定義 EnvironmentPostProcessor

  • 自定義 ApplicationListener 監聽 ApplicationEnvironmentPreparedEvent 事件

  • ConfigFileApplicationListener,即是 EnvironmentPostProcessor ,又是 ApplicationListener ,類的層次結構如下

Spring Boot外部化配置實戰解析

@Override

public void onApplicationEvent(ApplicationEvent event) {

    // 處理 ApplicationEnvironmentPreparedEvent 事件

    if (event instanceof ApplicationEnvironmentPreparedEvent) {

        onApplicationEnvironmentPreparedEvent(

            (ApplicationEnvironmentPreparedEvent) event);

    }

    // 處理 ApplicationPreparedEvent 事件

    if (event instanceof ApplicationPreparedEvent) {

        onApplicationPreparedEvent(event);

    }

}

private void onApplicationEnvironmentPreparedEvent(

    ApplicationEnvironmentPreparedEvent event) {

    // 加載 META-INF/spring.factories 中配置的 EnvironmentPostProcessor

    List

    // 加載自己 ConfigFileApplicationListener

    postProcessors.add(this);

    // 按照 Ordered 進行優先級排序

    AnnotationAwareOrderComparator.sort(postProcessors);

    // 回調 EnvironmentPostProcessor

    for (EnvironmentPostProcessor postProcessor : postProcessors) {

        postProcessor.postProcessEnvironment(event.getEnvironment(),                                            event.getSpringApplication());

    }

}

List

    return SpringFactoriesLoader.loadFactories(EnvironmentPostProcessor.class,                                               getClass().getClassLoader());

}

@Override

public void 

postProcessEnvironment(ConfigurableEnvironment environment,

                                   SpringApplication application) {

    addPropertySources(environment, application.getResourceLoader());

}

/**

  * Add config file property sources to the specified environment.

  * @param environment the environment to add source to

  * @param resourceLoader the resource loader

  * @see 

#addPostProcessors(ConfigurableApplicationContext)

  */

protected void 

addPropertySources(ConfigurableEnvironment environment,

                                  ResourceLoader resourceLoader) {

RandomValuePropertySource.addToEnvironment(environment);

    // 添加配置文件的屬性源

    new Loader(environment, resourceLoader).load();

}

RandomValuePropertySource

public static void 

addToEnvironment(ConfigurableEnvironment environment) {

    // 在 systemEnvironment 后面添加 random

    environment.getPropertySources().addAfter(

        StandardEnvironment.SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME,

        new RandomValuePropertySource(RANDOM_PROPERTY_SOURCE_NAME));

    logger.trace("RandomValuePropertySource add to Environment");

}

添加配置文件的屬性源:執行

new Loader(environment, resourceLoader).load();,

調用 load(Profile, DocumentFilterFactory, DocumentConsumer)(getSearchLocations()

獲取配置文件位置,可以指定通過 spring.config.additional-location 、spring.config.location 、spring.config.name 參數或者使用默認值 ), 然后調用 addLoadedPropertySources -> addLoadedPropertySource(加載 查找出來的 PropertySource 到 PropertySources,并確保放置到 defaultProperties 的前面 )

默認的查找位置,配置為

"classpath:/,classpath:/config/,file:./,file:./config/",查找順序從后向前

PropertySources 順序:

  • commandLineArgs

  • servletConfigInitParams

  • servletContextInitParams

  • jndiProperties

  • systemProperties

  • systemEnvironment

  • random

  • application.properties ...

  • defaultProperties
1.3.3 SpringApplication#prepareContext

prepareContext 方法中,主要的三步如下

private void 

prepareContext(ConfigurableApplicationContext context,

                            ConfigurableEnvironment environment,

                            SpringApplicationRunListeners listeners,

                            ApplicationArguments applicationArguments,

                            Banner printedBanner) {

    ...

    applyInitializers(context); // 3.1

    listeners.contextPrepared(context); //3.2

    ...

    listeners.contextLoaded(context); // 3.3

}
1)applyInitializers 方法

會遍歷執行所有的 ApplicationContextInitializer#initialize

擴展點

  • 自定義 ApplicationContextInitializer
2)listeners.contextPrepared 方法

會按優先級順序遍歷執行 SpringApplicationRunListener#contextPrepared,比如 EventPublishingRunListener 和 自定義的 SpringApplicationRunListener

擴展點

自定義 SpringApplicationRunListener ,重寫 contextPrepared 方法

3)listeners.contextLoaded 方法

會按優先級順序遍歷執行 SpringApplicationRunListener#contextLoaded,比如 EventPublishingRunListener 和 自定義的 SpringApplicationRunListener

EventPublishingRunListener 發布

ApplicationPreparedEvent 事件

  • ConfigFileApplicationListener 監聽

ApplicationEvent 事件 處理

ApplicationPreparedEvent 事件

擴展點

  • 自定義 SpringApplicationRunListener ,重寫 contextLoaded 方法

  • 自定義 ApplicationListener ,監聽 ApplicationPreparedEvent 事件

ConfigFileApplicationListener

@Override

public void onApplicationEvent(ApplicationEvent event) {

    // 處理 ApplicationEnvironmentPreparedEvent 事件

    if (event instanceof 

ApplicationEnvironmentPreparedEvent) {

        onApplicationEnvironmentPreparedEvent(

            (ApplicationEnvironmentPreparedEvent) event);

    }

    // 處理 ApplicationPreparedEvent 事件

    if (event instanceof ApplicationPreparedEvent) {

        onApplicationPreparedEvent(event);

    }

}

private void onApplicationPreparedEvent(ApplicationEvent event) {

    this.logger.replayTo(ConfigFileApplicationListener.class);

    addPostProcessors(((ApplicationPreparedEvent) event).getApplicationContext());

}

// 添加 PropertySourceOrderingPostProcessor 處理器,配置 PropertySources

protected void addPostProcessors(ConfigurableApplicationContext context) {

    context.addBeanFactoryPostProcessor(

        new PropertySourceOrderingPostProcessor(context));

}

PropertySourceOrderingPostProcessor

// 回調處理(在配置類屬性源解析)

@Override

public void 

postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory)

    throws BeansException {

    reorderSources(this.context.getEnvironment());

}

// 調整 PropertySources 順序,先刪除 defaultProperties, 再把 defaultProperties 添加到最后

private void reorderSources(ConfigurableEnvironment environment) {

    PropertySource

        .remove(DEFAULT_PROPERTIES);

    if (defaultProperties != null) {

        environment.getPropertySources().addLast(defaultProperties);

    }

}

PropertySourceOrderingPostProcessor 是 BeanFactoryPostProcessor

1.3.4 SpringApplication#refreshContext

會進行 @Configuration 配置類屬性源解析,處理 @PropertySource annotations on your @Configuration classes,但順序是在 defaultProperties 之后,下面會把defaultProperties 調整到最后

AbstractApplicationContext#refresh 調用 invokeBeanFactoryPostProcessors(PostProcessorRegistrationDelegate#invokeBeanFactoryPostProcessors), 然后進行 BeanFactoryPostProcessor 的回調處理 ,比如 PropertySourceOrderingPostProcessor 的回調(源碼見上文)

PropertySources 順序:

  • commandLineArgs

  • servletConfigInitParams

  • servletContextInitParams

  • jndiProperties

  • systemProperties

  • systemEnvironment

  • random

  • application.properties ...

  • @PropertySource annotations on your @Configuration classes

  • defaultProperties

(不推薦使用這種方式,推薦使用在 refreshContext 之前準備好,@PropertySource 加載太晚,不會對自動配置產生任何影響)

二、擴展外部化配置屬性源

2.1 基于 EnvironmentPostProcessor 擴展

public class CustomEnvironmentPostProcessor 

implements EnvironmentPostProcessor

2.2 基于 ApplicationEnvironmentPreparedEvent 擴展

public class 

ApplicationEnvironmentPreparedEventListener implements ApplicationListener

2.3 基于 SpringApplicationRunListener 擴展

public class CustomSpringApplicationRunListener implements SpringApplicationRunListener, Ordered

可以重寫方法 environmentPrepared、contextPrepared、contextLoaded 進行擴展

2.4 基于 ApplicationContextInitializer 擴展

public class CustomApplicationContextInitializer implements ApplicationContextInitializer

關于與 Spring Cloud Config Client 整合,對外部化配置加載的擴展(綁定到Config Server,使用遠端的property sources 初始化 Environment),參考源碼PropertySourceBootstrapConfiguration(是對 ApplicationContextInitializer 的擴展)、ConfigServicePropertySourceLocator#locate

獲取遠端的property sources是 RestTemplate 通過向 http://{spring.cloud.config.uri}/{spring.application.name}/{spring.cloud.config.profile}/{spring.cloud.config.label} 發送 GET 請求方式獲取的

2.5 基于 ApplicationPreparedEvent 擴展

public class ApplicationPreparedEventListener 

implements ApplicationListener

2.6 擴展實戰

2.6.1 擴展配置

在 classpath 下添加配置文件 META-INF/spring.factories, 內容如下

# Spring Application Run Listeners

org.springframework.boot.SpringApplicationRunListener=\

springboot.propertysource.extend.listener.CustomSpringApplicationRunListener

# Application Context Initializers

org.springframework.context.ApplicationContextInitializer=\

springboot.propertysource.extend.initializer.CustomApplicationContextInitializer

# Application Listeners

org.springframework.context.ApplicationListener=\

springboot.propertysource.extend.event.listener.ApplicationEnvironmentPreparedEventListener,\

springboot.propertysource.extend.event.listener.ApplicationPreparedEventListener

# Environment Post Processors

org.springframework.boot.env.EnvironmentPostProcessor=\

springboot.propertysource.extend.processor.CustomEnvironmentPostProcessor

以上的擴展可以選取其中一種進行擴展,只是屬性源的加載時機不太一樣

2.6.2 擴展實例代碼

https://github.com/shijw823/springboot-externalized-configuration-extend.git

PropertySources 順序:

  • propertySourceName: [ApplicationPreparedEventListener], propertySourceClassName: [OriginTrackedMapPropertySource]

  • propertySourceName: [CustomSpringApplicationRunListener-contextLoaded], propertySourceClassName: [OriginTrackedMapPropertySource]

  • propertySourceName: [CustomSpringApplicationRunListener-contextPrepared], propertySourceClassName: [OriginTrackedMapPropertySource]

  • propertySourceName: [CustomApplicationContextInitializer], propertySourceClassName: [OriginTrackedMapPropertySource]

  • propertySourceName: [bootstrapProperties], propertySourceClassName: [CompositePropertySource]

  • propertySourceName: [configurationProperties], propertySourceClassName: [ConfigurationPropertySourcesPropertySource]

  • propertySourceName: [CustomSpringApplicationRunListener-environmentPrepared], propertySourceClassName: [OriginTrackedMapPropertySource]

  • propertySourceName: [CustomEnvironmentPostProcessor-dev-application], propertySourceClassName: [OriginTrackedMapPropertySource]

  • propertySourceName: [ApplicationEnvironmentPreparedEventListener], propertySourceClassName: [OriginTrackedMapPropertySource]

  • propertySourceName: [commandLineArgs], propertySourceClassName: [SimpleCommandLinePropertySource]

  • propertySourceName: [servletConfigInitParams], propertySourceClassName: [StubPropertySource]

  • propertySourceName: [servletContextInitParams], propertySourceClassName: [ServletContextPropertySource]

  • propertySourceName: [systemProperties], propertySourceClassName: [MapPropertySource]

  • propertySourceName: [systemEnvironment], propertySourceClassName: [OriginAwareSystemEnvironmentPropertySource]

  • propertySourceName: [random], propertySourceClassName: [RandomValuePropertySource]

  • propertySourceName: [applicationConfig: [classpath:/extend/config/springApplicationRunListener.properties]], propertySourceClassName: [OriginTrackedMapPropertySource]

  • propertySourceName: [applicationConfig: [classpath:/extend/config/applicationListener.properties]], propertySourceClassName: [OriginTrackedMapPropertySource]

  • propertySourceName: [applicationConfig: [classpath:/extend/config/applicationContextInitializer.properties]], propertySourceClassName: [OriginTrackedMapPropertySource]

  • propertySourceName: [applicationConfig: [classpath:/extend/config/environmentPostProcessor.properties]], propertySourceClassName: [OriginTrackedMapPropertySource]

  • propertySourceName: [applicationConfig: [classpath:/extend/config/application.properties]], propertySourceClassName: [OriginTrackedMapPropertySource]

  • propertySourceName: [applicationConfig: [classpath:/extend/config/config.properties]], propertySourceClassName: [OriginTrackedMapPropertySource]

  • propertySourceName: [applicationConfig: [classpath:/application.properties]], propertySourceClassName: [OriginTrackedMapPropertySource]

  • propertySourceName: [springCloudClientHostInfo], propertySourceClassName: [MapPropertySource]

  • propertySourceName: [applicationConfig: [classpath:/bootstrap.properties]], propertySourceClassName: [OriginTrackedMapPropertySource]

  • propertySourceName: [propertySourceConfig], propertySourceClassName: [ResourcePropertySource]

  • propertySourceName: [defaultProperties], propertySourceClassName: [MapPropertySource]

bootstrapProperties 是 獲取遠端(config-server)的 property sources

加載順序也可參考 http://{host}:{port}/actuator/env

PropertySources 單元測試順序:

  • @TestPropertySource#properties

  • @SpringBootTest#properties

  • @TestPropertySource#locations

三、參考資料

https://docs.spring.io/spring-boot/docs/2.0.5.RELEASE/reference/htmlsingle/#boot-features-external-config

作者:石建偉

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

杭锦后旗| 桐庐县| 舟曲县| 栾川县| 桂平市| 湘潭县| 灵璧县| 龙游县| 秦皇岛市| 阿拉善左旗| 中宁县| 丹江口市| 四平市| 黎城县| 安阳市| 弥渡县| 涿州市| 苏州市| 辉县市| 铜山县| 新干县| 商城县| 焦作市| 建阳市| 临海市| 临城县| 阿荣旗| 秀山| 察雅县| 施秉县| 临颍县| 双鸭山市| 平山县| 宁南县| 富阳市| 若尔盖县| 舞阳县| 宣威市| 上林县| 永济市| 新兴县|