问题
I have the application property APP_ID
that should be randomly generated (UUID) and that should have the same value for the entire Spring Boot application.
What I did was the following: I defined in the application.properties
file the APP_ID=${random.uuid}
.
The UUID gets created successfully, however for every property reference @Value("${APP_ID}")
I will get a different UUID.
Example: In class Foo
I want to use the appId
:
@Value("${APP_ID}")
private String appId;
In class Bar
I want to use the appId
, too:
@Value("${APP_ID}")
private String appId;
However, the appId
in Bar
is always different to the appId
in Foo
.
I have read in this thread that this behavior is the correct one.
What would be proper implementation to always get the same APP_ID
?
回答1:
One way to do it (as suggested by wilkinsoa in this thread) is to "bind a single random value into a @ConfigurationProperties
annotated bean and then use that bean to configure anything else that needed the same value."
This results in an application.properties
file:
app.id=${random.uuid}
The configuration properties file is:
@Configuration
@ConfigurationProperties(prefix = "app")
public class AppProperties {
private String id;
public String getId() {
return this.id;
}
public void setId(String id) {
this.id = id;
}
}
The class using the id:
@Component
public class DoStuff {
private AppProperties appProperties;
@Autowired
public DoStuff(AppProperties appProperties) {
this.appProperties = appProperties;
}
}
回答2:
You can generate random value as constant for your test.
package com.yourdomain.config;
import org.apache.commons.lang3.RandomUtils;
public class TestConfig {
public static final long RANDOM_LONG = RandomUtils.nextLong();
}
and then reference it like:
integration.test.random.seed=#{T(com.yourdomain.config.TestConfig).RANDOM_LONG}
rabbitmq.queue=queueName_${integration.test.random.seed}
回答3:
I think I've found the most simple but harder to document solution.
The issue with using a class to store the value and autowiring is that you still lose the stateful-ness of the environmental variable. If someone makes a mistake and tries to reference it again you could easily run into some errors.
@Configuration
public class FileSharingConfiguration {
private final static UUID app_id = UUID.randomUUID();
@PostConstruct
private void init() {
System.setProperty("app.instance-id", app_id.toString());
}
}
I wouldn't rely on #{random.uuid} because it makes references stateless, so I generate my own in the program. Then in a post construction sequence you push that value into environmental variables.
This solution is better when you are forced to reference the same property multiple times (e.g: Thymeleaf templates) and they are read at runtime.
A slight disadvantage is that the property won't show up in the config files, unless you initialize them with a default value. So you have to find other ways of documenting it.
The major disadvantage still is that there's no guarantee that @Value("...") will initialize after you've set the environmental property. The Autowiring solution overcomes this problem by forcing the initialization order. But with this one you only need
@Autowired
private AppConfig config;
to cause them to be initialized after, you could also use @DependsOn and you don't need to use a getter.
In my opinion there needs to be a better way to do this, random properties being stateless makes them impractical for anything other than testing. But they certainly don't want doing it considering they have created so many workarounds for assigning and reading back random port numbers.
来源:https://stackoverflow.com/questions/49274032/spring-boot-configuration-how-to-return-always-same-random-value-when-reference