如何在Spring@Value注释中手动计算表达式?

如何在Spring@Value注释中手动计算表达式?,spring,Spring,我的SpringBoot应用程序有一堆@Value注释。当应用程序部署到我们的Kubernetes集群时,它最终使用一个属性文件,该文件通过两种不同的机制插入。当它最终实现时,如果开发人员犯了简单的错误,容器可能无法启动,原因很简单,因为他们没有正确设置所有属性。直到错误发生很久之后,才容易发现事情就是这样 请注意,几乎所有这些@Value注释都将使用“${}”语法,而不是“#{}”。主要关注的是从属性文件中读取特定属性,而不是Springbean属性 所以,我想写一个小的验证脚本(一个小Jav

我的SpringBoot应用程序有一堆@Value注释。当应用程序部署到我们的Kubernetes集群时,它最终使用一个属性文件,该文件通过两种不同的机制插入。当它最终实现时,如果开发人员犯了简单的错误,容器可能无法启动,原因很简单,因为他们没有正确设置所有属性。直到错误发生很久之后,才容易发现事情就是这样

请注意,几乎所有这些@Value注释都将使用“${}”语法,而不是“#{}”。主要关注的是从属性文件中读取特定属性,而不是Springbean属性

所以,我想写一个小的验证脚本(一个小Java类),它的功能如下:

        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;
                        }
                    }
                }
            }
        }
  • 获取生成的属性文件的路径
  • 将该属性文件加载到属性对象中
  • 在类路径中扫描所有类(使用基本包)以及这些类中的所有字段,以查找@Value注释
  • 对于找到的每个@Value注释,执行一些简单的验证并计算表达式
  • 如果验证或评估失败,请打印包含所有相关详细信息的错误消息
  • 此脚本将在“kubectl卷展栏”出现之前运行。如果我们在推出之前看到这些错误消息,我们将节省诊断这些问题的时间

    到目前为止,除了使用加载的属性文件和计算表达式之外,我已经能够实现所有功能。我知道Spring使用bean后处理器,但我不知道如何手动调用它

    你知道如何弥补这个缺失的环节吗

    更新

    我仍然没有答案

    我想答案可能会在Spring代码库中的BeanPostProcessor中找到,所以我克隆了Spring框架repo。我发现了两个潜在的变量,分别是“AutoWiredNotationBeanPostProcessor”、“BeanFactoryPostProcessor”、“CommonAnnotationBeanPostProcessor”和“BeanPostProcessor”,但我在这些变量中没有看到任何类似于在值注释中计算表达式的内容。我会尝试在注释的“value()”方法中设置断点,但当然不能在这样的方法中设置断点

    更新


    要清楚,这个表达式不是“Spring EL”表达式。这些引用bean属性(或加载的属性)并以“#{”开头。我正在使用只引用属性的表达式,这些属性以“${”开头。我确实尝试过用Spring EL解析表达式,但它只是认为那里什么都没有。

    我已经设法解决了这个问题。关键是“
    PropertyPlaceholderHelper.replacePlaceholders(字符串,属性)
    ”方法。使用该方法,我开发了如下内容:

            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;
                            }
                        }
                    }
                }
            }
    
    PropertyPlaceholderHelper PropertyPlaceholderHelper=
    新属性PlaceHolderHelper(“${”,“}”,“:”,true);
    ClassPathScanningCandidateComponentProvider scanner=新的ClassPathScanningCandidateComponentProvider(true);
    boolean FoundAtlastoneUnfoundProperty=false;
    用于(BeanDefinition bd:scanner.findCandidateComponents(basePackage)){
    字符串beanClassName=bd.getBeanClassName();
    Class clazz=Class.forName(beanClassName);
    for(字段:clazz.getDeclaredFields()){
    Value valueAnnotation=field.getAnnotation(Value.class);
    if(valueAnnotation!=null){
    Matcher Matcher=propertyRefPattern.Matcher(valueAnnotation.value());
    if(matcher.matches()){
    字符串结果值=propertyPlaceholderHelper.ReplacePlaceHolder(valueAnnotation.value(),properties);
    if(resultingValue.equals(valueAnnotation.value())){
    //这意味着找不到该属性。
    System.out.println(“错误:表达式\”“+valueAnnotation.value()+
    类\'+beanClassName中的字段\'+field.getName()+“\”上的\''+
    “\”引用未定义的属性。“);
    FoundAtlastoneUnfoundProperty=true;
    }
    }
    }
    }
    }