Configure Postgres' application_name from the environment

This commit configure the 'application_name' property of the Postgres
container from the standard 'spring.application.name'.

See gh-42460
This commit is contained in:
Dmytro Nosan
2024-09-30 20:51:12 +03:00
committed by Stéphane Nicoll
parent d2a7c68792
commit ce0bcf3493
9 changed files with 386 additions and 25 deletions

View File

@@ -17,6 +17,7 @@
package org.springframework.boot.docker.compose.service.connection;
import org.springframework.boot.docker.compose.core.RunningService;
import org.springframework.core.env.Environment;
/**
* Passed to {@link DockerComposeConnectionDetailsFactory} to provide details of the
@@ -32,12 +33,16 @@ public final class DockerComposeConnectionSource {
private final RunningService runningService;
private final Environment environment;
/**
* Create a new {@link DockerComposeConnectionSource} instance.
* @param runningService the running Docker Compose service
* @param environment environment in which the current application is running
*/
DockerComposeConnectionSource(RunningService runningService) {
DockerComposeConnectionSource(RunningService runningService, Environment environment) {
this.runningService = runningService;
this.environment = environment;
}
/**
@@ -48,4 +53,13 @@ public final class DockerComposeConnectionSource {
return this.runningService;
}
/**
* Environment in which the current application is running.
* @return the environment
* @since 3.5.0
*/
public Environment getEnvironment() {
return this.environment;
}
}

View File

@@ -31,6 +31,7 @@ import org.springframework.boot.docker.compose.core.RunningService;
import org.springframework.boot.docker.compose.lifecycle.DockerComposeServicesReadyEvent;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationListener;
import org.springframework.core.env.Environment;
import org.springframework.util.ClassUtils;
import org.springframework.util.StringUtils;
@@ -59,13 +60,15 @@ class DockerComposeServiceConnectionsApplicationListener
public void onApplicationEvent(DockerComposeServicesReadyEvent event) {
ApplicationContext applicationContext = event.getSource();
if (applicationContext instanceof BeanDefinitionRegistry registry) {
registerConnectionDetails(registry, event.getRunningServices());
Environment environment = applicationContext.getEnvironment();
registerConnectionDetails(registry, environment, event.getRunningServices());
}
}
private void registerConnectionDetails(BeanDefinitionRegistry registry, List<RunningService> runningServices) {
private void registerConnectionDetails(BeanDefinitionRegistry registry, Environment environment,
List<RunningService> runningServices) {
for (RunningService runningService : runningServices) {
DockerComposeConnectionSource source = new DockerComposeConnectionSource(runningService);
DockerComposeConnectionSource source = new DockerComposeConnectionSource(runningService, environment);
this.factories.getConnectionDetails(source, false).forEach((connectionDetailsType, connectionDetails) -> {
register(registry, runningService, connectionDetailsType, connectionDetails);
this.factories.getConnectionDetails(connectionDetails, false)

View File

@@ -16,11 +16,16 @@
package org.springframework.boot.docker.compose.service.connection.postgres;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import org.springframework.boot.autoconfigure.jdbc.JdbcConnectionDetails;
import org.springframework.boot.docker.compose.core.RunningService;
import org.springframework.boot.docker.compose.service.connection.DockerComposeConnectionDetailsFactory;
import org.springframework.boot.docker.compose.service.connection.DockerComposeConnectionSource;
import org.springframework.boot.docker.compose.service.connection.jdbc.JdbcUrlBuilder;
import org.springframework.core.env.Environment;
import org.springframework.util.StringUtils;
/**
* {@link DockerComposeConnectionDetailsFactory} to create {@link JdbcConnectionDetails}
@@ -42,7 +47,7 @@ class PostgresJdbcDockerComposeConnectionDetailsFactory
@Override
protected JdbcConnectionDetails getDockerComposeConnectionDetails(DockerComposeConnectionSource source) {
return new PostgresJdbcDockerComposeConnectionDetails(source.getRunningService());
return new PostgresJdbcDockerComposeConnectionDetails(source.getRunningService(), source.getEnvironment());
}
/**
@@ -57,10 +62,11 @@ class PostgresJdbcDockerComposeConnectionDetailsFactory
private final String jdbcUrl;
PostgresJdbcDockerComposeConnectionDetails(RunningService service) {
PostgresJdbcDockerComposeConnectionDetails(RunningService service, Environment environment) {
super(service);
this.environment = new PostgresEnvironment(service.env());
this.jdbcUrl = jdbcUrlBuilder.build(service, this.environment.getDatabase());
this.jdbcUrl = addApplicationNameIfNecessary(jdbcUrlBuilder.build(service, this.environment.getDatabase()),
environment);
}
@Override
@@ -78,6 +84,27 @@ class PostgresJdbcDockerComposeConnectionDetailsFactory
return this.jdbcUrl;
}
private static String addApplicationNameIfNecessary(String jdbcUrl, Environment environment) {
if (jdbcUrl.contains("&ApplicationName=") || jdbcUrl.contains("?ApplicationName=")) {
return jdbcUrl;
}
String applicationName = environment.getProperty("spring.application.name");
if (!StringUtils.hasText(applicationName)) {
return jdbcUrl;
}
StringBuilder jdbcUrlBuilder = new StringBuilder(jdbcUrl);
if (!jdbcUrl.contains("?")) {
jdbcUrlBuilder.append("?");
}
else if (!jdbcUrl.endsWith("&")) {
jdbcUrlBuilder.append("&");
}
return jdbcUrlBuilder.append("ApplicationName")
.append('=')
.append(URLEncoder.encode(applicationName, StandardCharsets.UTF_8))
.toString();
}
}
}

View File

@@ -17,12 +17,15 @@
package org.springframework.boot.docker.compose.service.connection.postgres;
import io.r2dbc.spi.ConnectionFactoryOptions;
import io.r2dbc.spi.Option;
import org.springframework.boot.autoconfigure.r2dbc.R2dbcConnectionDetails;
import org.springframework.boot.docker.compose.core.RunningService;
import org.springframework.boot.docker.compose.service.connection.DockerComposeConnectionDetailsFactory;
import org.springframework.boot.docker.compose.service.connection.DockerComposeConnectionSource;
import org.springframework.boot.docker.compose.service.connection.r2dbc.ConnectionFactoryOptionsBuilder;
import org.springframework.core.env.Environment;
import org.springframework.util.StringUtils;
/**
* {@link DockerComposeConnectionDetailsFactory} to create {@link R2dbcConnectionDetails}
@@ -44,7 +47,7 @@ class PostgresR2dbcDockerComposeConnectionDetailsFactory
@Override
protected R2dbcConnectionDetails getDockerComposeConnectionDetails(DockerComposeConnectionSource source) {
return new PostgresDbR2dbcDockerComposeConnectionDetails(source.getRunningService());
return new PostgresDbR2dbcDockerComposeConnectionDetails(source.getRunningService(), source.getEnvironment());
}
/**
@@ -53,16 +56,16 @@ class PostgresR2dbcDockerComposeConnectionDetailsFactory
static class PostgresDbR2dbcDockerComposeConnectionDetails extends DockerComposeConnectionDetails
implements R2dbcConnectionDetails {
private static final Option<String> APPLICATION_NAME = Option.valueOf("applicationName");
private static final ConnectionFactoryOptionsBuilder connectionFactoryOptionsBuilder = new ConnectionFactoryOptionsBuilder(
"postgresql", 5432);
private final ConnectionFactoryOptions connectionFactoryOptions;
PostgresDbR2dbcDockerComposeConnectionDetails(RunningService service) {
PostgresDbR2dbcDockerComposeConnectionDetails(RunningService service, Environment environment) {
super(service);
PostgresEnvironment environment = new PostgresEnvironment(service.env());
this.connectionFactoryOptions = connectionFactoryOptionsBuilder.build(service, environment.getDatabase(),
environment.getUsername(), environment.getPassword());
this.connectionFactoryOptions = getConnectionFactoryOptions(service, environment);
}
@Override
@@ -70,6 +73,26 @@ class PostgresR2dbcDockerComposeConnectionDetailsFactory
return this.connectionFactoryOptions;
}
private static ConnectionFactoryOptions getConnectionFactoryOptions(RunningService service,
Environment environment) {
PostgresEnvironment env = new PostgresEnvironment(service.env());
ConnectionFactoryOptions connectionFactoryOptions = connectionFactoryOptionsBuilder.build(service,
env.getDatabase(), env.getUsername(), env.getPassword());
return addApplicationNameIfNecessary(connectionFactoryOptions, environment);
}
private static ConnectionFactoryOptions addApplicationNameIfNecessary(
ConnectionFactoryOptions connectionFactoryOptions, Environment environment) {
if (connectionFactoryOptions.hasOption(APPLICATION_NAME)) {
return connectionFactoryOptions;
}
String applicationName = environment.getProperty("spring.application.name");
if (!StringUtils.hasText(applicationName)) {
return connectionFactoryOptions;
}
return connectionFactoryOptions.mutate().option(APPLICATION_NAME, applicationName).build();
}
}
}