preface

In this section, we mainly learn the property environment configuration interface of Spring Boot.

Description of the Environment

To learn how to configure Spring Boot properties, first we need to learn about the Environment class and take a look at its class annotations.

Interface representing the environment in which the current application is running. Models two key aspects of the application environment: profiles and properties. Methods related to property access are exposed via the {@link PropertyResolver} superinterface.

This interface represents the running environment of the current application. Model two aspects of the application environment: Profiles and Properties. When you need to access properties, you can use the methods provided by PropertyResolver.

A profile is a named, logical group of bean definitions to be registered with the container only if the given profile is active. Beans may be assigned to a profile whether defined in XML or via annotations; See the spring beans – 3.1 schema or the {@ link org. Springframework. Context. The annotation. Profile @ Profile} for the annotation syntax details. The role of the {@code Environment} object with relation to profiles is in determining which profiles (if any) are currently {@linkplain #getActiveProfiles active}, and which profiles (if any) should be {@linkplain #getDefaultProfiles active by default}.

Profiles are named logical groups defined by beans that are registered with the container only if a given profile is active.

The role of the Environment object associated with profiles is to determine which profiles (if any) are currently active and which profiles (if any) should be active by default.

Properties play an important role in almost all applications, and may originate from a variety of sources: properties files, JVM system properties, system environment variables, JNDI, servlet context parameters, ad-hoc Properties objects, Maps, and so on. The role of the environment object with relation to properties is to provide the user with a convenient service interface for configuring property sources and resolving properties from them.

Properties play an important role in almost any application and can come from a variety of sources: property files, JVM system Properties, system environment variables, JNDI, servlet context parameters, temporary property objects, maps, and so on. The attribute-related role of an environment object is to provide a convenient interface for users to configure the attribute source and parse the attribute from it.

We can learn:

  • Environment is an abstract representation of the Environment when Spring Boot is started.

  • The Environment provides a way to get properties by inheriting PropertyResolver

  • Environment has two other important concepts

    • profiles

      It is the suffix of the application-dev and application-test file names (e.g. Dev and test) that we routinely configure.

    • Properties

      Represents a specific property, such as Spring.name =lalala. There are many sources: properties files, JVM system properties, system environment variables, and so on.

      Note: this is not just our custom business properties, but also the current Jvm properties, system properties, and so on.

Externalized Configuration Externalized Configuration

The current version of Spring Boot is Spring Boot 2.1.9.

Docs. Spring. IO/spring – the boot…

There are 17 of them, most of which we don’t use, and only 12 to 15 of them we do.

Into the Environment

And finally, let’s look at the properties in Envitonment by injecting Environment.

First look at the property source list:

It contains the three system initializers that we created earlier, probably because the Spring Boot team thought that users might modify the system configuration properties in the system initializer.

We can also look at the properties we configured:

Principle of Environment loading

Environment loading is done in the SpringApplication’s Run method:

public ConfigurableApplicationContext run(String... args) {... ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments); . }Copy the code

prepareEnvironment(listeners, applicationArguments)

private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments) {
        // Create and configure the environment
        ConfigurableEnvironment environment = getOrCreateEnvironment();
        configureEnvironment(environment, applicationArguments.getSourceArgs());
        ConfigurationPropertySources.attach(environment);
        listeners.environmentPrepared(environment);
        bindToSpringApplication(environment);
        if (!this.isCustomEnvironment) {
            environment = new EnvironmentConverter(getClassLoader()).convertEnvironmentIfNecessary(environment,
                    deduceEnvironmentClass());
        }
        ConfigurationPropertySources.attach(environment);
        return environment;
    }
Copy the code

getOrCreateEnvironment()

private ConfigurableEnvironment getOrCreateEnvironment(a) {
        if (this.environment ! =null) {
            return this.environment;
        }
        switch (this.webApplicationType) {
        case SERVLET:
            return new StandardServletEnvironment();
        case REACTIVE:
            return new StandardReactiveWebEnvironment();
        default:
            return newStandardEnvironment(); }}Copy the code

Here we are generally the SERVLET environment, so will enter new StandardServletEnvironment ().

New StandardServletEnvironment () four attribute source loads:

First of all, the new StandardServletEnvironment (), will first calls the superclass constructor StandardEnvironment (), StandardEnvironment () will call his the superclass constructor:

public AbstractEnvironment(a) {
   customizePropertySources(this.propertySources);
}
Copy the code

Because customizePropertySources () method is a subclass wrote, so will directly call StandardServletEnvironment# customizePropertySources ` :

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);
    }
Copy the code

Here, StandardServletEnvironment # customizePropertySources again to call the super customizePropertySources (propertySources) :

@Override
protected void customizePropertySources(MutablePropertySources propertySources) {
        propertySources.addLast(
                new PropertiesPropertySource(SYSTEM_PROPERTIES_PROPERTY_SOURCE_NAME, getSystemProperties()));
        propertySources.addLast(
                new SystemEnvironmentPropertySource(SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME, getSystemEnvironment()));
    }
Copy the code

So, four attribute sources are added. This thing, it’s pretty convoluted. Maybe this is the big guy.

configureEnvironment(environment, applicationArguments.getSourceArgs())

The template methods are delegated to configurePropertySources(ConfigurableEnvironment, String[]) and configureProfiles(ConfigurableEnvironment, String[]) in this order. String []). Override this method to fully control environment customization, or override one of the above methods for fine-grained control over property sources or configuration files, respectively.

    protected void configureEnvironment(ConfigurableEnvironment environment, String[] args) {
        if (this.addConversionService) {
            ConversionService conversionService = ApplicationConversionService.getSharedInstance();
            environment.setConversionService((ConfigurableConversionService) conversionService);
        }
        configurePropertySources(environment, args);
        configureProfiles(environment, args);
    }
Copy the code

configurePropertySources(environment, args);

Add, remove, or reorder any PropertySource in this application’s environment.

protected void configurePropertySources(ConfigurableEnvironment environment, String[] args) {
    // Get the attribute source
        MutablePropertySources sources = environment.getPropertySources();
    / / set the defaultProperties
        if (this.defaultProperties ! =null&&!this.defaultProperties.isEmpty()) {
            sources.addLast(new MapPropertySource("defaultProperties".this.defaultProperties));
        }
    // this is the command line argument that we carry when we start the jar package
        if (this.addCommandLineProperties && args.length > 0) {
            String name = CommandLinePropertySource.COMMAND_LINE_PROPERTY_SOURCE_NAME;
            if(sources.contains(name)) { PropertySource<? > source = sources.get(name); CompositePropertySource composite =new CompositePropertySource(name);
                composite.addPropertySource(
                        new SimpleCommandLinePropertySource("springApplicationCommandLineArgs", args));
                composite.addPropertySource(source);
                sources.replace(name, composite);
            }
            else {
                sources.addFirst(newSimpleCommandLinePropertySource(args)); }}}Copy the code

configureProfiles(environment, args);

Configure which profiles are active (or active by default) in the profile environment. Additional profiles can be activated through the spring.profiles.active property during profile processing.

    protected void configureProfiles(ConfigurableEnvironment environment, String[] args) {        / / make sure they are initialized / / ensure they are initialized environment. GetActiveProfiles (); // But these ones should go first (last wins in a property key clash) // But these ones should go first (last wins in a property key clash  new LinkedHashSet<>(this.additionalProfiles); profiles.addAll(Arrays.asList(environment.getActiveProfiles())); environment.setActiveProfiles(StringUtils.toStringArray(profiles)); }
Copy the code

The active property specifies the profile. We’ll do a separate chapter later.

Skip it for a moment.

Retrieve attributes

Let’s revamp the system loader.

@Component@Order(10)public class MyOneRunner implements CommandLineRunner {    @Autowired    Environment environment;    @Override    public void run(String... args) throws Exception {        System.out.println("My first boot loader.");        String property = environment.getProperty("spring.application.name");        System.out.println(property);    }}
Copy the code

So convenient for us to debug, all the way down, we’ll come to this method:

protected <T> T getProperty(String key, Class<T> targetValueType, boolean resolveNestedPlaceholders) {        if (this.propertySources ! =null) {            for(PropertySource<? > propertySource :this.propertySources) {                Object value = propertySource.getProperty(key);                if(value ! =null) {                    if (resolveNestedPlaceholders && value instanceof String) {                        value = resolveNestedPlaceholders((String) value);                    }                    logKeyFound(key, propertySource, value);                    returnconvertValueIfNecessary(value, targetValueType); }}}...return null;    }
Copy the code

This method is actually quite simple. It iterates through the source of the property, and if it finds the property, it returns, never iterating again.

This means that the first key-value in the attribute source List takes effect.

Do a simple test:

Spring: Application: name: lalala spring: Application: name: lalalaCopy the code

Here is the list of attribute sources:

So it should be Lololo.

conclusion

This section focuses on understanding Enviroment and common configuration sources.

We will continue to learn more about configuring the active property.