我的SpringBoot应用程序具有一堆@Value注释。将应用程序部署到我们的Kubernetes集群时,最终使用的是通过两个不同机制插入的属性文件。当它最终到达那里时,如果开发人员犯了简单的错误,则容器可能无法启动,这仅仅是因为他们没有正确设置所有属性。直到犯错之后,才容易发现这是发生的事情。
请注意,实际上所有这些@Value批注将使用“ $ {}”语法,而不是“#{}”。主要关注的是从属性文件中读取特定属性,而不是从Spring bean属性中读取。
所以,我想写的是一个小的验证脚本(一个小的Java类),它执行以下操作:
此脚本将在“ kubectl推广”发生之前运行。如果在推出之前看到这些错误消息,我们将节省诊断这些问题的时间。
到目前为止,我已经能够完成所有工作,除了对已加载的属性文件进行某些操作并评估表达式。我知道Spring使用的是bean后处理器,但是我不知道如何手动调用它。
有什么主意如何实现缺失的链接吗?
更新:
我仍然没有答案。
我当时想也许答案会在Spring代码库的BeanPostProcessor中找到,所以我克隆了spring-framework存储库。我发现了几个潜在的可能,分别是“ AutowiredAnnotationBeanPostProcessor”,“ BeanFactoryPostProcessor”,“ CommonAnnotationBeanPostProcessor”和“ BeanPostProcessor”,但是在这些值中我什么都没看到,就像在Value注释中评估表达式一样。我本来可以在注释的“ value()”方法中设置断点,但是当然不能在这样的方法中设置断点。
更新:
要清楚,该表达式不是“ Spring EL”表达式。这些引用bean属性(或已加载的属性)并以“#{”开头。我正在使用仅引用以“ $ {”开头的属性的表达式。我确实尝试使用Spring EL解析该表达式,但它只是认为那里什么也没有。
答案 0 :(得分:0)
我设法弄清楚了。关键是“ PropertyPlaceholderHelper.replacePlaceholders(String, Properties)
”方法。使用它,我开发出了类似这样的东西:
PropertyPlaceholderHelper propertyPlaceholderHelper =
new PropertyPlaceholderHelper("${", "}", ":", true);
ClassPathScanningCandidateComponentProvider scanner = new ClassPathScanningCandidateComponentProvider(true);
boolean foundAtLeastOneUnfoundProperty = false;
for (BeanDefinition bd : scanner.findCandidateComponents(basePackage)) {
String beanClassName = bd.getBeanClassName();
Class<?> clazz = Class.forName(beanClassName);
for (Field field : clazz.getDeclaredFields()) {
Value valueAnnotation = field.getAnnotation(Value.class);
if (valueAnnotation != null) {
Matcher matcher = propertyRefPattern.matcher(valueAnnotation.value());
if (matcher.matches()) {
String resultingValue = propertyPlaceholderHelper.replacePlaceholders(valueAnnotation.value(), properties);
if (resultingValue.equals(valueAnnotation.value())) {
// This means that the property was not found.
System.out.println("ERROR: Expression \"" + valueAnnotation.value() +
"\" on field \"" + field.getName() + "\" in class \"" + beanClassName +
"\" references a property which is not defined.");
foundAtLeastOneUnfoundProperty = true;
}
}
}
}
}