I am developing an multi-tenant REST spring boot application. I am able to dynamically switch between different data-sources based on a header value in every request. But my problem is on the application.properties file. The different tenants have different values for the same properties in their properties files.
How can I separate the properties files per tenant and also dynamically determine which properties files to use based on a value in the request header
Instantiate the Properties class. Populate the created Properties object using the put() method. Instantiate the FileOutputStream class by passing the path to store the file, as a parameter.
properties in default location. Spring Boot loads the application. properties file automatically from the project classpath. All you have to do is to create a new file under the src/main/resources directory.
You can't switch profiles at runtime. Your options are limited to either creating a new ApplicationContext
which comes with its own drawbacks or you can load the tenant property files at startup and implement a tenant-specific getProperty
method to call when needed.
This ought-to handle the latter case:
@Component
public class TenantProperties {
private Map<String, ConfigurableEnvironment> customEnvs;
@Inject
public TenantProperties(@Autowired ConfigurableEnvironment defaultEnv,
@Value("${my.tenant.names}") List<String> tenantNames) {
this.customEnvs = tenantNames
.stream()
.collect(Collectors.toMap(
Function.identity(),
tenantId -> {
ConfigurableEnvironment customEnv = new StandardEnvironment();
customEnv.merge(defaultEnv);
Resource resource = new ClassPathResource(tenantId + ".properties");
try {
Properties props = PropertiesLoaderUtils.loadProperties(resource);
customEnv.getPropertySources()
.addLast(new PropertiesPropertySource(tenantId, props));
return customEnv;
} catch (IOException ex) {
throw new RuntimeException(ex);
}
}));
}
public String getProperty(String tenantId, String propertyName) {
ConfigurableEnvironment ce = this.customEnvs.get(tenantId);
if (ce == null) {
throw new IllegalArgumentException("Invalid tenant");
}
return ce.getProperty(propertyName);
}
}
You need to add a my.tenant.names
property to your main application properties that contains a comma separated list of tenant names (name1, name2
, etc.). tenant-specific properties are loaded from name1.properties
, ... from the classpath. You get the idea.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With