Business
Jobs
  • About Us
  • Solutions
    • Job Postings
      Post your job and receive qualified candidates in 48h.
    • Candidate Assessments
      500+ technical and psychological tests, plus anti-fraud.
    • Headhunting
      Tailor-made executive search from start to finish.
    • Payroll + EOR
      Payroll dispersal and EOR across 15+ LATAM countries.
  • Pricing
  • Jobs

0

211
Views
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 answers
Answer question

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 Report

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 Report

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 Report
Answer question
Find remote jobs

Discover the new way to find a job!

Top jobs
Top job categories
Business
Post vacancy Pricing Sales
Legal
Terms and conditions Privacy policy
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Show me some job opportunities
There's an error!