Register ApplicationConversionService for context

Update `SpringApplication` to automatically register the shared
`ApplicationConversionService` instance with the `BeanFactory` and
`Environment`.

Closes gh-12148
This commit is contained in:
Phillip Webb 2018-09-11 14:21:56 -07:00
parent ab6bdc7ae2
commit 0c00508b3c
6 changed files with 74 additions and 7 deletions

View File

@ -45,6 +45,7 @@ import org.springframework.boot.Banner.Mode;
import org.springframework.boot.context.properties.bind.Bindable;
import org.springframework.boot.context.properties.bind.Binder;
import org.springframework.boot.context.properties.source.ConfigurationPropertySources;
import org.springframework.boot.convert.ApplicationConversionService;
import org.springframework.boot.web.reactive.context.StandardReactiveWebEnvironment;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextInitializer;
@ -214,6 +215,8 @@ public class SpringApplication {
private boolean addCommandLineProperties = true;
private boolean addConversionService = true;
private Banner banner;
private ResourceLoader resourceLoader;
@ -397,7 +400,6 @@ public class SpringApplication {
logStartupInfo(context.getParent() == null);
logStartupProfileInfo(context);
}
// Add boot specific singleton beans
ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
beanFactory.registerSingleton("springApplicationArguments", applicationArguments);
@ -503,6 +505,10 @@ public class SpringApplication {
*/
protected void configureEnvironment(ConfigurableEnvironment environment,
String[] args) {
if (this.addConversionService) {
environment.setConversionService(
ApplicationConversionService.getSharedInstance());
}
configurePropertySources(environment, args);
configureProfiles(environment, args);
}
@ -644,6 +650,10 @@ public class SpringApplication {
.setClassLoader(this.resourceLoader.getClassLoader());
}
}
if (this.addConversionService) {
context.getBeanFactory().setConversionService(
ApplicationConversionService.getSharedInstance());
}
}
/**
@ -1046,6 +1056,16 @@ public class SpringApplication {
this.addCommandLineProperties = addCommandLineProperties;
}
/**
* Sets if the {@link ApplicationConversionService} should be added to the application
* context's {@link Environment}.
* @param addConversionService if the application conversion service should be added
* @since 2.1.0
*/
public void setAddConversionService(boolean addConversionService) {
this.addConversionService = addConversionService;
}
/**
* Set default environment properties which will be used in addition to those in the
* existing {@link Environment}.

View File

@ -31,11 +31,13 @@ import org.springframework.beans.factory.support.BeanNameGenerator;
import org.springframework.boot.Banner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.WebApplicationType;
import org.springframework.boot.convert.ApplicationConversionService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextInitializer;
import org.springframework.context.ApplicationListener;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.Environment;
import org.springframework.core.io.ResourceLoader;
import org.springframework.util.StringUtils;
@ -370,6 +372,19 @@ public class SpringApplicationBuilder {
return this;
}
/**
* Flag to indicate if the {@link ApplicationConversionService} should be added to the
* application context's {@link Environment}.
* @param addConversionService if the conversion service should be added.
* @return the current builder
* @since 2.1.0
*/
public SpringApplicationBuilder setAddConversionService(
boolean addConversionService) {
this.application.setAddConversionService(addConversionService);
return this;
}
/**
* Default properties for the environment in the form {@code key=value} or
* {@code key:value}.

View File

@ -57,7 +57,7 @@ public class ApplicationConversionService extends FormattingConversionService {
* building it once needed.
* @return the shared {@code ConversionService} instance (never {@code null})
*/
public static ConversionService getSharedInstance() {
public static ApplicationConversionService getSharedInstance() {
ApplicationConversionService sharedInstance = ApplicationConversionService.sharedInstance;
if (sharedInstance == null) {
synchronized (ApplicationConversionService.class) {

View File

@ -56,6 +56,7 @@ import org.springframework.boot.context.event.ApplicationReadyEvent;
import org.springframework.boot.context.event.ApplicationStartedEvent;
import org.springframework.boot.context.event.ApplicationStartingEvent;
import org.springframework.boot.context.event.SpringApplicationEvent;
import org.springframework.boot.convert.ApplicationConversionService;
import org.springframework.boot.testsupport.rule.OutputCapture;
import org.springframework.boot.web.embedded.netty.NettyReactiveWebServerFactory;
import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;
@ -597,6 +598,28 @@ public class SpringApplicationTests {
matchingPropertySource(PropertySource.class, "commandLineArgs"));
}
@Test
public void contextUsesApplicationConversionService() {
SpringApplication application = new SpringApplication(ExampleConfig.class);
application.setWebApplicationType(WebApplicationType.NONE);
this.context = application.run();
assertThat(this.context.getBeanFactory().getConversionService())
.isInstanceOf(ApplicationConversionService.class);
assertThat(this.context.getEnvironment().getConversionService())
.isInstanceOf(ApplicationConversionService.class);
}
@Test
public void contextWhenHasAddConversionServiceFalseUsesRegularConversionService() {
SpringApplication application = new SpringApplication(ExampleConfig.class);
application.setWebApplicationType(WebApplicationType.NONE);
application.setAddConversionService(false);
this.context = application.run();
assertThat(this.context.getBeanFactory().getConversionService()).isNull();
assertThat(this.context.getEnvironment().getConversionService())
.isNotInstanceOf(ApplicationConversionService.class);
}
@Test
public void runCommandLineRunnersAndApplicationRunners() {
SpringApplication application = new SpringApplication(CommandLineRunConfig.class);

View File

@ -1,5 +1,5 @@
/*
* Copyright 2012-2013 the original author or authors.
* Copyright 2012-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -16,6 +16,8 @@
package sample.simple.service;
import java.time.Duration;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
@ -25,8 +27,15 @@ public class HelloWorldService {
@Value("${name:World}")
private String name;
@Value("${duration:10s}")
private Duration duration;
public String getHelloMessage() {
return "Hello " + this.name;
return "Hello " + this.name + " for " + this.duration.getSeconds() + " seconds";
}
public Duration getDuration() {
return this.duration;
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2012-2017 the original author or authors.
* Copyright 2012-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -62,9 +62,9 @@ public class SampleSimpleApplicationTests {
@Test
public void testCommandLineOverrides() throws Exception {
SampleSimpleApplication.main(new String[] { "--name=Gordon" });
SampleSimpleApplication.main(new String[] { "--name=Gordon", "--duration=1m" });
String output = this.outputCapture.toString();
assertThat(output).contains("Hello Gordon");
assertThat(output).contains("Hello Gordon for 60 seconds");
}
}