Implementation of spring boot Environment Abstraction

  • 2021-07-13 05:28:49
  • OfStack

In actual development, when developers write springboot, they usually test it in the local environment and then deploy it to Production environment. Generally speaking, these two environments are different, and the main difference is the difference of data sources.

In the application environment, there are two aspects of the abstract environment model integrated in the container: profiles and properties. A set of logically named bean definitions is registered in the container only if the given profile is activated.

The relationship between the environment variable object role and profiles determines which profiles (if any) is currently active and which profiles is activated by default.

@Profile

Environment Configuration Based on Java Class

The @ Profile annotation can be used to annotate the @ Configuration annotated classes. Indicates that all bean under this class are activated in this specific environment. Of course, it can also be used specifically to annotate @ Bean, because many times the difference between local environment and Production environment is only the data source.


@Configuration
public class ProfileConf {


  @Bean
  @Profile("dev")
  public UserInfo devUserInfo() {
    UserInfo userInfo = new UserInfo();
    userInfo.setId(1);
    userInfo.setName("dev");
    return userInfo;
  }

  @Bean
  @Profile("production")
  public UserInfo productionUserInfo() {
    UserInfo userInfo = new UserInfo();
    userInfo.setId(1);
    userInfo.setName("production");
    return userInfo;
  }
}

Activate profile

Now that we have updated our configuration, we still need to specify which profile is active. If you register the @ Configuration annotated class directly, you will see an NoSuchBeanDefinitionException thrown because the container cannot find an bean in the corresponding environment.


  public static void main(String[] args) {
    AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
    context.getEnvironment().setActiveProfiles("dev");
    context.register(UserConf.class);
    context.refresh();
    System.out.println(context.getBean(UserInfo.class));
  }

Default profile

Default profiles represent profiles that are enabled by default.


  @Bean
  @Profile("default")
  public UserInfo defaultUserInfo() {
    UserInfo userInfo = new UserInfo();
    userInfo.setId(1);
    userInfo.setName("default");
    return userInfo;
  }

If no profile is active, the above bean will be created; This can be seen as providing a default definition for one or more bean. If any profile is enabled, the default profile will not be applied.

Attribute source abstraction

The Spring environment abstraction provides a configurable search operation for the attribute source hierarchy.


  public static void main(String[] args) {
    AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
//    context.getEnvironment().setActiveProfiles("dev");
    context.getEnvironment().setActiveProfiles("dev");
    context.register(ProfileConf.class);
    context.refresh();
    ConfigurableEnvironment environment = context.getEnvironment();
    Map<String, Object> maps = environment.getSystemProperties();
    maps.keySet().forEach(k -> System.out.println(k + "->" + maps.get(k)));

    System.out.println("===========================");
    Map<String, Object> environment1 = environment.getSystemEnvironment();
    environment1.keySet().forEach(k -> System.out.println(k + "->" + environment1.get(k)));

    System.out.println(environment.containsProperty("java.vm.version"));
  }

In the above example, you can get two system variables and environment variables of Environment.

One PropertySource is a simple abstraction of any key-value resource, and the standard environment of Spring is configured by two PropertySource, one representing a series of JVM system attributes (System. getProperties ()) and one representing a series of system environment variables (System. getenv ()).

Specifically, when using StandardEnvironment, a call to the env. containsProperty ("java. vm. version") method returns true if foo is included in the system properties or environment variables at run time.

More importantly, the whole mechanism is configurable. Maybe you have a custom attribute source, and you want to integrate it into this search. This is no problem, simply implement and instantiate your own PropertySource and add it to the PropertySources collection of the current environment:


  ConfigurableApplicationContext ctx = new GenericApplicationContext();
  MutablePropertySources sources = ctx.getEnvironment().getPropertySources();
  sources.addFirst(new MyPropertySource());

@PropertySource

As mentioned in the previous article, Java-based configurations are often mixed with xml. Among them, @ Import can also import other Java configuration classes, and the @ PropertySource annotation here means importing. properties files.


@Configuration
@PropertySource("classpath:user.properties")
public class UserConf {

  @Autowired
  Environment environment;

  @Bean
  // Creates on each call 1 A new one bean
  @Scope("prototype")
  public UserInfo userInfo() {
    UserInfo userInfo = new UserInfo();
    userInfo.setId(Integer.valueOf(environment.getProperty("user.id")));
    System.out.println(environment.getProperty("user.name"));
    userInfo.setName(environment.getProperty("user.name"));
    return userInfo;
  }
}

user.id=11
user.name=asdasd

Any resource location placeholder that appears in @ PropertySource is resolved by the resource registered in the environment variable.

Assuming "user. name" is already registered in one of the resources, such as system properties or environment variables, the placeholder will be resolved correctly.

If not, "default/path" will use the default value. If there is no default value and the property cannot be interpreted, an IllegalArgumentException exception is thrown.


Related articles: