spring@value取不到值的几种情况
一,spring组件重写构造方法,在构造方法中引用@value为null
由于spring实例化顺序为先执行构造方法,再注入成员变量,所以序为先执行构造方法,再注入成员变量,所以ing实例化顺取值为null
解决办法为:再写一个常量类,在常量类中引用@value,再在构造方法中引用常量类的变量即可。
二,调用spring组件时使用new对象,而不是@Autowired
三,使用final或static修饰成员变量
四,spring mvc中引用@value为null
spring mvc是spring的子容器,需要在两个配置文件中都导入配置文件
<context:property-placeholder location="classpath:jdbc.properties" ignore-unresolvable="true"/>
http://blog.51cto.com/jtech/2114686
springboot @ConfigurationProperties @EnableConfigurationProperties 自动配置
通过redis自动配置过程看这两个注解的联合使用,达到自动配置
springboot项目,maven
application.properties
配置redis
...
spring.redis.port=7379
...
需要获取配置的类,比如@Configuration注解的配置类,需要获取redis配置的其他类,redisProperties.getHost() 就可以取到配置
import org.springframework.boot.autoconfigure.data.redis.RedisProperties @EnableConfigurationProperties(RedisProperties.class) class JedisMy{ @Autowired private RedisProperties redisProperties }
获取使用内置的Environment获取配置,需要指定配置的key,上面的自动配置,key就是类的属性,redis的配置都是RedisProperties的属性
import org.springframework.core.env.Environment class DDD{ @Autowired private Environment env; public void dd(){ env.getProperty("spring.redis.port"); } }
关与 @EnableConfigurationProperties 注解
@EnableConfigurationProperties
测试发现 @ConfigurationProperties 与 @EnableConfigurationProperties 关系特别大。
@EnableConfigurationProperties 文档中解释:
当@EnableConfigurationProperties注解应用到你的@Configuration时, 任何被@ConfigurationProperties注解的beans将自动被Environment属性配置。 这种风格的配置特别适合与SpringApplication的外部YAML配置进行配合使用。
测试发现:
1.使用 @EnableConfigurationProperties 进行注册
@ConfigurationProperties(prefix = "service.properties") public class HelloServiceProperties { private static final String SERVICE_NAME = "test-service"; private String msg = SERVICE_NAME; set/get } @Configuration @EnableConfigurationProperties(HelloServiceProperties.class) @ConditionalOnClass(HelloService.class) @ConditionalOnProperty(prefix = "hello", value = "enable", matchIfMissing = true) public class HelloServiceAutoConfiguration { } @RestController public class ConfigurationPropertiesController { @Autowired private HelloServiceProperties helloServiceProperties; @RequestMapping("/getObjectProperties") public Object getObjectProperties () { System.out.println(helloServiceProperties.getMsg()); return myConfigTest.getProperties(); } }
自动配置设置
service.properties.name=my-test-name
service.properties.ip=192.168.1.1
service.user=kayle
service.port=8080
一切正常,但是 HelloServiceAutoConfiguration 头部不使用 @EnableConfigurationProperties,测访问报错。
2.不使用 @EnableConfigurationProperties 进行注册,使用 @Component 注册
@ConfigurationProperties(prefix = "service.properties") @Component public class HelloServiceProperties { private static final String SERVICE_NAME = "test-service"; private String msg = SERVICE_NAME; public String getMsg() { return msg; } public void setMsg(String msg) { this.msg = msg; } }
Controller 不变,一切正常,如果注释掉 @Component 测启动报错。
由此证明,两种方式都是将被 @ConfigurationProperties 修饰的类,加载到 Spring Env 中。
Spring @Value 设置默认值
1. 概述
在 Spring 组件中使用 @Value 注解的方式,很方便的读取 properties 文件的配置值。
2.使用场景
声明的变量中使用。
public static class FieldValueTestBean { @Value("#{ systemProperties['user.region'] }") private String defaultLocale; }
setter 方法中
public static class PropertyValueTestBean { private String defaultLocale; @Value("#{ systemProperties['user.region'] }") public void setDefaultLocale(String defaultLocale) { this.defaultLocale = defaultLocale; } }
方法中
public class SimpleMovieLister { private MovieFinder movieFinder; private String defaultLocale; @Autowired public void configure(MovieFinder movieFinder, @Value("#{ systemProperties['user.region'] }") String defaultLocale) { this.movieFinder = movieFinder; this.defaultLocale = defaultLocale; } // ... }
构造方法
public class MovieRecommender { private String defaultLocale; private CustomerPreferenceDao customerPreferenceDao; @Autowired public MovieRecommender(CustomerPreferenceDao customerPreferenceDao, @Value("#{systemProperties['user.country']}") String defaultLocale) { this.customerPreferenceDao = customerPreferenceDao; this.defaultLocale = defaultLocale; } // ... }
3. 字符串
字符串类型的属性设置默认值
@Value("${some.key:my default value}")
private String stringWithDefaultValue;
some.key 没有设置值,stringWithDefaultValue 变量值将会被设置成 my default value 。
如果默认值设为空,也将会被设置成默认值。
@Value("${some.key:}")
private String stringWithBlankDefaultValue;

4. 基本类型
基本类型设置默认值。
@Value("${some.key:true}")
private boolean booleanWithDefaultValue;
@Value("${some.key:42}")
private int intWithDefaultValue;
包装类型设置默认值。
@Value("${some.key:true}")
private Boolean booleanWithDefaultValue;
@Value("${some.key:42}")
private Integer intWithDefaultValue;
5. 数组
数组的默认值可以使用逗号分割。
@Value("${some.key:one,two,three}")
private String[] stringArrayWithDefaults;
@Value("${some.key:1,2,3}")
private int[] intArrayWithDefaults;


6. SpEL
使用 Spring Expression Language (SpEL) 设置默认值。
下面的代码标示在systemProperties属性文件中,如果没有设置 some.key 的值,my default system property value 会被设置成默认值。
@Value("#{systemProperties['some.key'] ?: 'my default system property value'}")
private String spelWithDefaultValue;
7.结语
上面讲解使用 Spring @Value 为属性设置默认值。在项目中,提供合理的默认值,在大多情况下不用任何配置,就能直接使用。达到零配置的效果,降低被人使用的门槛。简化新Spring应用的搭建、开发、部署过程。
8.参考链接
Using Spring @Value with Defaults
Annotation-based configuration
https://blog.csdn.net/vcfriend/article/details/79700048
import org.apache.commons.io.IOUtils; import org.hamcrest.Matchers; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.core.io.Resource; import org.springframework.test.context.junit4.SpringRunner; import java.io.IOException; import java.util.List; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.arrayContaining; import static org.hamcrest.Matchers.arrayWithSize; import static org.hamcrest.Matchers.emptyArray; import static org.hamcrest.Matchers.is; import static org.hamcrest.core.IsNull.notNullValue; /** * Created by tangcheng on 10/15/2017. */ @RunWith(SpringRunner.class) @SpringBootTest public class InjectTest { @Value("classpath:sourceData.txt") private Resource resource; @Value("${list.items:1,2,3}") private String[] items;
@Value("${list.items:1,2,3}")
private List<String> itemList;
@Value("${list.items:1,2,3}") private Long[] longItems; @Value("${list.items:}") private String[] itemsWithDefaultBlankValue; //@Value("${list.items}") private String[] itemsWithoutDefault; @Value("${str.value:}") private String strWithDefault; @Test public void injectFileTest() throws IOException { assertThat(resource, notNullValue()); String canonicalPath = resource.getFile().getCanonicalPath(); System.out.println(canonicalPath); List<String> list = IOUtils.readLines(resource.getInputStream(), "utf-8"); assertThat(list, Matchers.hasItems("123", "456")); for (String s : list) { System.out.println(s); } } /** * 使用英文逗点分隔的字符串会被按 英文逗点 进行分隔成 一个数组 */ @Test public void valueAnnotation_Given_String_Separate_With_Comma_Then_Return_Array() { assertThat(items, notNullValue()); assertThat(items, arrayWithSize(3)); for (String item : items) { System.out.println(item); } assertThat(items, arrayWithSize(3)); } /** * 使用:后,没有给默认值,则只会初始化数组。里面没有东西。 * 即仅仅 不为null */ @Test public void valueAnnotation_Given_Default_With_StringNum_Then_Return_Long_Type_Array() { assertThat(longItems, notNullValue()); assertThat(longItems.length, is(3)); assertThat(longItems, arrayContaining((long) 1, (long) 2, (long) 3)); } /** * 使用:后,没有给默认值,则只会初始化数组。里面没有东西。 * 即仅仅 不为null */ @Test public void valueAnnotation_Given_Default_Is_Nothing_Then_Return_Empty_Array() { assertThat(itemsWithDefaultBlankValue, notNullValue()); assertThat(itemsWithDefaultBlankValue, emptyArray()); assertThat(itemsWithDefaultBlankValue.length, is(0)); } /** * 使用 : 后,会有默认值 空字符串 */ @Test public void valueAnnotation_String() { assertThat(strWithDefault, is("")); assertThat(strWithDefault, Matchers.notNullValue()); System.out.println("strWithDefault:" + strWithDefault + ";"); } }

浙公网安备 33010602011771号