Environment, which represents the Environment information of the entire Spring application runtime, contains two key elements

  • profiles
  • properties

profiles

The concept of Profiles is probably well understood, and the most common is the solution that determines the different configuration contexts in the current Spring container in different environments. For example, when building different application.properties profiles for development, test, and production environments, we can use the Profiles property to determine which profiles are valid in the current Spring application context.

In fact, Profiles allows you to logically group the configuration of beans. In simple terms, profiles can be used to logically group different beans. This group has nothing to do with the definition of the bean itself, and you can configure which profile group the bean belongs to, whether in XML or annotations.

When there are multiple profile groupings, we can specify which profile takes effect, but if we do not specify this, Spring will follow the default profile. Let’s demonstrate this with a code.

ProfileService

Create a normal class with the following code

public class ProfileService {
    private String profile;

    public ProfileService(String profile) {

        this.profile = profile;
    }

    @Override
    public String toString(a) {
        return "ProfileService{" +
                "profile='" + profile + '\' ' +
                '} '; }}Copy the code

Declare a configuration class

In the configuration class, build two beans and configure different profiles.

@Configuration
public class ProfileConfiguration {

    @Bean
    @Profile("dev")
    public ProfileService profileServiceDev(a){
        return new ProfileService("dev");
    }

    @Bean
    @Profile("prod")
    public ProfileService profileServiceProd(a){
        return new ProfileService("prod"); }}Copy the code

Define test methods

public class ProfileMain {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext applicationContext=new AnnotationConfigApplicationContext();
// applicationContext.getEnvironment().setActiveProfiles("prod");applicationContext.register(ProfileConfiguration.class); applicationContext.refresh(); System.out.println(applicationContext.getBean(ProfileService.class)); }}Copy the code

Can be active configuration through many ways, by default is not to add applicationContext. GetEnvironment () setActiveProfiles (” prod “); You will find that the bean is not loaded. Once added, which bean is loaded is determined based on the currently active Profiles.

In addition, we can add -dspring.profiles. active=prod to the startup parameter to determine which profile is currently active. This property can be configured in system environment variables, JVM system properties, and so on.

Note that configuration files are not optional; It is possible to have multiple profiles active at the same time, programmatically using the setActiveProfiles() method, which takes a String array argument, namely multiple profile names

applicationContext.getEnvironment().setActiveProfiles("prod"."dev");
Copy the code

If no profile configuration is activated, the default profile will be activated. The default profile profile can be changed either by the setDefaultProfiles method of the environment variable, or by the declared value of the spring.profiles.default property

Profiles summary

To summarize, Profiles can be logically grouped into a group of beans that are loaded according to the active profile configured in the Environment context. It determines which profile is currently active.

  • A profile is a logical grouping of Bean definitions.

  • This group, this profile, is given a name, this profile name.

  • Only when a profile is in the active state are its logically organized Bean definitions registered with the container.

  • Beans added to profiles can be defined in XML or annotated.

  • The role played by Environment for profiles is to specify which profiles are currently active defaults.

Properties

Properties is used to store properties. It helps us manage various configuration information. The source of this configuration can be a Properties file, JVM Properties, system environment variables, or specialized Properties objects, etc.

Let’s take a look at the Environment interface, which inherits PropertyResolver. This interface is related to the operation of properties, that is, we can set and obtain properties through the Environment.

public interface Environment extends PropertyResolver {
    String[] getActiveProfiles();

    String[] getDefaultProfiles();

    / * *@deprecated* /
    @Deprecated
    boolean acceptsProfiles(String... var1);

    boolean acceptsProfiles(Profiles var1);
}
Copy the code

So far, we can simply summarize the role of Environment. Environment provides different profile configurations, while PropertyResolver provides configuration operations. The Spring container can obtain different configuration information based on different profiles to achieve the processing of the runtime environment in the Spring container.

The application of the environment

  • In the Spring Boot application, modify the application.properties configuration

    env=default
    Copy the code
  • Create a Controller to test

    @RestController
    public class EnvironementController {
    
        @Autowired
        Environment environment;
    
        @GetMapping("/env")
        public String env(a){
            return environment.getProperty("env"); }}Copy the code

Specify profile properties

In the previous section, we introduced the concepts of profile and property. Now let’s use the two concepts together to understand them better.

In spring Boot applications, the default externalized configuration is the application.properties file. In fact, in addition to this default configuration file, we can use the convention naming format in SpringBoot to implement the configuration of different environments

application-profile.properties
Copy the code

Which properties file the current Spring Boot application chooses to use as its context configuration depends on the currently active profile. Also, we can activate it in a number of ways, such as by adding spring.profiles. Active =dev to application.properties, or by adding this configuration to JVM parameters to specify the configuration in effect.

When not specified, the default configuration file is used. Simply put, if a configuration file is not explicitly activated, the application loads the properties in application-default.properties.

This function is very useful, the general company will have several operating environments, such as development, test, production environment, these environments will have some configuration information is different, such as the server address. We need to use the specified configuration information for different environments, which can be easily solved in this way.

The use of @value annotations

In addition to properties defined in the properties file, which can be obtained through environment’s getProperty method, Spring also provides the @Value annotation,

@RestController
public class EnvironementController {

    @Value("${env}")
    private String env;

    @GetMapping("/env")
    public String env(a){
        returnenv; }}Copy the code

When the Spring container loads a bean and finds that the bean has an @Value annotation, it can inject the property Value from the Environment, and an error will be reported if the property is not present in the Environment.

Spring Environment principle design

Based on what we have talked about before, let’s speculate about the realization principle of Environment.

A brief demonstration of configuration sources in the Environment

  • @value (“${java.version}”) gets system.getProperties, which gets System properties
  • Configure the JVM parameters for command,-Denvtest=command

Based on the derivation of the existing content, we can draw the following diagram.

  • The first part is the property definition, which can come from many places, such as application.properties, or system environment variables.
  • The configuration is then loaded in the specified path or scope in the convention and saved in memory.
  • Finally, we can look up the value from the cache based on the specified key.

The following is the class diagram representing Environment, which clearly reflects the principle of Environment.

The core API of the above class diagram is described below

  1. Environment interface, inheriting PropertyResolver. PropertyResolver, which has two main functions.

    • Obtain the corresponding propertValue value (getProperty) from the propertyName propertyName.

    • ${propertyName: defaultValue} format attributes placeholder, replaced by the actual value (resolvePlaceholders).

  2. Specific implementation class is PropertySourcesPropertyResolver PropertyResolver, attribute the source solution. This class is the only complete implementation class in the architecture. It takes the PropertySources PropertySource collection (internally held PropertySource List) as the source of property values, traverses each PropertySource sequentially, and returns a non-null property value.

Among them, the List of PropertySourcesPropertyResolver, said the source of the source of different attributes, it is the class diagram is as follows, said according to different data sources of storage.

Copyright Notice: All articles on this blog are subject to a CC BY-NC-SA 4.0 license unless otherwise stated. Reprint please specify from Mic to take you to learn structure! If this article is helpful to you, please also help to point attention and like, your persistence is the power of my continuous creation. Welcome to pay attention to the same wechat public account for more technical dry goods!