1

I am new to Java and spring boot. I am trying to create simple application where some data will be read from config.yml file like url and file for different server to update the data from file. My config.yml looks like this.

appserver1:
   url: http://localhost:8080/api1
   file: \file1.txt
appserver2:
   url: http://localhost:8081/api2
   file: \file2.txt
appserver3:
   url: http://localhost:8082/api3
   file: \file3.txt

I created 3 class where naming AppServer1 , AppServer2 and AppServer3 all have only 2 property containing URL and file path.

public class AppServer1 {
    private String URL;
    private String filePath;
    public String getURL() {
        return URL;
    }
    public void setURL(String URL) {
        this.URL = URL;
    }
    public String getFilePath() {
        return filePath;
    }
    public void setFilePath(String filePath) {
        this.filePath = filePath;
    }
}

How can I make the configuration such that I can use the above classes as Autowired where ever I need to access the AppServer1 or AppServer2 or AppServer3 all over my project. For eg. - If I want to use AppServer1 details I can directly Autowired AppServer1 and use the URL and File path in that class.

I have tried 1 solution using @Value but wanted to know if there is any other as if my config file is big so using @Value will be too hard. Below is the code I tried.

@Configuration
public class AppServer1 {
    @Value("${appserver1.url}")
    private String url;
    @Value("${appserver1.file}")
    private String file;

    @Bean
    AppServer1 beanExample() {
        return new AppServer1(url, file);
    }
}

Is there any annotation which can be used with @Configuration to directly identify the config data and used as Autowired.

Thanks.

Anish B.
  • 9,111
  • 3
  • 21
  • 41

2 Answers2

2
  • @PropertySource will be needed to load the custom yml that you have named config.yml

  • @ConfigurationProperties will be needed with a prefix in order to read the correct set of properties inside the yml

  • @Component will be needed to make that configuration class be converted into a spring bean which could be autowired

  • You also need to change the field of the class from filePath to file to match the property in your yml. Also change the field URL to url, to match again with the property.

     @PropertySource("classpath:config.yml")
     @ConfigurationProperties(prefix = appserver1)
     @EnableConfigurationProperties()
     public class AppServer1 {
         private String url;
         private String file;
         public String getUrl() {
             return url;
         }
         public void setUrl(String Url) {
             this.url = url;
         }
         public String getFile() {
             return file;
         }
         public void setFile(String file) {
             this.file = file;
         }
     }
    

If you want you can avoid @Component and use another annotations which is for that reason: Just go to the class where you need to be able to autowire those AppServers and add the following annotation @EnableConfigurationProperties ({AppServer1.class, AppServer2.class, AppServer3.class})

Panagiotis Bougioukos
  • 15,955
  • 2
  • 30
  • 47
0

First of all, don't use custom YML files as there is an issue in spring boot for custom YML support and it's still not resolved by Spring Team.

Read my answer here about why it doesn't support and also the workaround solution is attached in that answer.

Go for .properties file for now. Just create a config.properties file.

appserver1.url=http://localhost:8080/api1
appserver1.file=\\file1.txt

appserver2.url=http://localhost:8081/api2
appserver2.file=\\file2.txt

appserver3.url=http://localhost:8082/api3
appserver3.file=\\file3.txt

Then create your 3 class with same exact name (camelcase) of the field specified in the properties file.

AppServer1.java

@Component
@PropertySource("classpath:config.properties")
@ConfigurationProperties(prefix = "appserver1")
public class AppServer1 {
    private String url;

    private String file;

    public String getUrl() {
        return url;
    }

    public void setUrl(String url) {
        this.url = url;
    }

    public String getFile() {
        return file;
    }

    public void setFile(String file) {
        this.file = file;
    }

    @Override
    public String toString() {
        return "AppServer1 [url=" + url + ", file=" + file + "]";
    }

}

AppServer2.java

@Component
@PropertySource("classpath:config.properties")
@ConfigurationProperties(prefix = "appserver2")
public class AppServer2 {
    private String url;

    private String file;

    public String getUrl() {
        return url;
    }

    public void setUrl(String url) {
        this.url = url;
    }

    public String getFile() {
        return file;
    }

    public void setFile(String file) {
        this.file = file;
    }

    @Override
    public String toString() {
        return "AppServer2 [url=" + url + ", file=" + file + "]";
    }

}

AppServer3.java

@Component
@PropertySource("classpath:config.properties")
@ConfigurationProperties(prefix = "appserver3")
public class AppServer1 {
    private String url;

    private String file;

    public String getUrl() {
        return url;
    }

    public void setUrl(String url) {
        this.url = url;
    }

    public String getFile() {
        return file;
    }

    public void setFile(String file) {
        this.file = file;
    }

    @Override
    public String toString() {
        return "AppServer3 [url=" + url + ", file=" + file + "]";
    }

}

SampleController to test :

@RestController
public class SampleController {
    
    @Autowired
    private AppServer1 appServer;
    
    @GetMapping("appserver")
    public AppServer1 server() {
        return appServer;
    }

}

As soon as, you hit the api - http://localhost:8080/appserver

{
"url": "http://localhost:8080/api1",
"file": "\\file1.txt"
}
Anish B.
  • 9,111
  • 3
  • 21
  • 41
  • posting the same answer which is already posted from someone else is not considered good practice. – Panagiotis Bougioukos Jul 18 '21 at 12:47
  • @boug FYI, I didn't post the same answer. I have explained what needs to be there. – Anish B. Jul 18 '21 at 12:54
  • You can still use a YAML file for configuration, and it works the same way. You don't have to use a properties file. Sometimes, you just have to be aware of the behavior of overrides in YAML vs properties, but that is the only difference. The readability of YAML is far better than the readability of properties, so I wouldn't suggest avoiding YAML unless there is a clearly good reason to do so. – Steve Storck Jul 18 '21 at 13:22
  • 1
    @SteveStorck I know YAML has a lot of edge. But custom YAML file is not supported by `@PropertySource`. In that case, you have to move to properties file. You can read anywhere it's still not supported. There is a workaround solution that can be tried but officially it's not supported. – Anish B. Jul 18 '21 at 14:00
  • 2
    @AnishB. See https://docs.spring.io/spring-boot/docs/current/reference/html/features.html#features.external-config.yaml.directly-loading and a workaround here: https://www.baeldung.com/spring-yaml-propertysource I think it is worth it for the readability and concise format of YAML. – Steve Storck Jul 18 '21 at 16:46