Apollo 5 teaches you how to put your own configuration in the Spring environment

Source: Internet
Author: User
Tags set set

Directory:

    1. Objective
    2. Treatment Scenarios
    3. Simple example
Objective

Sometimes you may need to put some configuration into the Spring environment, but these configurations cannot be written to die in the configuration file, only in the runtime. So, what should we do at this time?

Apollo is a configuration, then naturally encounter this problem, he is how to deal with it?

Treatment Scenarios

First, what is the data structure of a configuration in the Spring environment?

is an abstract class PropertySource<T> , inside is a key value structure. This T can be any type, depending on the design of the subclass.

Subclasses can get the configuration by overriding the GetProperty abstract method.

Spring's own Org.springframework.core.env.MapPropertySource has rewritten this method.

public class MapPropertySource extends EnumerablePropertySource<Map<String, Object>> {    public MapPropertySource(String name, Map<String, Object> source) {        super(name, source);    }    @Override    public Object getProperty(String name) {        return this.source.get(name);    }    @Override    public boolean containsProperty(String name) {        return this.source.containsKey(name);    }    @Override    public String[] getPropertyNames() {        return StringUtils.toStringArray(this.source.keySet());    }}

As you can see, his generics are map,getproperty methods that are obtained from the MAP.

Apollo took advantage of this class directly.

Two different sub-classes, different refresh logic. We don't care about their differences for the time being.

These two classes are refreshableconfig combined and added to the Spring environment.

import org.springframework.core.env.ConfigurableEnvironment;public abstract class RefreshableConfig {  @Autowired  private ConfigurableEnvironment environment; // Spring 环境  @PostConstruct  public void setup() {  // 省略代码    for (RefreshablePropertySource propertySource : propertySources) {      propertySource.refresh();      // 注意:成功刷新后,放到 Spring 的环境中      environment.getPropertySources().addLast(propertySource);    }  // 省略代码

When getting the configuration from the Spring environment, the specific code is as follows:

protected <T> T getProperty(String key, Class<T> targetValueType, boolean resolveNestedPlaceholders) {        for (PropertySource<?> propertySource : this.propertySources) {            // 注意:这里调用的就是 propertySource.getProperty 方法,子类刚刚重写的方法            Object value = propertySource.getProperty(key);             // 省略无关代码........            return convertValueIfNecessary(value, targetValueType);        }        return null;}

Spring maintains a collection of propertysource, a combination that is sequential, that is, the highest priority (traversal starts at subscript 0).

The user can maintain a configuration dictionary (Map) in Propertysource, so that a data structure like a 2-D array is used.

Therefore, the configuration can be the same name, when the name of the first propertysource in the configuration prevail. So, Spring leaves a few APIs:

    1. AddFirst (propertysource<?> Propertysource)
    2. AddLast (propertysource<?> Propertysource)
    3. Addbefore (String relativepropertysourcename, propertysource<?> propertysource)
    4. Addafter (String relativepropertysourcename, propertysource<?> propertysource)

From the name we can see that through these APIs, we can insert propertysource into the place we specify. This allows you to manually control the priority of the configuration.

There is a ready-made Compositepropertysource class in Spring that aggregates an propertysource set set, and when GetProperty (String name), it iterates over the collection and calls the Propertysource the GetProperty (name) method. Equivalent to a 3-D array.

The approximate design is this:

An environment, there are multiple PS (propertysource abbreviation), each PS can be directly included in the configuration, you can also wrap a layer of PS.

Simple example

We have a simple example here that requires:
There is a configuration in the program, but can not be written dead in the configuration file, can only be configured during program startup, and then injected into the spring environment, so that spring in the following IOC, the normal use of these configurations.

The code is as follows:

@SpringBootApplicationpublic class DemoApplication {  @Value("${timeout:1}")  String timeout;  public static void main(String[] args) throws InterruptedException {    ApplicationContext c = SpringApplication.run(DemoApplication.class, args);    for (; ; ) {      Thread.sleep(1000);      System.out.println(c.getBean(DemoApplication.class).timeout);    }  }}

Application.properties configuration file

timeout=100

In the above code, we define a property timeout in the bean, write a value of 100 in the local configuration file, and give a default value of 1 in the expression.

So now the print is the value in the configuration file: 100.

However, this is not the result we want, so we need to modify the code.

We add a class:

@Componentclass Test implements EnvironmentAware, BeanFactoryPostProcessor {  @Override  public void setEnvironment(Environment environment) {    ((ConfigurableEnvironment) environment).getPropertySources()        // 这里是 addFirst,优先级高于 application.properties 配置        .addFirst(new PropertySource<String>("timeoutConfig", "12345") {          // 重点          @Override          public Object getProperty(String s) {            if (s.equals("timeout")) {//              return source;// 返回构造方法中的 source :12345            }            return null;          }        });  }  @Override  public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory)      throws BeansException {    // NOP  }}

After running, results: 12345

2018-07-02 15:26:54.315  INFO 43393 --- [           main] o.s.j.e.a.AnnotationMBeanExporter        : Registering beans for JMX exposure on startup2018-07-02 15:26:54.327  INFO 43393 --- [           main] com.example.demo.DemoApplication         : Started DemoApplication in 0.991 seconds (JVM running for 1.49)1234512345

Why did you add this class to replace the properties in the configuration file? Explain the role of this class.

All we have to do is insert a custom PS object in the Spring environment, so that when the container gets it, it can get the corresponding configuration through the GetProperty method.

So, to get the Spring environment object, we also need to create a PS object, and rewrite the GetProperty method, and note that your own PS configuration priority needs to be higher than the container configuration file priority, and on the safe side, first place.

The first parameter of PS construction method is useless, is an identifier, the second parameter is source, can be defined as any type, string,map, can, we here simple period, is a String, directly return this value, if it is map, call map get Method.

Why do you want to implement the Beanfactorypostprocessor interface? The purpose of implementing the Beanfactorypostprocessor interface is to make the Bean's load time advance, higher than the target bean's initialization. Otherwise, the timeout attribute in the target Bean is injected to the end, and the subsequent operation is meaningless.

Summarize

Plainly, just don't want to write configuration file!!!

And do not want to change the code of the old project, the old project even in the case of deleting the configuration file, can still use the configuration center!

This requires familiarity with Spring's configuration load logic and property acquisition logic.

Now, we know that you just have to get the SPIRNG environment object and add a custom PS object to the environment and rewrite the PS GetProperty method to get the configuration (note priority).

It is also important to note that the bean that loads this configuration has a high priority, usually implementing the Beanfactorypostprocessor interface is sufficient, and if not enough, some special operations are required.

Apollo 5 teaches you how to put your own configuration in the Spring environment

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.