Configuración de la aplicación - Metadatos de configuración de Spring

Personalizar su aplicación con @ConfigurationProperties , como alternativa al uso de @Value .

En el articulo

  • Establecer y cambiar la funcionalidad de la aplicación a través de application.properties usando ConfigurationProperties
  • Integrando application.properties con el IDE
  • Comprobando la configuración

imagen

Las diferencias entre los dos enfoques se describen aquí: ConfigurationProperties vs. Valor
En la imagen de arriba, la composición principal y el principio de funcionamiento. Los componentes disponibles del sistema, estos son componentes Spring, solo se pueden especificar clases, varias constantes, variables, etc. en el archivo application.properties, e incluso en el momento en que el entorno de desarrollo lo indique, se ofrecerán opciones y se realizarán verificaciones. Cuando se inicia la aplicación, se verificará que los valores indicados cumplan con el tipo, las restricciones y, si todo es satisfactorio, se iniciará la aplicación. Por ejemplo, es muy conveniente configurar la funcionalidad de la aplicación de la lista de componentes Spring disponibles, a continuación mostraré cómo.
Clase de propiedad

Para crear configuraciones de aplicaciones usando ConfigurationProperties, puede comenzar con una clase de propiedad. En realidad, indica las propiedades, los componentes del sistema que queremos configurar.

AppProperties.java
 @ConfigurationProperties(prefix = "demo") @Validated public class AppProperties { private String vehicle; @Max(value = 999, message = "Value 'Property' should not be greater than 999") private Integer value; private Map<String,Integer> contexts; private StrategyEnum strategyEnum; private Resource resource; private DemoService service; public String getVehicle() { return vehicle; } public void setVehicle(String vehicle) { this.vehicle = vehicle; } public Map<String, Integer> getContexts() { return contexts; } public void setContexts(Map<String, Integer> contexts) { this.contexts = contexts; } public StrategyEnum getStrategyEnum() { return strategyEnum; } public void setStrategyEnum(StrategyEnum strategyEnum) { this.strategyEnum = strategyEnum; } public Resource getResource() { return resource; } public void setResource(Resource resource) { this.resource = resource; } public DemoService getService() { return service; } public void setService(DemoService service) { this.service = service; } public Integer getValue() { return value; } public void setValue(Integer value) { this.value = value; } @Override public String toString() { return "MyAppProperties{" + "\nvehicle=" + vehicle + "\n,contexts=" + contexts + "\n,service=" + service + "\n,value=" + value + "\n,strategyEnum=" + strategyEnum + '}'; } } 


En la clase prefix = "demo" se utilizará en application.properties, como prefijo de la propiedad.

Clase de aplicación SpringApplication y proyecto pom.xml
 @SpringBootApplication @EnableConfigurationProperties({AppProperties.class}) @ImportResource(value= "classpath:context.xml") public class DemoConfigProcessorApplication { public static void main(String[] args) { ConfigurableApplicationContext context = SpringApplication.run(DemoConfigProcessorApplication.class, args); AppProperties properties = context.getBean(AppProperties.class); String perform = properties.getService().perform(properties.getVehicle()); System.out.println("perform: " + perform); System.out.println(properties.toString()); } } 

 <?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.example</groupId> <artifactId>demoConfigProcessor</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>jar</packaging> <name>demoConfigProcessor</name> <description>Demo project for Spring Boot Configuration Processor</description> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.1.0.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <java.version>1.8</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-validation</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-configuration-processor</artifactId> <optional>true</optional> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>com.jayway.jsonpath</groupId> <artifactId>json-path</artifactId> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project> 


Entonces declare dos contenedores de primavera

Contexto de primavera (context.xml)
 <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <bean id="service1" class="com.example.demoConfigProcessor.MyDemoService1"> <description>Description MyDemoService 1</description> </bean> <bean id="service2" class="com.example.demoConfigProcessor.MyDemoService2"> <description>Description MyDemoService 2</description> </bean> </beans> 


En la clase AppProperties, especifiqué un enlace a algún servicio de aplicación disponible, lo cambiaré en application.properties, tendré dos de sus implementaciones y conectaré una de ellas en application.properties.

imagen

Aquí está su implementación

DemoService
 public interface DemoService { String perform(String value); } 

 public class MyDemoService1 implements DemoService { @Override public String perform(String value) { return "Service №1: perform routine maintenance work on <" + value +">"; } } 

 public class MyDemoService2 implements DemoService { @Override public String perform(String value) { return "Service №2: perform routine maintenance work on <" + value +">"; } } 


Esto ahora es suficiente para comenzar a personalizar application.properties. Pero cada vez que se realizan cambios en la clase con ConfigurationProperties, debe reconstruir el proyecto, después de lo cual el archivo aparece en el proyecto
\target\classes\META-INF\spring-configuration-metadata.json . En realidad, su IDE se utiliza para editar en el archivo application.properties. Indicaré su estructura en el enlace de los materiales. Este archivo se creará en función de la clase AppProperties. Si ahora abre el archivo application.properties y comienza a escribir "demo", el entorno comenzará a mostrar las propiedades disponibles

imagen

Si intenta ingresar el tipo incorrecto, el IDE informará

imagen

Incluso si lo deja como está e intenta iniciar la aplicación, habrá un error completamente distinto

imagen
Agregar metadatos adicionales

Metadatos adicionales, esto es solo por la conveniencia de trabajar con application.properties en el IDE, si esto no es necesario, no puede hacerlo. Para hacer esto, es posible especificar sugerencias y otra información para el entorno en un archivo adicional. Para hacer esto, copie el archivo spring-configuration-metadata.json creado en \src\main\resources\META-INF\ y cámbiele el nombre a
additional-spring-configuration-metadata.json . En este archivo, solo me interesará la sección de sugerencias: []

En él será posible enumerar, por ejemplo, valores válidos para demo.vehicle

 "hints": [ { "name": "demo.vehicle", "values": [ { "value": "car make A", "description": "Car brand A is allowed." }, { "value": "car make B", "description": "Car brand B is allowed." } ] }] 

En el campo "nombre", se indica la propiedad "demo.vehicle", y en "valores" una lista de valores válidos. Ahora, si reconstruyo el proyecto y voy al archivo application.properties, cuando entro en demo.vehicle obtengo una lista de valores válidos

imagen

Si ingresa una diferente de la propuesta, pero del mismo tipo, el editor resaltará, pero la aplicación se iniciará en este caso, ya que esta no es una restricción estricta, sino solo una pista.

imagen

Anteriormente en el proyecto, anuncié dos servicios MyDemoService1 y MyDemoService2, ambos implementan la interfaz DemoService, ahora puede configurar para que solo los servicios que implementan esta interfaz sean accesibles para application.properties y, en consecuencia, la clase seleccionada se inicializa en la clase AppProperties. Para hacer esto, hay Proveedores, puede especificarlos en metadatos de configuración de resorte adicionales. Hay varios tipos de proveedores que se pueden encontrar en la documentación, mostraré un ejemplo para uno, spring-bean-reference . Este tipo muestra los nombres de los beans disponibles en el proyecto actual. La lista está limitada a la clase base o interfaz.

Ejemplo de proveedores para DemoService:

  "hints": [ { "name": "demo.service", "providers": [ { "name": "spring-bean-reference", "parameters": { "target": "com.example.demoConfigProcessor.DemoService" } } ] } ] 

Después de eso, en application.properties para el parámetro demo.service, una opción de dos servicios estará disponible, puede ver su descripción (descripción de la definición).

imagen

Ahora es conveniente elegir el servicio adecuado, cambiar la funcionalidad de la aplicación. Hay un punto para la configuración de objetos, Spring necesita un poco de ayuda para convertir la cadena que se especifica en la configuración en un objeto. Para hacer esto, una pequeña clase se hereda de Converter.

ServiceConverter
 @Component @ConfigurationPropertiesBinding public class ServiceConverter implements Converter<String, DemoService> { @Autowired private ApplicationContext applicationContext; @Override public DemoService convert(String source) { return (DemoService) applicationContext.getBean(source); } } 


El diagrama de clase de proyecto muestra cómo estos servicios están separados de la aplicación principal y son accesibles a través de AppProperties.

imagen
Propiedad de validación
En los campos de la clase AppProperties, puede agregar comprobaciones disponibles en el marco de JSR 303. Escribí sobre esto aquí . Esto dará como resultado un archivo de configuración de la aplicación conveniente y verificable.

Salida de la consola

imagen

Estructura del proyecto

imagen

Archivo completo Additional-Spring-configuration-metadata.json

adicional-spring-configuration-metadata
 { "groups": [ { "name": "demo", "type": "com.example.demoConfigProcessor.AppProperties", "sourceType": "com.example.demoConfigProcessor.AppProperties" } ], "properties": [ { "name": "demo.contexts", "type": "java.util.Map<java.lang.String,java.lang.Integer>", "sourceType": "com.example.demoConfigProcessor.AppProperties" }, { "name": "demo.vehicle", "type": "java.lang.String", "sourceType": "com.example.demoConfigProcessor.AppProperties" } ], "hints": [ { "name": "demo.vehicle", "values": [ { "value": "car make A", "description": "Car brand A is allowed." }, { "value": "car make B", "description": "Car brand B is allowed." } ] }, { "name": "demo.service", "providers": [ { "name": "spring-bean-reference", "parameters": { "target": "com.example.demoConfigProcessor.DemoService" } } ] } ] } 


Materiales de metadatos de configuración

Source: https://habr.com/ru/post/es430256/


All Articles