I’m trying to make some modifications to our Spring config file, for connecting to mongo. Right now, we simply define the URL
<mongo:db-factory id="mongo_connection" client-uri="mongodb://server_1:27000,server_2:27000,server_3:27000/db_name?replicaSet=test" />
I’m now setting up authentication on the mongo server, which would change the connection string to mongodb://username:password@server_1:27000,server_2:27000,server_3:27000/db_name?replicaSet=test
. However, I can’t hardcode these into the XML; they will come from a different API on startup.
I know how to setup the URL in a seperate Java file:
public class MongoConstructor {
String username = secret_username;
String password = secret_password;
String db = "db_name"
String rs = "test"
//uri="mongodb://server_1:27000,server_2:27000,server_3:27000/db_name?replicaSet=test"
public String getMongoConstructor() {
return "mongodb://" + username + ":" + password + "@server_1:27000,server_2:27000,server_3:27000/" + db + "?replicaSet=" + rs;
}
}
Is there anyway for me to create that value before the bean is registered, and pass that value into the config file? If not, is there anyway for me to override the config in the xml file later on?
EDIT: Having done more research, I’ve discovered plaveholders for Spring, which seems to be what I’m looking for. However, I’m still struggling. So far, I’ve made the change in the XML file:
<beans>
<mongo:db-factory id="devMongoConnection"
client-uri="mongodb://{username}:{password}@server_1:27000,server_2:27000,server_3:27000/db_name?replicaSet=test" />
</beans>
Since I can’t use a properties file to store the credential information, I’ve made a Java file to initialize the username and password:
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class SecretImpl {
Secret secret = Internal_API_For_Secrets();
public SecretImpl(String username, String password) {
}
@Bean(name="username")
public String username() {
return secret.getUsername();
}
@Bean(name="password")
public String password() {
return secret.getUsername();
}
}
What I’m struggling with is getting these secrets into the xml file. All the documentation I’ve seen so far seems to assume that I would use either xml or Java, not a mix. They also seem to assume that the password can be placed in a properties files as plain text.
2
Answers
Probably the best way to go would be using SpEL expressions for accessing either system properties or system environment variables with your credentials configuration.
The approach is described in the Spring documentation.
For example, you can define system properties like this when running your program:
and then reference those properties in your XML configuration like this:
Or preferably, you can define the same information using environment variables. For example, in Linux or Unix based systems:
and use those variables like this:
I am not sure if it will work, because it highly depends on how you are obtaining the credentials, but you could define a bean corresponding to a slightly modified version of your
SecretImpl
class:in your XML file and reference the corresponding properties in your Mongo configuration, using SpEL again:
Finally, you could try providing a modified version of the
MongoDatabaseFactory
for taking into account the API for obtaining the credentials. It is unclear in your question the version of the Spring Data library for Mongo that you are using, but assuming the most recent, theMongoDatabaseFactory
abstraction is implemented inSimpleMongoClientDatabaseFactory
. The proposed solution will then consist of defining a class that, for example, extends that class providing the necessary artifacts for dealing with your API for obtaining the required credentials, something like (please, excuse the simplicity of the code):Your XML configuration could look similar to this (based for instance on this):
Actually it is not clear what
Secret secret = Internal_API_For_Secrets();
does.But you could register your own properties on application startup in
ConfigurableEnvironment
First option
You can achieve it the following way:
Implement your own
EnvironmentPostProcessor
:Register that post processor with
spring.factories
file. Create this file inMETA-INF
directory. By maven conventions it should bemain/java/resources/META-INF/spring.factories
There you specify the class name with package
So, during startup your property
mongo-url
will be registered inEnvironment
and will be also accessible with the placeholder.From Java code:
In xml:
Second option
Another option if you want to inject some bean that makes a call to the external API:
Declare an
ApplicationListener<ContextRefreshedEvent>
:After this you can use the placeholder
${mongo-url}
both in your Java configs and in XML configs, just like in the example above.