Solución:
Para aquellos que necesitan cargar propiedades de la base de datos antes de que se inicie la aplicación, y hacer que esos accesorios sean accesibles mediante @Value en cualquier lugar de su proyecto, simplemente agregue este procesador.
public class ReadDbPropertiesPostProcessor implements EnvironmentPostProcessor {
/**
* Name of the custom property source added by this post processor class
*/
private static final String PROPERTY_SOURCE_NAME = "databaseProperties";
private String[] KEYS = {
"excel.threads",
"cronDelay",
"cronDelayEmail",
"spring.mail.username",
"spring.mail.password",
"spring.mail.host",
"spring.mail.port",
"spring.mail.properties.mail.transport.protocol",
"spring.mail.properties.mail.smtp.auth",
"spring.mail.properties.mail.smtp.starttls.enabled",
"spring.mail.properties.mail.debug",
"spring.mail.properties.mail.smtp.starttls.required",
"spring.mail.properties.mail.socketFactory.port",
"spring.mail.properties.mail.socketFactory.class",
"spring.mail.properties.mail.socketFactory.fallback",
"white.executor.threads",
"white.search.threads",
"lot.sync.threads",
"lot.async.threads",
"lot.soap.threads",
"excel.async.threads",
"kpi.threads",
"upload.threads"
};
/**
* Adds Spring Environment custom logic. This custom logic fetch properties from database and setting highest precedence
*/
@Override
public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) {
Map<String, Object> propertySource = new HashMap<>();
try {
// Build manually datasource to ServiceConfig
DataSource ds = DataSourceBuilder
.create()
.username(environment.getProperty("spring.datasource.username"))
.password(environment.getProperty("spring.mail.password"))
.url(environment.getProperty("spring.datasource.url"))
.driverClassName("com.mysql.jdbc.Driver")
.build();
// Fetch all properties
Connection connection = ds.getConnection();
JTrace.genLog(LogSeverity.informational, "cargando configuracion de la base de datos");
PreparedStatement preparedStatement = connection.prepareStatement("SELECT value FROM config WHERE id = ?");
for (int i = 0; i < KEYS.length; i++) {
String key = KEYS[i];
preparedStatement.setString(1, key);
ResultSet rs = preparedStatement.executeQuery();
// Populate all properties into the property source
while (rs.next()) {
propertySource.put(key, rs.getString("value"));
}
rs.close();
preparedStatement.clearParameters();
}
preparedStatement.close();
connection.close();
// 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 (Throwable e) {
throw new RuntimeException(e);
}
}
} // class ReadDbPropertiesPostProcessor end
En application.properties deben existir datos de origen de datos para poder conectarse a la base de datos.
Luego en carpeta META-INF crear un archivo llamado fábricas de primavera y allí ponga la siguiente línea:
org.springframework.boot.env.EnvironmentPostProcessor=test.config.ReadDbPropertiesPostProcessor
Y eso es todo, las propiedades retiradas serán accesibles en cualquier lugar.
Puede configurar los beans con los valores de la base de datos manualmente dependiendo de sus necesidades (de esta manera puede aprovechar Spring CDI y las configuraciones de la base de datos de arranque).
Tomemos como ejemplo la configuración del tiempo de espera de la sesión:
@SpringBootApplication
public class MySpringBootApplication extends SpringBootServletInitializer {
public static void main(String[] args) {
SpringApplication.run(MySpringBootApplication.class, args);
}
@Bean
public HttpSessionListener httpSessionListener(){
return new MyHttpSessionListener();
}
}
Luego, una definición de bean para configurar el bean:
import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;
public class MyHttpSessionListener implements HttpSessionListener {
@Autowired
private MyRepository myRepository;
@Override
public void sessionCreated(HttpSessionEvent se) {
se.getSession().setMaxInactiveInterval(this.myRepository.getSessionTimeoutSeconds());
}
@Override
public void sessionDestroyed(HttpSessionEvent se) {
// Noop
}
}
Nota: puede mover la llamada de la base de datos a una @PostConstruct
método para evitar hacerlo para cada sesión.