在Spring-boot中,为@Value注解添加从数据库读取properties支持

一般我们会把常用的属性放在工程的classpath文件夹中,以property,yaml或json的格式进行文件存储,便于Spring-boot在初始化时获取。

@Value则是Spring一个非常有用的注解,可以在初始化时很方便的对Bean的入参变量进行赋值,例如:

@Bean
    public BusinessClient businessClient (@Value("http://baseUrl/") String baseUrl) {
        Retrofit retrofit = new Retrofit.Builder()
                    .baseUrl(baseUrl)
                    .addConverterFactory(GsonConverterFactory.create())
                    .build();
        return retrofit.create(BusinessClient .class);

于是,初始化好的Business Client进行http请求时,默认的baseurl都是”http://baseUrl“。
实际上,@Value还支持一种特殊的写法:”${some.proptery.key}”,即将property的key值写在花括号中。例如,我有一个property为aerexu.basurl=http://baseUrl2,将上例中的@Value改写成@Value("${aerexu.basurl}"),baseUrl实际获取到的值是http://baseUrl2。 
这个特性是利用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);

原文地址:https://www.cnblogs.com/bevis-byf/p/11491475.html

时间: 2024-08-30 16:26:52

在Spring-boot中,为@Value注解添加从数据库读取properties支持的相关文章

spring boot中mybatis使用注解进行模糊查询

小白一枚,spring boot 2.0.5在使用mybatis进行注解模糊查询时遇到一些低级的错误,现记录下来错误示例:"select * from user where name like \""#{name}\""这个错误报Parameter index out of range (1 > number of parameters, which is 0): 经过百度查询其它的得到这条sql语句,虽然能查出来,但是是全部数据都查出来了"

Spring Boot 中使用 @Transactional 注解配置事务管理

事务管理是应用系统开发中必不可少的一部分.Spring 为事务管理提供了丰富的功能支持.Spring 事务管理分为编程式和声明式的两种方式.编程式事务指的是通过编码方式实现事务:声明式事务基于 AOP,将具体业务逻辑与事务处理解耦.声明式事务管理使业务代码逻辑不受污染, 因此在实际使用中声明式事务用的比较多.声明式事务有两种方式,一种是在配置文件(xml)中做相关的事务规则声明,另一种是基于 @Transactional 注解的方式.本文将着重介绍基于 @Transactional 注解的事务管

在Spring Boot中使用 @ConfigurationProperties 注解

使用mail做例子.配置放在mail.properties文件中.属性必须命名规范才能绑定成功. Spring Boot 使用一些松的规则来绑定属性到@ConfigurationProperties bean 并且支持分层结构(hierarchical structure).开始创建一个@ConfigurationProperties bean: @ConfigurationProperties(locations = "classpath:mail.properties", igno

spring boot中的jave注解学习

在spring中,不仅框架作者会使用java注解,开发者也常使用. 可以随手给个例子:在org.springframework.boot.autoconfigure.jdbc.DataSourceProperties中@ConfigurationProperties(prefix="spring.datasource"),这个注解的意思根据经验,就是使用注解读取了配置文件中以prefix为前缀的配置信息.自己可以想想其实现原理,而不必看源码.源码那么多,是看不完的,关键是自己理解,掌握

企业分布式微服务云SpringCloud SpringBoot mybatis (十四)Spring Boot中使用MyBatis注解配置详解

传参方式 下面通过几种不同传参方式来实现前文中实现的插入操作. 使用@Param 在之前的整合示例中我们已经使用了这种最简单的传参方式,如下: @Insert("INSERT INTO USER(NAME, AGE) VALUES(#{name}, #{age})") int insert(@Param("name") String name, @Param("age") Integer age); 这种方式很好理解,@Param中定义的name

传统的Servlet在spring boot中怎么实现的?

本文主要内容: 1:springboot一些介绍 2:传统的servlete项目在spring boot项目中怎么实现的?web.xml.url-patterns怎么设置? 3:有几种实现方式?分别是什么? 4:代码位置 spring boot 三大特性 组件自动装配:webMVC.webFlux.JDBC等 嵌入式Web容器:Tomcat.Jetty以及undertow 生产准备特性:指标.健康检查.外部化部署等 组件自动装配: 激活自动装配注解:@EnableAutoConfiguratio

Spring Boot中的注解

文章来源:http://www.tuicool.com/articles/bQnMra 在Spring Boot中几乎可以完全弃用xml配置文件,本文的主题是分析常用的注解. Spring最开始是为了解决EJB等大型企业框架对应用程序的侵入性,因此大量依靠配置文件来“非侵入式”得给POJO增加功能,然而,从Spring 3.x开始,Spring被外界最为诟病的一点就是配置繁多,号称“配置地狱”,各种xml文件,出了问题非常难排查.从Spring 4.x开始,Spring.io提供了三种方式编织B

3.Spring Boot中使用Swagger2构建强大的RESTful API文档

原文:http://www.jianshu.com/p/8033ef83a8ed 由于Spring Boot能够快速开发.便捷部署等特性,相信有很大一部分Spring Boot的用户会用来构建RESTful API.而我们构建RESTful API的目的通常都是由于多终端的原因,这些终端会共用很多底层业务逻辑,因此我们会抽象出这样一层来同时服务于多个移动端或者Web前端. 这样一来,我们的RESTful API就有可能要面对多个开发人员或多个开发团队:IOS开发.Android开发或是Web开发

Spring Boot中使用Swagger2生成RESTful API文档(转)

效果如下图所示: 添加Swagger2依赖 在pom.xml中加入Swagger2的依赖 <!-- https://mvnrepository.com/artifact/io.springfox/springfox-swagger2 --> <dependency> <groupId>io.springfox</groupId> <artifactId>springfox-swagger2</artifactId> <versi