Empresas
Empleos
  • Sobre nosotros
  • Soluciones
    • Publicación de vacantes
      Publica tu vacante y recibe candidatos calificados en 48h.
    • Evaluación de candidatos
      500+ pruebas técnicas y psicológicas, más anti-fraude.
    • Headhunting
      Búsqueda ejecutiva a la medida de principio a fin.
    • Nómina + EOR
      Dispersión de nómina y EOR en más de 15 países de LATAM.
  • Precios
  • Empleos

0

158
Vistas
Cómo registrar errores en una ejecución de EnvironmentPostProcessor

Creé un EnvironmentPostProcessor en SpringBoot para obtener propiedades de la base de datos y lo adjunté al Environment de Spring como PropertySource.

Este es el código que tengo:

 @Override public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) { Map<String, Object> propertySource = new HashMap<>(); // LOG SOMETHING HERE ******************* logger.error("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"); String[] activeProfiles = environment.getActiveProfiles(); String[] defaultProfiles = environment.getDefaultProfiles(); // Do not pull db configuration when 'default' profile (used by Jenkins only) is run if (activeProfiles.length == 0 && defaultProfiles[0] == "default") { return; } // Load properties for Config schema String dataSourceUrl = environment.getProperty("service.datasource.url"); String username = environment.getProperty("service.datasource.username"); String password = environment.getProperty("service.datasource.password"); String driver = environment.getProperty("service.datasource.driverClassName"); try { // Build manually datasource to Config DataSource ds = DataSourceBuilder .create() .username(username) .password(password) .url(dataSourceUrl) .driverClassName(driver) .build(); // Fetch all properties PreparedStatement preparedStatement = ds.getConnection().prepareStatement("SELECT name, value FROM propertyConfig WHERE service = ?"); preparedStatement.setString(1, APP_NAME); ResultSet rs = preparedStatement.executeQuery(); // Populate all properties into the property source while (rs.next()) { String propName = rs.getString("name"); propertySource.put(propName, rs.getString("value")); } // Create a custom property source with the highest precedence and add it to Spring Environment environment.getPropertySources().addFirst(new MapPropertySource(PROPERTY_SOURCE_NAME, propertySource)); } catch (Exception e) { throw new Exception("Error fetching properties from ServiceConfig"); } }

Y este es el archivo main/META-INF/spring-factories que se tuvo que crear:

 # Environment Post Processor org.springframework.boot.env.EnvironmentPostProcessor=com.blabla.config.ReadDbPropertiesPostProcessor

El código funciona bien, obtiene de la base de datos lo que necesito. Sin embargo, me gustaría registrar información sobre esto en caso de que ocurra algo incorrecto, por ejemplo, si la base de datos está inactiva, quiero registrar un error y detener la aplicación para que se inicie. Mi aplicación está configurada para usar el registrador y no la consola.

Intenté registrar el error, lanzar excepciones, también imprimir algo, pero mi registro nunca registra esta información.

¿Cómo puedo hacer para usar el registrador durante esta etapa de principios de primavera? ¿Es posible hacer esto de todos modos? ¿Estoy usando EnvironmentPostProcessor incorrectamente?

about 4 years ago · Santiago Trujillo
3 Respuestas
Responde la pregunta

0

El problema aquí es que el sistema de registro se inicializa solo después de que se inicializa el contexto de primavera. Cuando se invoca el método de registro, el sistema de registro no sabe qué hacer con la información y no hace nada.

No hay una forma elegante de resolver este problema. O se deshace del sistema de registro administrado por resorte o usa mecanismos de registro diferido (al igual que lo hace Spring internamente).

Para poder usar DeferredLog , debe asegurarse de que después de la inicialización del contexto, el sistema solicitará reproducir los registros.

Esta es una de las formas en que podría lograrse:

 @Component public class MyEnvironmentPostProcessor implements EnvironmentPostProcessor, ApplicationListener<ApplicationEvent> { private static final DeferredLog log = new DeferredLog(); @Override public void postProcessEnvironment( ConfigurableEnvironment env, SpringApplication app) { log.error("This should be printed"); } @Override public void onApplicationEvent(ApplicationEvent event) { log.replayTo(MyEnvironmentPostProcessor.class); } }

En este ejemplo, cada mensaje de registro se almacena en caché en DeferredLog . Y una vez que el contexto se haya inicializado, el sistema llamará a onApplicationEvent . Este método reproducirá todos los eventos de registro almacenados en caché en el registrador estándar.

NOTA: Usé ApplicationListener aquí, pero puede usar cualquier forma conveniente. La idea es llamar a DeferredLog.replayTo() una vez que se haya inicializado el contexto y no importa desde qué lugar lo llame.

PD: La ubicación de spring.factories debe ser src/main/resources/META-INF ; de lo contrario, es posible que no se invoque postProcessEnvironment .

about 4 years ago · Santiago Trujillo Denunciar

0

Como se señaló en la respuesta aceptada, el problema es que el sistema de registro aún no se ha inicializado cuando se ejecutan los EnvironmentPostProcessor .

Sin embargo, usar un mecanismo como un DeferredLog estático en EnvironmentPostProcessor para almacenar los registros temporalmente y luego reproducirlos en ApplicationListener<ApplicationPreparedEvent> (una vez que se inicializa el sistema de registro) tampoco funciona porque EnvironmentPostProcessor y ApplicationListener están cargados e inicializados por una clase diferente. cargadores

Por eso, la instancia de la Clase utilizada para ApplicationListener no tiene visibilidad en la instancia de la Clase utilizada como EnvironmentPostProcessor (incluso si son de hecho la misma clase).

Un truco sería usar System.setProperty(...) para configurar lo que desea cerrar sesión en EnvironmentPostProcessor y System.getProperty(...) en ApplicationListener para cerrar sesión. Esto evita el problema con los cargadores de clases de Spring. Definitivamente recomiendo no usar este enfoque, pero funciona.

YMMV, pero en mi caso descubrí que mover la lógica de configuración del entorno personalizado de un EnvironmentPostProcessor a un ApplicationListener<ApplicationPreparedEvent> funcionó bien para mí, incluido el registro.

Referencia de eventos de la aplicación Spring: https://docs.spring.io/spring-boot/docs/2.2.6.RELEASE/reference/html/spring-boot-features.html#boot-features-application-events-and-listeners


ACTUALIZACIÓN: según la respuesta de shaohua-shi , aquí hay una solución de trabajo simple que usa un ApplicationContextInitializer para reproducir un DeferredLog después de que se haya inicializado el sistema de registro:

 public class MyEnvPostProcessor implements EnvironmentPostProcessor { private DeferredLog log = new DeferredLog(); @Override public void postProcessEnvironment(ConfigurableEnvironment env, SpringApplication app) { app.addInitializers(ctx -> log.replayTo(MyEnvPostProcessor.class)); log.warn("In Env Post Processor"); } }

Tronco:

 . ____ _ __ _ _ /\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \ ( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \ \\/ ___)| |_)| | | | | || (_| | ) ) ) ) ' |____| .__|_| |_|_| |_\__, | / / / / =========|_|==============|___/=/_/_/_/ :: Spring Boot :: (v2.3.1.RELEASE) 2020-06-25 20:51:15.118 WARN 7297 --- [ restartedMain] cetestenvpostproc.MyEnvPostProcessor : In Env Post Processor
about 4 years ago · Santiago Trujillo Denunciar

0

¡Encontré! invoque addInitializers cuando ejecute postProcessEnvironment.

 public class MyEnvironmentProcessor implements EnvironmentPostProcessor, Ordered { public static final int ORDER = Ordered.LOWEST_PRECEDENCE - 6; private DeferredLog logger = new DeferredLog(); @Override public void postProcessEnvironment(ConfigurableEnvironment env, SpringApplication app) { app.addInitializers(new MyContextInitializer(this)); logger.error("---------------MyEnvironmentProcessor---------------"); } public DeferredLog getLogger() { return logger; } }
 public class MyContextInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext> { private final Logger logger = LoggerFactory.getLogger(I3keContextInitializer.class); MyEnvironmentProcessor processor; public MyContextInitializer(MyEnvironmentProcessor processor) { this.processor = processor; } @Override public void initialize(ConfigurableApplicationContext applicationContext) { logger.warn("------------> DeferredLog:"); processor.getLogger().replayTo(MyEnvironmentProcessor.class); } }

Mostrar registro

 . ____ _ __ _ _ /\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \ ( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \ \\/ ___)| |_)| | | | | || (_| | ) ) ) ) ' |____| .__|_| |_|_| |_\__, | / / / / =========|_|==============|___/=/_/_/_/ :: Spring Boot :: (v2.3.0.RELEASE) 06-10 15:48:59.874 WARN 38518 --- [restartedMain] cseinit.MyContextInitializer |21 : ------------> DeferredLog: 06-10 15:48:59.885 ERROR 38518 --- [restartedMain] cseeMyEnvironmentProcessor |231 : ---------------MyEnvironmentProcessor---------------
about 4 years ago · Santiago Trujillo Denunciar
Responde la pregunta
Encuentra empleos remotos

¡Descubre la nueva forma de encontrar empleo!

Top de empleos
Top categorías de empleo
Empresas
Publicar vacante Precios Comercial
Legal
Términos y condiciones Política de privacidad
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomiéndame algunas ofertas
Necesito ayuda