SpringBoot Profile uses detailed configuration and source code parsing

In the course of practice, we often encounter situations in different environments require different profiles, each for a change if re-edit the configuration file or repackage once would be more trouble, Spring Boot aims to provide a Profile Configuration to resolve this issue.

Profile role

Profile the corresponding Chinese and no suitable translation, its main role is to make Spring Boot configuration can provide different support functions depending on the environment.

We often encounter this scenario: there is development, testing, production environment, different environments have different configurations. If every environment when deploying need to modify the configuration file will be very troublesome, and you can easily solve the problem by changing Profile.

The basic use of Profile

For example, the above environment, we can create four files in the Spring Boot:

  • applcation.properties: a common configuration
  • application-dev.properties: development environment configuration
  • application-test.properties: Test Environment Configuration
  • application-prod.properties: production environment configuration

Applcation.properties arranged in a common configuration, and then activate the configuration specified by environment configuration:

spring.profiles.active = prod

Where "prod" control file name application-prod.properties. Spring Boot will get when dealing with the configuration file applcation.properties, then spliced ​​by specifying the value of the profile of the "prod", get the name and path of the file application-prod.properties.

Illustration, such as port development environment using the service for 8080, but in a production environment need to use port 18080. Then, in application-prod.properties configured as follows:

server.port=8080

The configuration in application-prod.properties as:

server.port=18080

When using different environments, can be specified (as in the example above), you may be specified by a start command by using a configuration attribute value applcation.properties spring.profiles.active in:

java -jar springboot.jar --spring.profiles.active=prod

Only after the procedure so packed line parameters you can use a different configuration file from the command environment.

Yml based on file type

If the profile is based on yml file type, you can also configure all in the same configuration file:

spring:
  profiles: 
    active: prod

server: 
  port: 18080
  
---
spring: 
  profiles: dev  
  
server: 
  port: 8080  
  
---
spring: 
  profiles: test  
  
server: 
  port: 8081    

In the above configuration, "---" is divided, which is the default position of the first profile, such as the above-described configuration is started, using the default port 18080. Specify the above command to start if you want to use the specified port can also be used.

Source resolve

Here with us a brief look at the Spring Boot against the basic process flow of Profile (not overly refined specific operation). The method of performing its run during start Spring Boot, the following piece of code is executed:

public ConfigurableApplicationContext run(String... args) {
    // ...
    try {
        ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
        ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
        // ...
    } 
    // ...
}

Wherein the relevant code prepareEnvironment method is as follows:

private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners,
        ApplicationArguments applicationArguments) {
    // ...
    listeners.environmentPrepared(environment);
    // ...
}

In the course of processing services prepareEnvironment method will call SpringApplicationRunListeners environmentPrepared method of publishing events. This method will traverse the registered implementation class in spring.factories in SpringApplicationRunListener, then call its environmentPrepared method.

Which spring.factories in SpringApplicationRunListener implementation class Registered as:

# Run Listeners
org.springframework.boot.SpringApplicationRunListener=\
org.springframework.boot.context.event.EventPublishingRunListener

Calling code SpringApplicationRunListeners method as follows:

void environmentPrepared(ConfigurableEnvironment environment) {
    for (SpringApplicationRunListener listener : this.listeners) {
        listener.environmentPrepared(environment);
    }
}

Which is a collection of registered listeners classes, where the default is only EventPublishingRunListener. It environmentPrepared method is implemented as:

@Override
public void environmentPrepared(ConfigurableEnvironment environment) {
    this.initialMulticaster
            .multicastEvent(new ApplicationEnvironmentPreparedEvent(this.application, this.args, environment));
}

In fact, it released a listening event. The event will be registered in the same spring.factories in ConfigFileApplicationListener listening to:

# Application Listeners
org.springframework.context.ApplicationListener=\
// ...
org.springframework.boot.context.config.ConfigFileApplicationListener
// ...

Core processing with respect to the configuration file will be completed in ConfigFileApplicationListener in. In this class, we can see a lot of familiar constants:

public class ConfigFileApplicationListener implements EnvironmentPostProcessor, SmartApplicationListener, Ordered {

    private static final String DEFAULT_PROPERTIES = "defaultProperties";

    // Note the order is from least to most specific (last one wins)
    private static final String DEFAULT_SEARCH_LOCATIONS = "classpath:/,classpath:/config/,file:./,file:./config/";

    private static final String DEFAULT_NAMES = "application";
    // ...
}

For example, Spring Boot default name of the configuration file searching, such as the default class path scan.

Not only that, the class implements the listener SmartApplicationListener interface and the interface is also EnvironmentPostProcessor is to have the listener function and environmental processes.

Its onApplicationEvent method to judge the received event, if the event is ApplicationEnvironmentPreparedEvent call onApplicationEnvironmentPreparedEvent method for processing code is as follows:

@Override
public void onApplicationEvent(ApplicationEvent event) {
    if (event instanceof ApplicationEnvironmentPreparedEvent) {
        onApplicationEnvironmentPreparedEvent((ApplicationEnvironmentPreparedEvent) event);
    }
    if (event instanceof ApplicationPreparedEvent) {
        onApplicationPreparedEvent(event);
    }
}

onApplicationEnvironmentPreparedEvent be acquired and call its corresponding EnvironmentPostProcessor postProcessEnvironment method for processing. The loadPostProcessors method to get the EnvironmentPostProcessor precisely configured in spring.factories in the current class.

private void onApplicationEnvironmentPreparedEvent(ApplicationEnvironmentPreparedEvent event) {
    List<EnvironmentPostProcessor> postProcessors = loadPostProcessors();
    postProcessors.add(this);
    AnnotationAwareOrderComparator.sort(postProcessors);
    for (EnvironmentPostProcessor postProcessor : postProcessors) {
        postProcessor.postProcessEnvironment(event.getEnvironment(), event.getSpringApplication());
    }
}

After a series of calls to finally call the following methods of the class:

protected void addPropertySources(ConfigurableEnvironment environment, ResourceLoader resourceLoader) {
    RandomValuePropertySource.addToEnvironment(environment);
    new Loader(environment, resourceLoader).load();
}

Wherein Loader class ConfigFileApplicationListener internal class that provides a specific configuration file processing priority, Profile, loading parsing functions.

For example, in the load method Loader class will have the following piece of code:

for (PropertySourceLoader loader : this.propertySourceLoaders) {
    if (canLoadFileExtension(loader, location)) {
        load(loader, location, profile, filterFactory.getDocumentFilter(profile), consumer);
        return;
    }
}

The code PropertySourceLoader traversal list, and analyzes the corresponding configuration file, and the list herein in the same configuration in spring.factories PropertySourceLoader in:

# PropertySource Loaders
org.springframework.boot.env.PropertySourceLoader=\
org.springframework.boot.env.PropertiesPropertySourceLoader,\
org.springframework.boot.env.YamlPropertySourceLoader

Both PropertySourceLoader view the source code, you will find the configuration file format and resolution method SpringBoot supported by default.

public class PropertiesPropertySourceLoader implements PropertySourceLoader {

    private static final String XML_FILE_EXTENSION = ".xml";

    @Override
    public String[] getFileExtensions() {
        return new String[] { "properties", "xml" };
    }

    @Override
    public List<PropertySource<?>> load(String name, Resource resource) throws IOException {
        Map<String, ?> properties = loadProperties(resource);
        // ...
    }

    @SuppressWarnings({ "unchecked", "rawtypes" })
    private Map<String, ?> loadProperties(Resource resource) throws IOException {
        String filename = resource.getFilename();
        if (filename != null && filename.endsWith(XML_FILE_EXTENSION)) {
            return (Map) PropertiesLoaderUtils.loadProperties(resource);
        }
        return new OriginTrackedPropertiesLoader(resource).load();
    }
}

For example PropertiesPropertySourceLoader support and the xml configuration file properties both formats, respectively, and provide two classes OriginTrackedPropertiesLoader PropertiesLoaderUtils and perform corresponding processing.

The same YamlPropertySourceLoader support profile and yml yaml format and parsed using OriginTrackedYamlLoader class.

public class YamlPropertySourceLoader implements PropertySourceLoader {

    @Override
    public String[] getFileExtensions() {
        return new String[] { "yml", "yaml" };
    }

    @Override
    public List<PropertySource<?>> load(String name, Resource resource) throws IOException {
        // ...
        List<Map<String, Object>> loaded = new OriginTrackedYamlLoader(resource).load();
        // ...
    }
}

Of course, also in ConfigFileApplicationListener class implements splicing how to achieve the above-mentioned default profiles and profile, the relevant code is as follows:

private void loadForFileExtension(PropertySourceLoader loader, String prefix, String fileExtension,
        Profile profile, DocumentFilterFactory filterFactory, DocumentConsumer consumer) {
    // ...
    if (profile != null) {
        String profileSpecificFile = prefix + "-" + profile + fileExtension;
        load(loader, profileSpecificFile, profile, defaultFilter, consumer);
        load(loader, profileSpecificFile, profile, profileFilter, consumer);
        // Try profile specific sections in files we've already processed
        for (Profile processedProfile : this.processedProfiles) {
            if (processedProfile != null) {
                String previouslyLoaded = prefix + "-" + processedProfile + fileExtension;
                load(loader, previouslyLoaded, profile, profileFilter, consumer);
            }
        }
    }
    // ...
}

ConfigFileApplicationListener class also implements other more features, everyone interested can read debug.

Original link: " SpringBoot Profile uses detailed configuration and source code parsing "

Spring Technology Video

CSDN Institute: "the Spring the Boot video tutorials family bucket"


New Horizons program : exciting and growth are not to be missed

New Horizons program - micro-channel public number

Guess you like

Origin www.cnblogs.com/secbro/p/12088267.html