【问题标题】:Spring Boot 1.5 validated ConfigurationPropertiesSpring Boot 1.5 验证的 ConfigurationProperties
【发布时间】:2017-04-18 14:17:47
【问题描述】:

跳到底部了解这个问题的动机和解决方案!

在从Spring Boot 1.4升级到1.5的过程中看了(来源:https://github.com/spring-projects/spring-boot/wiki/Spring-Boot-1.5-Release-Notes#upgrading-from-spring-boot-14

如果您有使用 JSR-303 约束注解的 @ConfigurationProperties 类,您现在应该另外使用 @Validated 对它们进行注解。现有验证当前将继续工作,但将记录警告。将来,没有@Validated 的类将根本不会被验证。

因此,我努力地将@Validated 添加到我的所有配置属性中。现在我有一个中断的特定用例,也就是不再加载属性(我先总结,然后添加代码)。

如果我使用application.properties 文件中定义的模板属性,然后尝试覆盖特定配置文件的值,则应用程序不会启动。

这里是一些重现的示例代码(相关文件):

build.gradle

buildscript {
    ext {
        springBootVersion = '1.5.1.RELEASE'
    }
    repositories {
        mavenCentral()
    }
    dependencies {
        classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
    }
}

apply plugin: 'java'
apply plugin: 'eclipse'
apply plugin: 'org.springframework.boot'

version = '0.0.1-SNAPSHOT'
sourceCompatibility = 1.8

repositories {
    mavenCentral()
}


dependencies {
    compile('org.springframework.boot:spring-boot-starter-web')
    testCompile('org.springframework.boot:spring-boot-starter-test')
}

application.properties : demo.prop=${profile.prop}

application-demo.propertiesprofile.prop=demo

DemoApplication.java

package package;

import javax.validation.constraints.NotNull;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;

@SpringBootApplication
public class DemoApplication {

    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }

    @org.springframework.web.bind.annotation.RestController
    public static class RestController {

        @Autowired
        private DemoProperties properties;

        @GetMapping
        public String get() {
            return properties.prop == null ? "null" : properties.prop;
        }
    }

    @Component
    @ConfigurationProperties(prefix = "demo")
//  @Validated
    public static class DemoProperties {

        @NotNull
        private String prop;

        public void setProp(String prop) {
            this.prop = prop;
        }

        public String getProp() {
            return prop;
        }
    }
}

就目前而言,我的应用程序在使用 -Dspring.profiles.active=demo 运行时会产生预期的结果

curl "http://localhost:8080"
demo

但是,取消注释 //@validated 并像以前一样运行应用程序会产生

curl "http://localhost:8080"
null

https://github.com/ThanksForAllTheFish/boot-props 上提供完整的应用程序(包括一个测试用例,显示在config/application.properties 中定义profile.prop@validated 一样失败,但在没有@validated 时成功)。

我猜这是 Spring Boot 中的一个错误,但可能我没有理解某些东西,所以首先 SoF(如 github 上的 Spring Boot 问题管理器中所暗示的)。

这个 github 问题似乎相关:https://github.com/spring-projects/spring-boot/issues/8173

【问题讨论】:

  • 我实际上让用例变得更加复杂。只需将 application.properties 和 demo.prop=prop 作为单行内容就足以看到相同的问题。我更新了 github 仓库
  • 您没有包含验证器,因此不会验证任何内容。像这样的覆盖属性也不起作用。它不是一个多通道过程,所有内容都被读取然后处理......所以只有将它指定为系统属性、环境属性或启动参数才会使其覆盖
  • @M.Deinum,不正确,正如我所写,如果我删除 @Validated,应用程序的行为与预期一样。我也很惊讶我不需要验证器,但是如果我清空我的 application.properties 文件,我会得到一个 BindException
  • (Caused by: org.springframework.validation.BindException: org.springframework.boot.bind.RelaxedDataBinder$RelaxedBeanPropertyBindingResult: 1 errors Field error in object 'demo' on field 'prop': rejected value [null]; codes [NotNull.demo.prop,NotNull.prop,NotNull.java.lang.String,NotNull]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [demo.prop,prop]; arguments []; default message [prop]]; default message [may not be null]) which imo 足以显示验证发生
  • 嗯 ...显然验证器是 web starter 的默认部分(认为它是可选的)。我仍然不明白您所描述的内容有什么问题(您没有指定个人资料并且属性是 null 这是正确的恕我直言,因为您没有另外指定。

标签: spring-boot


【解决方案1】:

当我找到了我的问题的解决方案时(不久前已经找到了,但在问题本身中添加了解释),我认为在这里复制我的发现可能更有帮助。

我的示例代码的问题是 @Validated 用代理包装了真实类,因此可以注入验证问题,因此 return properties.prop == null ? "null" : properties.prop; 实际上是在尝试访问代理的 prop 字段。更改为 getProp() 是解决方法。一经发现就很明显了。

关于生产代码:问题与https://github.com/spring-projects/spring-boot/issues/8173 相关,或者更准确地说与https://github.com/spring-cloud/spring-cloud-commons/issues/177 有关,因为我们使用的是spring-cloud。基本上,spring-cloudspring-boot 之间的 BeanPostProcessor 存在冲突(详细信息在 github 上的票证中),在 spring-cloudDalston.RELEASE 中已解决。只需更新我们项目中的依赖项也解决了生产中的问题。大量的挖掘和测试只需要更改我们代码库中的 7 个字符。

【讨论】:

    猜你喜欢
    • 2016-07-24
    • 1970-01-01
    • 1970-01-01
    • 2015-06-17
    • 2018-02-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多