注解@value

在spring boot中,有些变量根据需求配置在application.properties或者application.yaml中,

在应用程序中使用@Value注解获取值。

eg:

在配置application.properteis配置一个键值对:

TestValue=This is my test!

程序中获取方式:

/** 使用@value注解,从配置文件读取值 */  
  
@Value("${TestValue}")  
private String testValueAnno;

将变量testValueAnno值初始化为This is my test!

******@PropertySource******

@PropertySource注解用于指定目录,指定编码读取properties文件,

如果将TestValue在配置文件中对应的值加上中文,通过@Value读取

到的值会出现中文乱码,因为spring boot加载application.properties

采用的是unicode编码形式,后台读取的变量值自然是乱码,解决办法

就是通过@PropertySource注解指定文件路径,通过utf-8的编码读取文件。

eg:

package com.lanhuigu.hello;  
  
import org.springframework.beans.factory.annotation.Value;  
import org.springframework.context.annotation.PropertySource;  
import org.springframework.web.bind.annotation.RequestMapping;  
import org.springframework.web.bind.annotation.ResponseBody;  
import org.springframework.web.bind.annotation.RestController;  
/** 
 * @RestController这个注解等价于spring mvc用法中的@Controller+@ResponseBody  
 */  
@RestController  
@PropertySource(value = {"classpath:application.properties"},encoding="utf-8")  
@RequestMapping(value="hello")  
public class HelloController {  
    /** 使用@value注解,从配置文件读取值 */  
    @Value("${TestValue}")  
    private String testValueAnno;  
      
    @RequestMapping(value="sayHello")  
    @ResponseBody  
    private String sayHello() {  
        System.out.println("测试:"+testValueAnno+"一意孤行!");  
        return "hello world!";  
    }  
} 
通过以上方式,能够解决spring boot通过@Value读取变量值出现中文乱码问题。


这个特性是利用Spring的bean PropertySourcesPlaceholder实现的,Spring boot已经在初始化时帮我们自动实例化了该bean。若是传统的Spring工程,则需要主动实例化,如下:
 @Bean
    public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {
        PropertySourcesPlaceholderConfigurer configurer = new PropertySourcesPlaceholderConfigurer();
        configurer.setPlaceholderPrefix(PlaceholderConfigurerSupport.DEFAULT_PLACEHOLDER_PREFIX);
        configurer.setPlaceholderSuffix(PlaceholderConfigurerSupport.DEFAULT_PLACEHOLDER_SUFFIX);
        configurer.setValueSeparator(PlaceholderConfigurerSupport.DEFAULT_VALUE_SEPARATOR);  
        return configurer;
    }
一般情况下,property存在工程中的文件就可以了,但带来的坏处是如果属性需要改变,必须重新发布工程。比如,对接上例中的url,可能会变为https,可能端口会变化。所以,这种类型的属性放在数据库中更合适。 
然而将属性存储在数据库中后, @Value 对应的值就无法正常解析了。因此,这里提供一种hack的方法,使得 @Value 可以正常解析。 
PropertySourcesPlaceholder在解析属性时,都是从ConfigurableEnvironment中进行寻找的。当ConfigurableEnvironment没有存在的属性时,${}写法的@Value就无法解析了。因此,需要通过特殊的处理,将存储在数据库中的属性注入到ConfigurableEnvironment中。本文定义了一个LoadFromDatabasePropertyConfig类实现该功能,其代码如下:


 @Configuration
    @Slf4j
    public class LoadFromDatabasePropertyConfig {
        @Autowired
        private ConfigurableEnvironment env;
        @Autowired
        private SysPropertyResourceMapper propertyResourceMapper;
        @PostConstruct
        public void initializeDatabasePropertySourceUsage() {
            MutablePropertySources propertySources = env.getPropertySources();
            try {
                Map<String, Object> propertyMap = propertyResourceMapper.selectAll().stream()
                        .collect(Collectors.toMap(SysPropertyResource::getPropertyName, SysPropertyResource::getPropertyValue));
                Properties properties = new Properties();
                properties.putAll(propertyMap);
                PropertiesPropertySource dbPropertySource = new PropertiesPropertySource("dbPropertySource", properties);
                Pattern p = Pattern.compile("^applicationConfig.*");
                String name = null;
                boolean flag = false;
                for (PropertySource<?> source : propertySources) {
                    if (p.matcher(source.getName()).matches()) {
                        name = source.getName();
                        flag = true;
                        log.info("Find propertySources ".concat(name));
                        break;
                    }
                }
                log.info("=========================================================================");
                if(flag) {
                    propertySources.addBefore(name, dbPropertySource);
                } else {
                    propertySources.addFirst(dbPropertySource);
                }
            } catch (Exception e) {
                log.error("Error during database properties setup", e);
                throw new RuntimeException(e);
            }
        }
    }

上述代码的具体思路是将数据库中的所有需要的属性读出,通过Properties类转换为Spring可用的PropertiesPropertySource,并取名为dbPropertySource。随后利用正则匹配,从已有的所有属性中找到名称以applicationConfig开头的属性(该属性即是所有配置在文件中的property所解析成的对象),并将dbPropertySource存储在其之前。这样当文件和数据库中同时存在key相等的属性时,会优先使用数据库中存储的value。 
需要注意的是,上述方案提供的属性解析,必须在数据库相关的bean都实例化完成后才可进行。且为了保证bean在实例化时,数据库属性已经被加入到ConfigurableEnvironment中去了,必须添加 @DependsOn 注解。上面的BusinessClient的实例化就需更新成:
 @Bean
    @DependsOn("loadFromDatabasePropertyConfig")
    public BusinessClient businessClient (@Value("${aerexu.basurl}") String baseUrl) {
        Retrofit retrofit = new Retrofit.Builder()
                    .baseUrl(baseUrl)
                    .addConverterFactory(GsonConverterFactory.create())
                    .build();
        return retrofit.create(BusinessClient .class);



  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值