1. Introducción
Hola a todos!. En este post veremos cómo inyectar propiedades dentro de nuestros microservicios de Spring Boot. Éstos se definen dentro del fichero application.yml que se debe encontrar dentro del classpath de la aplicación. En futuros post veremos que la solución mas realista es situar los properties fuera del classpath para poder realizar cambios de propiedades sin necesidad de realizar un build. Esto lo resolverá el servidor de Configuration de Spring Cloud.
Básicamente existen tres maneras de inyectar propiedades dentro de nuestros beans de Spring Boot.
- Enviroment
- @Value
- @ConfigurationProperties
Os podéis descargar el código de ejemplo de mi GitHub aquí.
Tecnologías empleadas:
- Java 8
- Gradle 3.1
- SpringBoot 1.5.2.RELEASE
- Spring 4.3.7.RELEASE
2. Ficheros
group 'com.jorgehernandezramirez.spring.springboot' version '1.0-SNAPSHOT' buildscript { repositories { mavenCentral() } dependencies { classpath("org.springframework.boot:spring-boot-gradle-plugin:1.5.2.RELEASE") } } apply plugin: 'java' apply plugin: 'idea' apply plugin: 'org.springframework.boot' apply plugin: 'maven' sourceCompatibility = 1.8 springBoot { mainClass = "com.jorgehernandezramirez.spring.springboot.helloworld.Application" } repositories { mavenCentral() } dependencies { compile("org.springframework.boot:spring-boot-starter-web") }
Mostramos la clase Application.java que permitirá arrancar Spring Boot.
package com.jorgehernandezramirez.spring.springboot.property; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class Application { public Application(){ //For Spring } public static void main(String[] args) { SpringApplication.run(Application.class, args); } }
Nos creamos los siguientes properties de ejemplo dentro del fichero application.yml
. Se definen cuáles son las diferentes base de datos que soporta springdata así como algunas características de ellas como su nombre, si son relacionales y sus fundadores. Fijaros que para especificar una lista de elementos en el caso de los fundadores, debemos poner el caracter -
delante de cada elementos de la lista.
spring: springdata: mongodb: relational: false name: mongodb founders: - "Kevin P. Ryan" - "Eliot Horowitz" - "Dwight Merriman" oracle: relational: true name: oracle founders: - "Lawrence J. Ellison" - "Ed Oates" - "Bob Miner"
A continuación veremos las diferentes formas que tenemos de hacer uso de estos properties dentro de nuestra aplicación.
3. Enviroment
Es la menos utilizada. Consiste en hacer uso de la clase org.springframework.core.env.Enviroment
de Spring. Para obtener el nombre de la base de datos de mongodb:
@Autowired private Environment environment; ... @RequestMapping("/mongodb/name/enviroment") public String getMongoDbNameUsingEnviroment(){ return environment.getProperty("spring.springdata.mongodb.name"); }
4. @Value
Consiste en hacer uso de la anotación @Value de Spring. Para obtener el nombre de la base de datos de mongodb:
@Value("${spring.springdata.mongodb.name}") private String mongoDBName; ... @RequestMapping("/mongodb/name/value") public String getMongoDbNameUsingValue(){ return mongoDBName; }
5. @Configurationproperties
Es el mecanismo más potente y más utilizado. Consiste en realizar el mapeo de propiedades sobre una clase java. Si queremos mapear las propiedades de la base de datos mongodb.
package com.jorgehernandezramirez.spring.springboot.property.configuration; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.context.annotation.Configuration; import java.io.Serializable; import java.util.List; @Configuration @ConfigurationProperties("spring.springdata.mongodb") public class SpringDataConfiguration { private Boolean relational; private String name; private List<String> founders; public SpringDataConfiguration(){ //For Spring } public SpringDataConfiguration(Boolean relational, String name, List<String> founders) { this.relational = relational; this.name = name; this.founders = founders; } public Boolean getRelational() { return relational; } public void setRelational(Boolean relational) { this.relational = relational; } public String getName() { return name; } public void setName(String name) { this.name = name; } public List<String> getFounders() { return founders; } public void setFounders(List<String> founders) { this.founders = founders; } @Override public String toString() { return "MongoDBConfiguration{" + "relational=" + relational + ", name='" + name + '\'' + ", founders='" + founders + '\'' + '}'; } }
Para hacer uso de dicha clase basta con inyectarla dentro de algún bean de Spring.
@Autowired private SpringDataConfiguration mongoDBConfiguration; ... @RequestMapping("/mongodb/name/configurationproperties") public String getMongoDbNameUsingConfigurationProperties(){ return mongoDBConfiguration.getName(); }
Realizar mapeo de todos las bases de datos definidas en application.yml en un mapa
Lo que vamos a hacer a continuación es mapear todas las bases de datos definidas en el fichero de propiedades en un Map, siendo la clave la base de datos (mongodb, oracle) y el valor una instancia de SpringDataConfiguration
. Además tener en cuenta
- En la anotación
@ConfigurationProperties
especificamos la ruta yml desde donde se va a empezar a mapear los datos - El atributo
springdata
de la claseSpringDatasConfiguration
debe coincidir con la subpropiedad que se debe encontrar por debajo de spring: dentro de application.yml
package com.jorgehernandezramirez.spring.springboot.property.configuration; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.context.annotation.Configuration; import java.util.Map; @Configuration @ConfigurationProperties("spring") public class SpringDatasConfiguration { private Map<String, SpringDataConfiguration> springdata; public SpringDatasConfiguration(){ //For Spring } public SpringDatasConfiguration(Map<String, SpringDataConfiguration> springdata) { this.springdata = springdata; } public Map<String, SpringDataConfiguration> getSpringdata() { return springdata; } public void setSpringdata(Map<String, SpringDataConfiguration> springdata) { this.springdata = springdata; } }
Para hacer uso de esta clase basta con inyectarla dentro de un bean de Spring.
@Autowired private SpringDatasConfiguration springDatasConfiguration; ... @RequestMapping("/") public Map<String, SpringDataConfiguration> getAllConfigurationUsingConfigurationProperties(){ return springDatasConfiguration.getSpringdata(); }
A continuación mostramos la clase PropertyController.java entera
package com.jorgehernandezramirez.spring.springboot.property.controller; import com.jorgehernandezramirez.spring.springboot.property.configuration.SpringDataConfiguration; import com.jorgehernandezramirez.spring.springboot.property.configuration.SpringDatasConfiguration; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.core.env.Environment; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import java.util.Map; @RestController @RequestMapping(value = "/property") public class PropertyController { @Value("${spring.springdata.mongodb.name}") private String mongoDBName; @Autowired private Environment environment; @Autowired private SpringDataConfiguration mongoDBConfiguration; @Autowired private SpringDatasConfiguration springDatasConfiguration; public PropertyController(){ //For Spring } @RequestMapping("/mongodb/name/value") public String getMongoDbNameUsingValue(){ return mongoDBName; } @RequestMapping("/mongodb/name/enviroment") public String getMongoDbNameUsingEnviroment(){ return environment.getProperty("spring.springdata.mongodb.name"); } @RequestMapping("/mongodb/name/configurationproperties") public String getMongoDbNameUsingConfigurationProperties(){ return mongoDBConfiguration.getName(); } @RequestMapping("/") public Map<String, SpringDataConfiguration> getAllConfigurationUsingConfigurationProperties(){ return springDatasConfiguration.getSpringdata(); } }
6. Probando la aplicación
Compilamos y ejecutamos la aplicación
Ejecutamos los controladores
La respuesta obtenida es
mongodb
La respuesta obtenida es
mongodb
La respuesta obtenida es
mongodb
La respuesta obtenida es
{“mongodb”:{“relational”:false,”name”:”mongodb”,”founders”:[“Kevin P. Ryan”,”Eliot Horowitz”,”Dwight Merriman”]},”oracle”:{“relational”:true,”name”:”oracle”,”founders”:[“Lawrence J. Ellison”,”Ed Oates”,”Bob Miner”]}}