Java SpringBootServletilizer和@ConfigurationProperties在.war部署上不使用根属性

Java SpringBootServletilizer和@ConfigurationProperties在.war部署上不使用根属性,java,spring,spring-boot,Java,Spring,Spring Boot,我正在使用SpringBoot2.0.0.RC1构建REST服务。为了提供jar执行和.war部署,我扩展了SpringBootServletInitializer,如下所示: @Configuration @SpringBootApplication @EnableWebFlux @EnableConfigurationProperties({ RbsConfiguration.class, JwtConfiguration.class }) public class RbsApplicat

我正在使用SpringBoot2.0.0.RC1构建REST服务。为了提供jar执行和.war部署,我扩展了
SpringBootServletInitializer
,如下所示:

@Configuration
@SpringBootApplication
@EnableWebFlux
@EnableConfigurationProperties({ RbsConfiguration.class, 
JwtConfiguration.class })
public class RbsApplication extends SpringBootServletInitializer 
implements WebFluxConfigurer {

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

    ...
}
@ConfigurationProperties
@Validated
public class RbsConfiguration {

    private Map<String, String> users;

    @NotEmpty
    public Map<String, String> getUsers() {
        return users;
    }

    public void setUsers(Map<String, String> users) {
        this.users = users;
    }
}
我还使用
@ConfigurationProperties
将我的
应用程序.yml
配置绑定到如下bean:

@Configuration
@SpringBootApplication
@EnableWebFlux
@EnableConfigurationProperties({ RbsConfiguration.class, 
JwtConfiguration.class })
public class RbsApplication extends SpringBootServletInitializer 
implements WebFluxConfigurer {

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

    ...
}
@ConfigurationProperties
@Validated
public class RbsConfiguration {

    private Map<String, String> users;

    @NotEmpty
    public Map<String, String> getUsers() {
        return users;
    }

    public void setUsers(Map<String, String> users) {
        this.users = users;
    }
}
当我使用
java-jar
启动应用程序时,一切正常,我可以通过
RbsConfiguration
访问用户。但如果我将其作为.war部署到Tomcat,则会出现以下异常:

***************************
APPLICATION FAILED TO START
***************************

Description:

Failed to bind properties under '' to foo.bar.RbsConfiguration:

    Reason: PropertyName must not be empty

Action:

Update your application's configuration

...

Caused by: org.springframework.boot.context.properties.bind.BindException: Failed to bind properties under '' to foo.bar.RbsConfiguration
    at org.springframework.boot.context.properties.bind.Binder.handleBindError(Binder.java:227)
    at org.springframework.boot.context.properties.bind.Binder.bind(Binder.java:203)
    at org.springframework.boot.context.properties.bind.Binder.bind(Binder.java:187)
    at org.springframework.boot.context.properties.bind.Binder.bind(Binder.java:169)
    at org.springframework.boot.context.properties.ConfigurationPropertiesBinder.bind(ConfigurationPropertiesBinder.java:79)
    at org.springframework.boot.context.properties.ConfigurationPropertiesBindingPostProcessor.postProcessBeforeInitialization(ConfigurationPropertiesBindingPostProcessor.java:167)
    ... 100 more
Caused by: java.lang.IllegalArgumentException: PropertyName must not be empty
    at org.springframework.util.Assert.hasLength(Assert.java:233)
    at org.springframework.boot.origin.PropertySourceOrigin.<init>(PropertySourceOrigin.java:41)
    at org.springframework.boot.origin.PropertySourceOrigin.get(PropertySourceOrigin.java:79)
    at org.springframework.boot.context.properties.source.SpringConfigurationPropertySource.find(SpringConfigurationPropertySource.java:121)
    at org.springframework.boot.context.properties.source.SpringConfigurationPropertySource.find(SpringConfigurationPropertySource.java:104)
    at org.springframework.boot.context.properties.source.SpringConfigurationPropertySource.getConfigurationProperty(SpringConfigurationPropertySource.java:86)
    at org.springframework.boot.context.properties.bind.Binder.lambda$findProperty$3(Binder.java:294)
    at java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:193)
    at java.util.Spliterators$IteratorSpliterator.tryAdvance(Spliterators.java:1812)
    at java.util.stream.ReferencePipeline.forEachWithCancel(ReferencePipeline.java:126)
    at java.util.stream.AbstractPipeline.copyIntoWithCancel(AbstractPipeline.java:498)
    at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:485)
    at java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:471)
    at java.util.stream.FindOps$FindOp.evaluateSequential(FindOps.java:152)
    at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
    at java.util.stream.ReferencePipeline.findFirst(ReferencePipeline.java:464)
    at org.springframework.boot.context.properties.bind.Binder.findProperty(Binder.java:295)
    at org.springframework.boot.context.properties.bind.Binder.bindObject(Binder.java:239)
    at org.springframework.boot.context.properties.bind.Binder.bind(Binder.java:198)
    ... 104 more
***************************
应用程序无法启动
***************************
说明:
无法将“”下的属性绑定到foo.bar.rbs配置:
原因:PropertyName不能为空
行动:
更新应用程序的配置
...
原因:org.springframework.boot.context.properties.bind.BindException:无法将“”下的属性绑定到foo.bar.RbsConfiguration
位于org.springframework.boot.context.properties.bind.Binder.handleBindError(Binder.java:227)
位于org.springframework.boot.context.properties.bind.Binder.bind(Binder.java:203)
位于org.springframework.boot.context.properties.bind.Binder.bind(Binder.java:187)
位于org.springframework.boot.context.properties.bind.Binder.bind(Binder.java:169)
位于org.springframework.boot.context.properties.ConfigurationPropertiesBinder.bind(ConfigurationPropertiesBinder.java:79)
位于org.springframework.boot.context.properties.ConfigurationPropertiesBindingPostProcessor.postProcessBeforeInitialization(ConfigurationPropertiesBindingPostProcessor.java:167)
... 100多
原因:java.lang.IllegalArgumentException:PropertyName不能为空
位于org.springframework.util.Assert.hasLength(Assert.java:233)
位于org.springframework.boot.origin.PropertySourceOrigin.(PropertySourceOrigin.java:41)
位于org.springframework.boot.origin.PropertySourceOrigin.get(PropertySourceOrigin.java:79)
位于org.springframework.boot.context.properties.source.SpringConfigurationPropertySource.find(SpringConfigurationPropertySource.java:121)
位于org.springframework.boot.context.properties.source.SpringConfigurationPropertySource.find(SpringConfigurationPropertySource.java:104)
位于org.springframework.boot.context.properties.source.SpringConfigurationPropertySource.getConfigurationProperty(SpringConfigurationPropertySource.java:86)
位于org.springframework.boot.context.properties.bind.Binder.lambda$findProperty$3(Binder.java:294)
位于java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:193)
位于java.util.Spliterators$IteratorSpliterator.tryAdvance(Spliterators.java:1812)
位于java.util.stream.ReferencePipeline.forEachWithCancel(ReferencePipeline.java:126)
位于java.util.stream.AbstractPipeline.copyIntoWithCancel(AbstractPipeline.java:498)
位于java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:485)
位于java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:471)
位于java.util.stream.FindOps$FindOp.evaluateSequential(FindOps.java:152)
位于java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
位于java.util.stream.ReferencePipeline.findFirst(ReferencePipeline.java:464)
位于org.springframework.boot.context.properties.bind.Binder.findProperty(Binder.java:295)
位于org.springframework.boot.context.properties.bind.Binder.bindObject(Binder.java:239)
位于org.springframework.boot.context.properties.bind.Binder.bind(Binder.java:198)
... 104多
所以我想知道这里有什么不同。当它作为.war启动时,它似乎需要一个前缀,当直接通过Spring Boot启动时,它可以不固定。除了
RbsConfiguration
之外,我还有更多的配置类(例如
JwtConfiguration
),它们使用前缀,似乎可以与.war部署配合使用


有什么提示我为什么会看到这种行为吗?

您需要在
@ConfigurationProperties
定义中提供前缀。否则,你希望事情如何运作?所有内容都应该映射到您的配置类,包括
spring.*
namespace


我想您可能会看到这些部署之间的差异可能与启动应用程序时环境中存在的值有关。

扩展
SpringBootServletInitializer
最终对我来说不起作用。它没有正确地绑定根属性(我认为它甚至没有加载
application.yml
),它不知怎么地忽略了我的Spring安全设置,并提出了自己的默认设置

对我来说,有效的方法是放弃
RbsApplication
中的
extends
,只需自己提供一个Webflux初始化器,手动设置SpringBoot应用程序,这在很大程度上是受
SpringBootServletilizer
的启发

public class WebfluxInitializer extends AbstractReactiveWebInitializer {

    private ServletContext servletContext;

    @Override
    public void onStartup(ServletContext servletContext) throws ServletException {
        this.servletContext = servletContext;
        super.onStartup(servletContext);
    }

    @Override
    protected ApplicationContext createApplicationContext() {

        SpringApplicationBuilder builder = new SpringApplicationBuilder();

        StandardServletEnvironment environment = new StandardServletEnvironment();
        environment.initPropertySources(servletContext, null);

        builder.environment(environment);
        builder.sources(getConfigClasses());
        builder.web(WebApplicationType.NONE);
        builder.main(RbsApplication.class);

        return builder.build().run();
    }

    @Override
    protected Class<?>[] getConfigClasses() {
        return new Class[] { RbsApplication.class };
    }
}
公共类WebfluxInitializer扩展了AbstractReactiveWebInitializer{
私有ServletContext ServletContext;
@凌驾
启动时公共void(ServletContext ServletContext)引发ServletException{
this.servletContext=servletContext;
super.onStartup(servletContext);
}
@凌驾
受保护的ApplicationContext createApplicationContext(){
SpringApplicationBuilder=新的SpringApplicationBuilder();
StandardServleteEnvironment环境=新的StandardServleteEnvironment();
initPropertySources(servletContext,null);
建筑商.环境(环境);
sources(getConfigClasses());
web(WebApplicationType.NONE);
builder.main(RbsApplication.class);
返回builder.build().run();
}
@凌驾
受保护类[]getConfigClasses(){
返回新类[]{RbsApplication.Class};
}
}
使用此Webflux,安全性将按定义工作,并将根属性绑定到