文章目录
前言
当前环境,JDK1.8,IDEA2019.3,Maven3.6
Application.Properties
spring-configuration-metadata.json效果
可以看到根据前缀,idea自动给出了提示,并提供了一个默认值.
提示的来源则是jar包下的spring-configuration-metadata.json文件,支持的IDE会根据这个文件在输入时给予提示
spring-configuration-metadata.json生成
而spring-configuration-metadata.json文件的来源则分为两种
1.根据@ConfigurationProperties(prefix = "server", ignoreUnknownFields = true)注解提供生成
2.手动按格式编写json
1.通过解析 @ConfigurationProperties 注解配置
@ConfigurationProperties(prefix = "server", ignoreUnknownFields = true)
public class ServerProperties {
/**
* Server HTTP port.
*/
private Integer port;
2.通过按格式手写
{
"name": "spring.banner.image.bitdepth",
"type": "java.lang.Integer",
"description": "The bit depth to use for ANSI colors. Supported values are 4 (16 color) or 8 (256 color).",
"defaultValue": 4
},
{
"name": "spring.banner.image.height",
"type": "java.lang.Integer",
"description": "Height of the banner image in chars (default based on image height)."
},
1.赋值(默认值)
public abstract class AbstractConfigurableWebServerFactory implements ConfigurableWebServerFactory {
private int port = 8080;
2.赋值(默认值)
{
"name": "spring.banner.image.bitdepth",
"type": "java.lang.Integer",
"description": "The bit depth to use for ANSI colors. Supported values are 4 (16 color) or 8 (256 color).",
"defaultValue": 4
},
BitDepth.FOUR;
org.springframework.boot.SpringApplication#printBanner
private Banner printBanner(ConfigurableEnvironment environment) {
if (this.bannerMode == Banner.Mode.OFF) {
return null;
}
ResourceLoader resourceLoader = (this.resourceLoader != null) ? this.resourceLoader
: new DefaultResourceLoader(getClassLoader());
//打印类
SpringApplicationBannerPrinter bannerPrinter = new SpringApplicationBannerPrinter(resourceLoader, this.banner);
if (this.bannerMode == Mode.LOG) {
return bannerPrinter.print(environment, this.mainApplicationClass, logger);
}
return bannerPrinter.print(environment, this.mainApplicationClass, System.out);
}
class SpringApplicationBannerPrinter {
static final String BANNER_LOCATION_PROPERTY = "spring.banner.location";
static final String BANNER_IMAGE_LOCATION_PROPERTY = "spring.banner.image.location";
...
private BitDepth getBitDepthProperty(Environment environment) {
Integer bitDepth = getProperty(environment, "bitdepth", Integer.class, null);
//BitDepth.FOUR;
return (bitDepth != null) ? BitDepth.of(bitDepth) : BitDepth.FOUR;
}
可以看到 spring-configuration-metadata.json 作用只是给予提示,值的处理还是要自己做.
ConfigurationProperties
属性安全的注入变量,对于能转型的会帮忙转型,配置之后可以通过前缀在默认的application.properties文件中定义值.
@ConfigurationProperties(prefix = "user")
public class User {
private String password;
private String username;
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
}
HelloController
@RestController
@EnableConfigurationProperties(User.class)
public class HelloController {
User user;
public HelloController(User user) {
this.user = user;
}
@GetMapping(value = "/hello")
public User hello() {
return user;
}
}
除了通过 @EnableConfigurationProperties激活 @ConfigurationProperties,还可以直接在 @ConfigurationProperties注解的类上再加一个 @component,总之只要确保会被注册为bean,spring就会根据配置的注解信息自动注值
Spring处理
/**
* {@link BeanPostProcessor} to bind {@link PropertySources} to beans annotated with
* {@link ConfigurationProperties @ConfigurationProperties}.
*
* @author Dave Syer
* @author Phillip Webb
* @author Christian Dupuis
* @author Stephane Nicoll
* @author Madhura Bhave
* @since 1.0.0
*/
public class ConfigurationPropertiesBindingPostProcessor
implements BeanPostProcessor, PriorityOrdered, ApplicationContextAware, InitializingBean {
application.properties
spring.main.banner-mode=off
user.password=1
user.username=username
注意一定要有get,set方法和默认的构造方法,不然是无法注入值的.这是一种遵守Java语法的注值方式,没有通过反射强制赋值
@ConfigurationProperties(prefix = "user")
public class User {
private String password;
private String username;
public User(String password, String username) {
this.password = password;
this.username = username;
}
}
报错
Error starting ApplicationContext. To display the conditions report re-run your application with 'debug' enabled.
2020-12-01 00:48:33.961 ERROR 16480 --- [ main] o.s.b.d.LoggingFailureAnalysisReporter :
***************************
APPLICATION FAILED TO START
***************************
Description:
Parameter 0 of constructor in com.example.note.User required a bean of type 'java.lang.String' that could not be found.
Action:
Consider defining a bean of type 'java.lang.String' in your configuration.
通过这个可以看到是根据propertysource注值的,所以也可以这样:
@ConfigurationProperties(prefix = "user")
public class User {
private String password;
private String username;
public String getPassword() {
return password;
...
}
@RestController
@EnableConfigurationProperties(User.class)
public class HelloController {
User user;
...
}
@SpringBootApplication
@PropertySource("classpath:test.properties")
public class NoteApplication {
public static void main(String[] args) {
SpringApplicationBuilder builder = new SpringApplicationBuilder(NoteApplication.class);
builder.build(args).run();
}
}
注意,如果通过 @EnableConfigurationProperties(User.class),注入, @PropertySource(“classpath:test.properties”) 注解就一定要在启动类上,因为启动类上配置会默认一开始就加载解析,如果和User.class放在一起,registerBeanDefinitions不会处理扩展配置@PropertySource(“classpath:test.properties”)
@Import(EnableConfigurationPropertiesRegistrar.class)
public @interface EnableConfigurationProperties {
...
}
class EnableConfigurationPropertiesRegistrar implements ImportBeanDefinitionRegistrar {
@Override
public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
registerInfrastructureBeans(registry);
ConfigurationPropertiesBeanRegistrar beanRegistrar = new ConfigurationPropertiesBeanRegistrar(registry);
getTypes(metadata).forEach(beanRegistrar::register);
}
但是如果在User.class上加 @Component ,就可以直接添加 **@PropertySource(“classpath:test.properties”)**了,因为这样就会处理注解上面的外部化配置了,同时 **@EnableConfigurationProperties(User.class)**也可以删除了,虽然不影响,但是功能重复了
@ConfigurationProperties(prefix = "user")
@Component
@PropertySource("classpath:test.properties")
public class User {
private String password;
private String username;
public String getPassword() {
}
....
}
@RestController
public class HelloController {
User user;
public HelloController(User user) {
this.user = user;
}
...
}
@SpringBootApplication
public class NoteApplication {
public static void main(String[] args) {
SpringApplicationBuilder builder = new SpringApplicationBuilder(NoteApplication.class);
builder.build(args).run();
}
}