Spring Boot external configuration of Sessions

 

First, process analysis

1.1 entry program

In SpringApplication # run (String ... args) method, the external configuration of the key processes divided into the following four steps

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);

    }

    ...

}

 

FIG critical processes mind 1.2

1.3 Detailed critical processes

Four-step procedure for the entry mark, as follows

1.3.1 Spring application # getRunListeners

Load META-INF / spring.factories 

Get SpringApplicationRunListener 

Set of examples, the object is stored in EventPublishingRunListener type of custom implementation types SpringApplicationRunListener

1.3.2 SpringApplication#prepareEnvironment

prepareEnvironment method, the following three steps main

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 方法

In WebApplicationType.SERVLET web application type, will create StandardServletEnvironment, paper StandardServletEnvironment for example, the following class hierarchy

When creating StandardServletEnvironment, StandardServletEnvironment parent AbstractEnvironment call customizePropertySources method performs StandardServletEnvironment # customizePropertySources and StandardEnvironment # customizePropertySources, source code as follows 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 order:

  • servletConfigInitParams

  • servletContextInitParams

  • jndiProperties

  • systemProperties

  • systemEnvironment

PropertySources PropertySource relationship with one pair of N

2) configureEnvironment method

Call configurePropertySources (environment, args), which is provided in a method PropertySources Environment, and comprising defaultProperties

SimpleCommandLinePropertySource (commandLineArgs), PropertySources to add defaultProperties Finally, add 

SimpleCommandLinePropertySource (commandLineArgs) to the front

PropertySources order:

  • commandLineArgs

  • servletConfigInitParams

  • servletContextInitParams

  • jndiProperties

  • systemProperties

  • systemEnvironment

  • defaultProperties

3) listeners.environmentPrepared 方法

It will be traversed in order of priority the implementation of SpringApplicationRunListener # environmentPrepared, such as EventPublishingRunListener and custom SpringApplicationRunListener

EventPublishingRunListener release

ApplicationEnvironmentPreparedEvent 事件

  • ConfigFileApplicationListener monitor 

ApplicationEvent event, ApplicationEnvironmentPreparedEvent event handling, loading all EnvironmentPostProcessor including their own, and then follow the order of the callback method

--- ConfigFileApplicationListener # postProcessEnvironment callback method, then the method call addPropertySources 

RandomValuePropertySource # addToEnvironment, was added after the random systemEnvironment, then add attributes of the source profile (see source ConfigFileApplicationListener.Loader # load ()

Extension point

  • Custom SpringApplicationRunListener, rewrite method environmentPrepared

  • Custom EnvironmentPostProcessor

  • Custom ApplicationListener listening ApplicationEnvironmentPreparedEvent event

  • ConfigFileApplicationListener, that is EnvironmentPostProcessor, is ApplicationListener, class hierarchy as follows

@Override

public void onApplicationEvent(ApplicationEvent event) {

    // 处理 ApplicationEnvironmentPreparedEvent 事件

    if (event instanceof ApplicationEnvironmentPreparedEvent) {

        onApplicationEnvironmentPreparedEvent(

            (ApplicationEnvironmentPreparedEvent) event);

    }

    // 处理 ApplicationPreparedEvent 事件

    if (event instanceof ApplicationPreparedEvent) {

        onApplicationPreparedEvent(event);

    }

}

private voidonApplicationEnvironmentPreparedEvent ( 

    ApplicationEnvironmentPreparedEvent Event ) { 

    // load EnvironmentPostProcessor META-INF / spring.factories configured 

    List 

    // load its ConfigFileApplicationListener 

    postProcessors.add ( the this ); 

    // be prioritized according to the Ordered 

    AnnotationAwareOrderComparator.sort (postProcessors); 

    // callback 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");

}

 

Add a profile properties Source: execution 

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

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

Get the configuration file location can be specified by spring.config.additional-location, spring.config.location, spring.config.name parameters or use the default value), then call addLoadedPropertySources -> addLoadedPropertySource (loaded Find out PropertySource to PropertySources, and placed in the front ensuring defaultProperties)

Find the default location, configure

"Classpath: /, classpath: / config /, file: ./, file: ./ config /", find the order from back to front

PropertySources order:

  • commandLineArgs

  • servletConfigInitParams

  • servletContextInitParams

  • jndiProperties

  • systemProperties

  • systemEnvironment

  • random

  • application.properties ...

  • defaultProperties

1.3.3 SpringApplication#prepareContext

prepareContext method, the following three steps main

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 method

It will traverse perform all ApplicationContextInitializer # initialize

Extension point

  • Custom ApplicationContextInitializer
2)listeners.contextPrepared 方法

It will be traversed in order of priority the implementation of SpringApplicationRunListener # contextPrepared, such as EventPublishingRunListener and custom SpringApplicationRunListener

Extension point

Custom SpringApplicationRunListener, rewrite method contextPrepared

3)listeners.contextLoaded 方法

It will be traversed in order of priority the implementation of SpringApplicationRunListener # contextLoaded, such as EventPublishingRunListener and custom SpringApplicationRunListener

EventPublishingRunListener release

ApplicationPreparedEvent 事件

  • ConfigFileApplicationListener monitor 

ApplicationEvent event processing 

ApplicationPreparedEvent 事件

Extension point

  • Custom SpringApplicationRunListener, rewrite method contextLoaded

  • Custom ApplicationListener, listening ApplicationPreparedEvent event

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

// callback handler (source attribute in the configuration class parsing) 

@Override 

public  void  

postProcessBeanFactory (ConfigurableListableBeanFactory beanFactory) 

    throws BeansException { 

    reorderSources ( the this .context.getEnvironment ()); 

} 

 

// adjust PropertySources order, delete defaultProperties, then add defaultProperties Finally, the 

Private  void reorderSources (ConfigurableEnvironment Environment) { 

    PropertySource 

        .remove (DEFAULT_PROPERTIES); 

    IF (! defaultProperties = null ) { 

        . environment.getPropertySources () addLast (defaultProperties); 

    } 

}

 

PropertySourceOrderingPostProcessor 是 BeanFactoryPostProcessor

1.3.4 SpringApplication#refreshContext

@Configuration configuration will be parsed source class attribute, processing @PropertySource annotations on your @Configuration classes, but the order is after defaultProperties, the following will be adjusted to the final defaultProperties

AbstractApplicationContext # refresh call invokeBeanFactoryPostProcessors (PostProcessorRegistrationDelegate # invokeBeanFactoryPostProcessors), then the callback process BeanFactoryPostProcessor, such PropertySourceOrderingPostProcessor callback (Source see above)

PropertySources order:

  • commandLineArgs

  • servletConfigInitParams

  • servletContextInitParams

  • jndiProperties

  • systemProperties

  • systemEnvironment

  • random

  • application.properties ...

  • @PropertySource annotations on your @Configuration classes 

  • defaultProperties

(Not recommended for use in this way, it is recommended to use ready before refreshContext, @ PropertySource load too late, will not have any impact on the auto-configuration)

Second, to expand the external source of configuration properties

2.1 Based on EnvironmentPostProcessor extension

public class CustomEnvironmentPostProcessor 

implements EnvironmentPostProcessor

 

2.2 Based on ApplicationEnvironmentPreparedEvent extension

public class 

ApplicationEnvironmentPreparedEventListener implements ApplicationListener

 

2.3 Based on SpringApplicationRunListener extension

public class CustomSpringApplicationRunListener implements SpringApplicationRunListener, Ordered

 

The method can override environmentPrepared, contextPrepared, contextLoaded extended

2.4 Based on ApplicationContextInitializer extension

public class CustomApplicationContextInitializer implements ApplicationContextInitializer

 

About integration with Spring Cloud Config Client, the external configuration of the extended load (bound to the Config Server, use the remote property sources initialization Environment), a reference source PropertySourceBootstrapConfiguration (ApplicationContextInitializer is an extension of), ConfigServicePropertySourceLocator # locate

Get property sources is distal to RestTemplate through http: // {spring.cloud.config.uri} / {spring.application.name} / {spring.cloud.config.profile} / {spring.cloud.config.label } acquired transmission request method GET

2.5 Based on ApplicationPreparedEvent extension

public class ApplicationPreparedEventListener 

implements ApplicationListener

 

2.6 Extended combat

2.6.1 Extended configuration

Add a profile META-INF / spring.factories at classpath, as follows

# 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

 

You can select more than one extension extended, but the timing of loading properties of the source are not the same

Examples of spreading codes 2.6.2

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

PropertySources order:

  • 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 is to obtain a distal end (config-server) of the property sources

Loading sequence may also refer to http: // {host}: {port} / actuator / env

PropertySources unit testing sequence:

  • @ # TestPropertySource properties

  • @SpringBootTest#properties

  • @TestPropertySource#locations

Third, reference materials

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

Author: Shi Jianwei

Source: CreditEase Institute of Technology

Guess you like

Origin www.cnblogs.com/yixinjishu/p/10966318.html