El libro "Java en la nube. Spring Boot, Spring Cloud, Cloud Foundry »

imagen Hola a todos! Este libro está destinado principalmente a desarrolladores de máquinas Java y JVM que buscan formas de crear un mejor software en poco tiempo utilizando Spring Boot, Spring Cloud y Cloud Foundry. Es para aquellos que ya han escuchado el ruido que aumenta alrededor de los microservicios. Es posible que ya se haya dado cuenta de la altura estratosférica que ha arrancado Spring Boot, y le sorprende que las empresas de hoy utilicen la plataforma Cloud Foundry. Si es así, entonces este libro es para ti.

Extracto 3. Estilo de configuración de la aplicación de doce factores


Este capítulo discutirá cómo implementar la configuración de la aplicación.

Definir varios términos de vocabulario. Cuando se trata de la configuración en Spring, a menudo me refiero a ingresar en el entorno Spring varias implementaciones del contexto de la aplicación: ApplicationContext , que ayuda al contenedor a comprender cómo conectar los componentes de bean. Esta configuración se puede representar como un archivo XML que se debe servir en un ClassPathXmlApplicationContext , o clases Java anotadas de una manera que se puede proporcionar a un objeto AnnotationConfigApplicationContext . Y, por supuesto, al estudiar la última opción, nos referiremos a la configuración de Java.

Pero en este capítulo, vamos a ver la configuración en la forma en que se define en el manifiesto de la aplicación de 12 factores . En este caso, se trata de valores literales que pueden cambiar de un entorno a otro: estamos hablando de contraseñas, puertos y nombres de host, o de indicadores de propiedad. La configuración ignora las constantes mágicas integradas en el código. El manifiesto incluye un criterio excelente para la configuración correcta: ¿puede la base de código de la aplicación ser de código abierto en cualquier momento sin revelar y comprometer credenciales importantes? Este tipo de configuración se refiere exclusivamente a aquellos valores que varían de un entorno a otro y no se aplica, por ejemplo, a la conexión de Spring beans o la configuración de rutas Ruby.

Apoyo en el marco de Spring


En Spring, se ha admitido un estilo de configuración de 12 factores desde el advenimiento de la clase PropertyPlaceholderConfigurer . Una vez que se define su instancia, reemplaza los literales en la configuración XML con los valores extraídos del archivo con la extensión .properties. En el entorno Spring, la clase PropertyPlaceholderConfigurer se ofrece desde 2003. Spring 2.5 introdujo soporte para el espacio de nombres XML, y al mismo tiempo soporte para la sustitución de propiedades en este espacio. Esto permite la sustitución en la configuración XML de valores literales para las definiciones de componentes de bean con los valores asignados a las claves en el archivo de propiedades externo (en este caso, en el archivo simple.properties, que puede aparecer en la ruta de clase o ser externo a la aplicación).

La configuración en el estilo de 12 factores tiene como objetivo eliminar la falta de confiabilidad de las cadenas mágicas existentes, es decir, valores como las direcciones de las bases de datos y las cuentas para conectarse a ellas, puertos, etc., codificadas en la aplicación compilada. Si la configuración se mueve fuera de la aplicación, se puede reemplazar sin recurrir a un nuevo conjunto de código.

Class PropertyPlaceholderConfigurer


Veamos un ejemplo de uso de la clase PropertyPlaceholderConfigurer, definiciones XML de componentes de Spring bean y un archivo con una extensión de .properties fuera de los límites de la aplicación. Solo necesitamos imprimir el valor disponible en este archivo de propiedades. Esto ayudará a hacer el código que se muestra en el ejemplo 3.1.

Ejemplo 3.1 Archivo de propiedades: some.properties

configuration.projectName=Spring Framework 

Esta es la clase ClassPathXmlApplicationContext de Spring, por lo que utilizamos el espacio de nombres XML del contexto Spring y apuntamos a nuestro archivo some.properties. Luego usamos literales en forma de $ {configuration.projectName} en las definiciones de componentes de bean, y Spring los reemplazará con los valores de nuestro archivo de propiedades durante la ejecución (ejemplo 3.2).

Ejemplo 3.2. Archivo XML de configuración de Spring

 <context:property-placeholder location="classpath:some.properties"/> (1) <bean class="classic.Application"> <property name="configurationProjectName" value="${configuration.projectName}"/> </bean> 

(1) classpath: ubicación que se refiere al archivo en el bloque de código compilado actual (.jar, .war, etc.). Spring admite muchas alternativas, incluido file: y url :, que permiten que el archivo exista aparte del bloque de código.

Finalmente, veamos cómo se ve la clase Java, gracias a la cual es posible reunir todo esto (Ejemplo 3.3).

Ejemplo 3.3 La clase Java que debe configurarse con el valor de la propiedad
paquete clásico;

 import org.apache.commons.logging.LogFactory; import org.springframework.context.support.ClassPathXmlApplicationContext; public class Application { public static void main(String[] args) { new ClassPathXmlApplicationContext("classic.xml"); } public void setConfigurationProjectName(String pn) { LogFactory.getLog(getClass()).info("the configuration project name is " + pn); } } 

El primer ejemplo utiliza el formato XML de configuración de Spring Bean. En Spring 3.0 y 3.1, la situación para los desarrolladores que usan la configuración de Java ha mejorado significativamente. La anotación de valor y la abstracción del entorno se introdujeron en estas versiones.

Ambiente abstracto y valor


La abstracción del entorno representa, durante la ejecución del código, su relación indirecta con el entorno del entorno en el que se ejecuta, y permite que la aplicación plantee la pregunta ("¿Qué separador de línea es line.separator en esta plataforma?") Sobre las propiedades del entorno. Una abstracción actúa como un mapeo de claves y valores. Al configurar PropertySource en el entorno, puede configurar desde dónde se leerán estos valores. Por defecto, Spring carga las claves del sistema y los valores del entorno, como line.separator. Puede indicar a Spring que cargue las claves de configuración de un archivo en el mismo orden que podría usarse en versiones anteriores de la solución de sustitución de propiedades de Spring utilizando la anotación @PropertySource.

La anotación Value proporciona una forma de incrustar valores de entorno en constructores, setters, campos, etc. Estos valores se pueden calcular utilizando Spring Expression Language o la sintaxis de sustitución de propiedades siempre que PropertySourcesPlaceholderConfigurer esté registrado, como en el Ejemplo 3.4.

Ejemplo 3.4. Registrar PropertySourcesPlaceholderConfigurer
paquete env;

 import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.beans.factory.InitializingBean; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.PropertySource; import org.springframework.context.support.PropertySourcesPlaceholderConfigurer; import org.springframework.core.env.Environment; import javax.annotation.PostConstruct; (1) @Configuration @PropertySource("some.properties") public class Application { private final Log log = LogFactory.getLog(getClass()); public static void main(String[] args) throws Throwable { new AnnotationConfigApplicationContext(Application.class); } (2) @Bean static PropertySourcesPlaceholderConfigurer pspc() { return new PropertySourcesPlaceholderConfigurer(); } (3) @Value("${configuration.projectName}") private String fieldValue; (4) @Autowired Application(@Value("${configuration.projectName}") String pn) { log.info("Application constructor: " + pn); } (5) @Value("${configuration.projectName}") void setProjectName(String projectName) { log.info("setProjectName: " + projectName); } (6) @Autowired void setEnvironment(Environment env) { log.info("setEnvironment: " + env.getProperty("configuration.projectName")); } (7) @Bean InitializingBean both(Environment env, @Value("${configuration.projectName}") String projectName) { return () -> { log.info("@Bean with both dependencies (projectName): " + projectName); log.info("@Bean with both dependencies (env): " + env.getProperty("configuration.projectName")); }; } @PostConstruct void afterPropertiesSet() throws Throwable { log.info("fieldValue: " + this.fieldValue); } } 

(1) Anotación @PropertySource es una abreviatura similar a un marcador de posición de propiedad, que configura un PropertySource a partir de un archivo con la extensión .properties.

(2) PropertySourcesPlaceholderConfigurer debe registrarse como un bean estático, ya que es una implementación de BeanFactoryPostProcessor y debe llamarse en una etapa temprana del ciclo de vida de inicialización en Spring bean. Cuando se utilizan componentes de bean en la configuración Spring XML, este matiz no es visible.

(3) Puede decorar los campos con la anotación Value (pero no haga esto, ¡de lo contrario, el código no pasará la prueba!) ...

(4) ... o la anotación Value puede decorar los parámetros del constructor ...

(5) ... o utilice métodos de instalación ...

(6) ... o incrustar un objeto Spring Environment y realizar la resolución clave manualmente.

(7) Los parámetros con la anotación Value también se pueden usar en el proveedor de argumentos del método Bean en la configuración Spring Spring.

En este ejemplo, los valores se cargan desde el archivo simple.properties, y luego tiene el valor configuration.projectName, proporcionado de varias maneras.

Perfiles


Entre otras cosas, la abstracción del entorno introduce perfiles . Esto le permite asignar etiquetas (perfiles) para agrupar componentes de bean. Los perfiles deben usarse para describir los componentes de frijol y los gráficos de frijol que varían de un entorno a otro. Se pueden activar varios perfiles simultáneamente. Los beans que no tienen perfiles asignados siempre están activados. Los beans que tienen un perfil predeterminado solo se activan si no tienen otros perfiles activos. El atributo de perfil se puede especificar en la definición del componente de bean en XML o en clases de etiqueta, clases de configuración, componentes de bean individuales o en los métodos del proveedor de Bean que utiliza Profile .

Los perfiles le permiten describir conjuntos de componentes de bean que deben crearse en un entorno de forma algo diferente que en otro. En un perfil de desarrollo de desarrollo local, por ejemplo, puede usar la fuente de datos H2 incorporada javax.sql.DataSource, y luego, cuando el perfil prod esté activo, cambie a la fuente de datos javax.sql.DataSource obtenida usando la búsqueda JNDI o leyendo propiedades de una variable de entorno en Cloud Foundry . En ambos casos, su código funcionará: obtendrá javax.sql.DataSource, pero la decisión sobre qué instancia particular usar se toma activando uno o varios perfiles (ejemplo 3.5).

Ejemplo 3.5 Demostración de que las clases de @Configuration pueden cargar varios archivos de configuración y proporcionar diferentes beans basados ​​en
perfil activo

 package profiles; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.beans.factory.InitializingBean; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.*; import org.springframework.context.support.PropertySourcesPlaceholderConfigurer; import org.springframework.core.env.Environment; import org.springframework.util.StringUtils; @Configuration public class Application { private Log log = LogFactory.getLog(getClass()); @Bean static PropertySourcesPlaceholderConfigurer pspc() { return new PropertySourcesPlaceholderConfigurer(); } (1) @Configuration @Profile("prod") @PropertySource("some-prod.properties") public static class ProdConfiguration { @Bean InitializingBean init() { return () -> LogFactory.getLog(getClass()).info("prod InitializingBean"); } } @Configuration @Profile({ "default", "dev" }) (2) @PropertySource("some.properties") public static class DefaultConfiguration { @Bean InitializingBean init() { return () -> LogFactory.getLog(getClass()).info("default InitializingBean"); } } (3) @Bean InitializingBean which(Environment e, @Value("${configuration.projectName}") String projectName) { return () -> { log.info("activeProfiles: '" + StringUtils.arrayToCommaDelimitedString(e.getActiveProfiles()) + "'"); log.info("configuration.projectName: " + projectName); }; } public static void main(String[] args) { AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(); ac.getEnvironment().setActiveProfiles("dev"); (4) ac.register(Application.class); ac.refresh(); } } 

(1) Esta clase de configuración y todas las definiciones de Bean contenidas en ella se calcularán solo si el perfil de producción está activo.

(2) Esta clase de configuración y todas las definiciones de Bean contenidas en ella se calcularán solo si el perfil de desarrollo está activo o no hay ningún perfil activo, incluido el desarrollo.

(3) Este componente InitializingBean simplemente registra el perfil actualmente activo e ingresa el valor que finalmente se ingresó en el archivo de propiedades.

(4) Activar un perfil (o perfiles) mediante programación es bastante simple.

Spring responde a varios otros métodos de activación de perfil utilizando el token spring_profiles_active o spring.profiles.active. Se puede establecer un perfil utilizando una variable de entorno (por ejemplo, SPRING_PROFILES_ACTIVE), una propiedad JVM (-Dspring.profiles.active = ...), un parámetro de inicialización de la aplicación de servlet o mediante programación.

Configuración Bootiful


Spring Boot mejora significativamente la situación. El entorno inicialmente cargará automáticamente las propiedades de una jerarquía de ubicaciones predefinidas. Los argumentos de la línea de comando anulan los valores de propiedad derivados de JNDI, que anulan las propiedades obtenidas de System.getProperties (), etc.

- Argumentos de línea de comando.
- Atributos JNDI de java: comp / env.
- Propiedades de System.getProperties ().
- Variables de entorno del sistema operativo.
- Archivos de propiedades externas en el sistema de archivos: (config /)? Aplicación. (Yml.properties).
- Archivos de propiedades internas en el archivo (config /)? Aplicación. (Yml.properties).
- Anotación @PropertySource en clases de configuración.
- Propiedades de origen de SpringApplication.getDefaultProperties ().

Si el perfil está activo, los datos de los archivos de configuración basados ​​en el nombre del perfil se leerán automáticamente, por ejemplo, de un archivo como src / main / resources / application-foo.properties, donde foo es el perfil actual.

Si la biblioteca SnakeYAML se menciona en los classpaths, los archivos YAML también se cargarán automáticamente, siguiendo básicamente la misma convención.

La página de especificaciones de YAML establece que "YAML es un estándar legible por humanos para serializar datos para todos los lenguajes de programación". YAML es una representación jerárquica de valores. En los archivos normales con la extensión .properties, la jerarquía se indica con un punto ("."), Y en los archivos YAML, se utiliza una nueva línea y un nivel de sangría adicional. Sería bueno usar estos archivos para evitar la necesidad de especificar raíces comunes en presencia de árboles de configuración altamente ramificados.

El contenido de un archivo con la extensión .yml se muestra en el ejemplo 3.6.

Ejemplo 3.6 Archivo de propiedades de la aplicación.yml. Los datos se presentan en orden jerárquico.

 configuration: projectName : Spring Boot management: security: enabled: false 

Además, el entorno Spring Boot hace que sea mucho más fácil obtener el resultado correcto en casos generales. Convierte los argumentos -D en variables de entorno de proceso y java disponibles como propiedades. Incluso lleva a cabo su normalización, en la que la variable de entorno $ CONFIGURATION_PROJECTNAME (PROJECT_NAME CONFIGURATION) o el argumento -D en la forma –Dconfiguration.projectName (configuration.project_name) están disponibles utilizando la clave configuration.projectName (configuration.project_name) como antes el token spring_profiles_active está disponible.

Los valores de configuración son cadenas y, si son suficientes, pueden volverse ilegibles al intentar asegurarse de que dichas claves no se conviertan en cadenas mágicas en el código. Spring Boot presenta el tipo de componente @ConfigurationProperties. Al anotar un POJO - Objeto Java simple y antiguo - usando @ConfigurationProperties y especificando un prefijo, Spring intentará asignar todas las propiedades que comienzan con este prefijo a las propiedades POJO. En el siguiente ejemplo, el valor de configuration.projectName se asignará a una instancia de POJO, que todo el código puede inyectar y desreferenciar para leer valores de tipo seguro. Como resultado, solo tendrá una asignación de la tecla (Cadena) en un lugar (Ejemplo 3.7).

Ejemplo 3.7. Resolución automática de propiedades de src / main / resources / application.yml
paquete de arranque;

 import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.stereotype.Component; (1) @EnableConfigurationProperties @SpringBootApplication public class Application { private final Log log = LogFactory.getLog(getClass()); public static void main(String[] args) { SpringApplication.run(Application.class); } @Autowired public Application(ConfigurationProjectProperties cp) { log.info("configurationProjectProperties.projectName = " + cp.getProjectName()); } } (2) @Component @ConfigurationProperties("configuration") class ConfigurationProjectProperties { private String projectName; (3) public String getProjectName() { return projectName; } public void setProjectName(String projectName) { this.projectName = projectName; } } 

(1) La anotación @EnableConfigurationProperties le dice a Spring que asigne propiedades a POJO anotados con @ConfigurationProperties.

(2) La anotación @ConfigurationProperties muestra a Spring que este bean debe usarse como raíz para todas las propiedades que comienzan con la configuración., Seguido de tokens que se asignan a las propiedades del objeto.

(3) El campo projectName finalmente tendrá el valor asignado a la clave de propiedad configuration.projectName.

Spring Boot utiliza activamente el mecanismo @ConfigurationProperties para dar a los usuarios la capacidad de anular los componentes elementales del sistema. Puede observar que las claves de propiedad le permiten realizar cambios, por ejemplo, agregando la dependencia org.springframework.boot: spring-boot-starter-actuator a la aplicación web Spring Boot, y luego visitando la página 127.0.0.1 : 8080 / configprops.

Los puntos finales del actuador se analizarán con más detalle en el Capítulo 13. Están bloqueados y requieren un nombre de usuario y contraseña predeterminados. Las medidas de seguridad se pueden deshabilitar (pero solo para echar un vistazo a estos puntos) especificando management.security.enabled = false en el archivo application.properties (o en application.yml).

Obtendrá una lista de propiedades de configuración compatibles en función de los tipos presentados en los classpaths en tiempo de ejecución. A medida que crece el número de tipos de Spring Boot, se mostrarán propiedades adicionales. Este punto final también mostrará las propiedades exportadas por sus POJO que tienen la anotación @ConfigurationProperties.

Configuración registrada centralizada con Spring Cloud Configuration Server


Hasta ahora, todo está bien, pero las cosas deben ser aún más exitosas. Todavía no hemos respondido preguntas sobre casos de uso común:

  • Después de los cambios realizados en la configuración de la aplicación, se requiere un reinicio;
  • sin trazabilidad: ¿cómo determinar los cambios que se ponen en funcionamiento y, si es necesario, revertirlos?
  • la configuración está descentralizada; no está claro de inmediato dónde se deben hacer los cambios para cambiar uno u otro aspecto;
  • sin soporte de instalación para codificación y decodificación por motivos de seguridad.

Servidor de configuración de Spring Cloud


El problema de centralizar la configuración se puede resolver guardando la configuración en un directorio y señalando todas las aplicaciones. También puede instalar el control de versiones de este directorio utilizando Git o Subversion. Luego se recibirá el soporte necesario para la verificación y el registro. Pero los dos últimos requisitos aún no se cumplirán, por lo que se necesita algo más sofisticado. Diríjase al servidor de configuración Spring Cloud . La plataforma Spring Cloud ofrece un servidor de configuración y un cliente para este servidor.

El servidor Spring Cloud Config es una API REST a la que nuestros clientes se conectarán para recuperar su configuración. El servidor también gestiona el repositorio de configuración de control de versiones. Es un intermediario entre nuestros clientes y el repositorio de configuración y, por lo tanto, está en una posición favorable para implementar herramientas de seguridad para conectar las conexiones de los clientes al servicio y las conexiones del servicio al repositorio de configuración con control de versiones. El cliente Spring Cloud Config proporciona a las aplicaciones cliente un nuevo alcance, actualización, que le permite configurar los componentes Spring nuevamente sin tener que reiniciar la aplicación.

Las tecnologías como el servidor Spring Cloud Config juegan un papel importante, pero conllevan una sobrecarga adicional. Idealmente, esta responsabilidad debería transferirse a la plataforma y automatizarse. Al usar Cloud Foundry, puede encontrar el servicio del Servidor de configuración en el catálogo de servicios, cuyas acciones se basan en el uso del servidor Spring Cloud Config.

Considere un ejemplo simple. Primero, configure el servidor Spring Cloud Config. Se puede acceder a uno de estos servicios mediante varias aplicaciones Spring Boot a la vez. Necesitas hacer que funcione en algún lugar y de alguna manera. Entonces solo queda notificar a todos nuestros servicios sobre dónde encontrar el servicio de configuración. Funciona como una especie de intermediario para las claves de configuración y los valores que lee del almacenamiento de Git a través de la red o del disco. Agregue la cadena org.springframework.cloud: spring-cloud-config-server al ensamblaje de su aplicación Spring Boot para ingresar al servidor Spring Cloud Config (ejemplo 3.8).

Ejemplo 3.8. Para incrustar un servidor de configuración en el ensamblado, use la anotación @EnableConfigServer

 package demo; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.config.server.EnableConfigServer; (1) @SpringBootApplication @EnableConfigServer public class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); } } 

(1) El uso de la anotación @EnableConfigServer hace que se instale el servidor Spring Cloud Config.

El ejemplo 3.9 muestra la configuración para el servicio de configuración.

Ejemplo 3.9. Configuración del servidor de configuración Src / main / resources / application.yml

server.port = 8888
spring.cloud.config.server.git.uri = \
github.com/cloud-native-java/config-server-configuration-repository (1)

(1) Una indicación de un repositorio Git en funcionamiento que es de naturaleza local o accesible a través de la red (por ejemplo, en GitHub (https://github.com/)) y utilizado por el servidor Spring Cloud Config.

Aquí, el servicio de configuración de Spring Cloud tiene instrucciones de buscar archivos de configuración para clientes individuales en el repositorio de Git en GitHub. Señalamos este repositorio, pero un enlace a cualquier Git URI válido sería suficiente. Por supuesto, ni siquiera tiene que aplicar al sistema Git, puede usar Subversion o incluso directorios no administrados (aunque recomendamos encarecidamente no hacerlo). En este caso, el URI de almacenamiento está codificado, pero no hay nada que evite que se obtenga del argumento -D, del argumento o de una variable de entorno.

»Se puede encontrar más información sobre el libro en el sitio web del editor
» Contenidos
» Extracto

20% de descuento en cupones para fermentadores de Java - Java

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


All Articles