SpringBoot自定义加载yml实现方式,附源码解读

目录
  • 自定义加载yml,附源码解读
    • 解决方法
    • 源码解读
  • 如何引入多个yml方法
    • 方案一:无前缀,使用@Value注解
    • 方案二:有前缀,无需@Value注解

自定义加载yml,附源码解读

昨天在对公司的微服务配置文件标准化的过程中,发现将原来的properties文件转为yml文件之后,微服务module中标记有@Configuration的配置类都不能正常工作了,究其原因,是由于@PropertySource属性默认只用于标记并告诉spring boot加载properties类型的文件

spring boot 2.0.0.RELEASE版的文档解释如下:

24.6.4 YAML Shortcomings

YAML files cannot be loaded by using the @PropertySource annotation. So, in the case that you need to load values that way, you need to use a properties file.

这段话的意思是说:

24.6.4 YAML 缺点

YAML 文件不能用 @PropertySource 注解来标记加载。因此,在需要加载值的场景,你需要使用属性文件。

解决方法

解决这个问题并不难,我们只需要自定义一个yaml文件加载类,并在@PropertySource注解的factory属性中声明就可以。scala版实现代码如下,spring boot版本为2.0.0.RELEASE:

1、自定义yaml文件资源加载类

import org.springframework.boot.env.YamlPropertySourceLoader
import org.springframework.core.env.PropertySource
import org.springframework.core.io.support.{DefaultPropertySourceFactory, EncodedResource}
/**
  * yaml资源加载类
  */
class YamlPropertyLoaderFactory extends DefaultPropertySourceFactory{
  override def createPropertySource(name: String, resource: EncodedResource): PropertySource[_] = {
    if (resource == null) {
      super.createPropertySource(name, resource)
    }
    return new YamlPropertySourceLoader().load(resource.getResource.getFilename, resource.getResource, null)
  }
}

这个类继承自DefaultPropertySourceFactory类,并重写了createPropertySource方法。

2、引入@PropertySource注解并使用

import com.core.conf.YamlPropertyLoaderFactory
import javax.persistence.EntityManagerFactory
import javax.sql.DataSource
import org.springframework.beans.factory.annotation.{Autowired, Qualifier}
import org.springframework.boot.autoconfigure.jdbc.DataSourceBuilder
import org.springframework.boot.context.properties.ConfigurationProperties
import org.springframework.boot.orm.jpa.EntityManagerFactoryBuilder
import org.springframework.context.annotation.{Bean, Configuration, PropertySource}
import org.springframework.core.env.Environment
import org.springframework.data.jpa.repository.config.EnableJpaRepositories
import org.springframework.orm.jpa.{JpaTransactionManager, LocalContainerEntityManagerFactoryBean}
import org.springframework.transaction.PlatformTransactionManager
/**
  * JPA 数据源配置
  */
@Configuration
@PropertySource(value = Array("classpath:/bootstrap-report.yml"), factory = classOf[YamlPropertyLoaderFactory])
@EnableJpaRepositories(
  entityManagerFactoryRef = "reportEntityManager",
  transactionManagerRef = "reportTransactionManager",
  basePackages = Array("com.report.dao")
)
class ReportDBConfig {
  @Autowired
  private var env: Environment = _
  @Bean
  @ConfigurationProperties(prefix = "spring.datasource.report")
  def reportDataSource(): DataSource = DataSourceBuilder.create.build
  @Bean(name = Array("reportEntityManager"))
  def reportEntityManagerFactory(builder: EntityManagerFactoryBuilder): LocalContainerEntityManagerFactoryBean = {
    val entityManager = builder
      .dataSource(reportDataSource())
      .packages("com.report.model") //设置JPA实体包路径
      .persistenceUnit("reportPU")
      .build
    entityManager.setJpaProperties(additionalProperties())
    entityManager
  }
  @Bean(name = Array("reportTransactionManager"))
  def reportTransactionManager(@Qualifier("reportEntityManager")
                               entityManagerFactory: EntityManagerFactory): PlatformTransactionManager = {
    new JpaTransactionManager(entityManagerFactory)
  }
  /**
    * 获取JPA配置
    *
    * @return
    */
  def additionalProperties(): Properties = {
    val properties = new Properties();
    properties.setProperty("hibernate.hbm2ddl.auto", env.getProperty("spring.jpa.report.hibernate.ddl-auto"))
    properties.setProperty("hibernate.show_sql", env.getProperty("spring.jpa.report.show-sql"))
    properties.setProperty("hibernate.dialect", env.getProperty("spring.jpa.report.database-platform"))
    properties
  }
}

源码解读

实现该功能涉及两个地方:

1、@PropertySource注解:用于声明和配置自定义配置类需要加载的配置文件信息,源码及属性解释如下:

package org.springframework.context.annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Repeatable;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.core.io.support.PropertySourceFactory;
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Repeatable(PropertySources.class)
public @interface PropertySource {
    // 用于声明属性源名称
    String name() default "";
    // 声明属性文件位置
    String[] value();
    // 是否忽略未找到的资源
    boolean ignoreResourceNotFound() default false;
    // 声明配置文件的编码
    String encoding() default "";
    // 声明解析配置文件的类
    Class<? extends PropertySourceFactory> factory() default PropertySourceFactory.class;
}

2、spring boot配置文件解析类:

在@PropertySource注解的定义中,属性factory主要用来声明解析配置文件的类,这个类必须是PropertySourceFactory接口的实现,在我们自定义了yaml文件加载类之后,它的实现关系如下:

从以上类图可以发现,它的实现类主要有2个:

  • DefaultPropertySourceFactory:默认的配置文件解析类,主要用于解析properties配置文件
  • YamlPropertyLoaderFactory:自定义的yaml资源解析类,主要用于解析yaml配置文件,使用时需要在PropertySource注解的factory属性上声明

这两个类将配置文件解析后,会将属性信息存入Spring的Environment对象中,以供我们通过@Value注解等方式使用。

因此,我们如果遇到spring boot不能加载并解析自定义配置的时候,可以试试自定义配置文件解析类解决。

参考链接

YAML Shortcomings

Exposing YAML as Properties in the Spring Environment

ConfigurationProperties loading list from YML:base on kotlin

Properties转YAML idea插件——生产力保证:Properties to YAML Converter

如何引入多个yml方法

SpringBoot默认加载的是application.yml文件,所以想要引入其他配置的yml文件,就要在application.yml中激活该文件

定义一个application-resources.yml文件(注意:必须以application-开头)

application.yml中:

spring: 
 profiles:
   active: resources

以上操作,xml自定义文件加载完成,接下来进行注入。

application-resources.yml配置文件代码:

user:
 filepath: 12346
 uname: "13"
admin:
 aname: 26

方案一:无前缀,使用@Value注解

@Component
//@ConfigurationProperties(prefix = "user")
public class User {
    @Value("${user.filepath}")
    private String filepath;
    @Value("${user.uname}")
    private String uname;
   public String getFilepath() {
       return filepath;
   }
   public void setFilepath(String filepath) {
       this.filepath = filepath;
   }
   public String getUname() {
       return uname;
   }
   public void setUname(String uname) {
       this.uname = uname;
   }
   @Override
   public String toString() {
       return "User{" +
               "filepath='" + filepath + '\'' +
               ", uname='" + uname + '\'' +
               '}';
   }
}

方案二:有前缀,无需@Value注解

@Component
@ConfigurationProperties(prefix = "user")
public class User {
    //@Value("${user.filepath}")
    private String filepath;
    //@Value("${user.uname}")
    private String uname;
   public String getFilepath() {
       return filepath;
   }
   public void setFilepath(String filepath) {
       this.filepath = filepath;
   }
   public String getUname() {
       return uname;
   }
   public void setUname(String uname) {
       this.uname = uname;
   }
   @Override
   public String toString() {
       return "User{" +
               "filepath='" + filepath + '\'' +
               ", uname='" + uname + '\'' +
               '}';
   }
}

测试类:

package com.sun123.springboot;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
@RunWith(SpringRunner.class)
@SpringBootTest
public class UTest {
   @Autowired
   User user;
   @Test
   public void test01(){
       System.out.println(user);
   }
}

测试结果:

以上为个人经验,希望能给大家一个参考,也希望大家多多支持我们。

(0)

相关推荐

  • spring boot装载自定义yml文件

    yml格式的配置文件感觉很人性化,所以想把项目中的.properties都替换成.yml文件,主要springboot自1.5以后就把@configurationProperties中的location参数去掉,各种查询之后发现可以用YamlPropertySourceLoader去装载yml文件,上代码 public void onApplicationEvent(ApplicationEnvironmentPreparedEvent event) { ResourceLoader loade

  • 详解Spring Boot加载properties和yml配置文件

    一.系统启动后注入配置 package com.example.config; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.PropertySource; import org.springframewo

  • 详解springboot读取yml配置的几种方式

    yml 文件规则 yml文件的好处,天然的树状结构,一目了然,实质上跟properties是差不多的. 不支持tab缩进 可以使用 "-小写字母" 或 "_小写字母"来 代替 "大写字母",如 userName 与 user-name ,user_name 含义是一样的 key: value 格式书写 key 后面跟着冒号,再后面跟着一个空格,然后是值 几种数据格式的表示方式 1.普通的值(数字,字符串,布尔) 2.对象.Map (属性和值) (

  • springboot实现yml里的自定义配置方法

    主要介绍三种,字符串配置,数组配置和带默认值的配置 ◆字符串配置 //yml setString: hello /** * 字符串. */ @Value("${setString}") String setString; ◆数组配置 //yml setArray: -http://www.taobao.com -http://www.tmall.com /** * 数组. */ @Value("${setArray}") String[] setArray; ◆带默

  • SpringBoot自定义加载yml实现方式,附源码解读

    目录 自定义加载yml,附源码解读 解决方法 源码解读 如何引入多个yml方法 方案一:无前缀,使用@Value注解 方案二:有前缀,无需@Value注解 自定义加载yml,附源码解读 昨天在对公司的微服务配置文件标准化的过程中,发现将原来的properties文件转为yml文件之后,微服务module中标记有@Configuration的配置类都不能正常工作了,究其原因,是由于@PropertySource属性默认只用于标记并告诉spring boot加载properties类型的文件 spr

  • 如何使用PHP+jQuery+MySQL实现异步加载ECharts地图数据(附源码下载)

    ECharts地图主要用于地理区域数据的可视化,展示不同区域的数据分布信息.ECharts官网提供了中国地图.世界地图等地图数据下载,通过js引入或异步加载json文件的形式调用地图. 效果演示      源码下载 本文将结合实例讲解如何使用PHP+jQuery+MySQL实现异步加载ECharts地图数据,我们以中国地图为例,展示去年(2015年)我国各省份GDP数据.通过异步请求php,读取mysql中的数据,然后展示在地图上,因此本文除了你掌握前端知识外,还需要你了解PHP以及MySQL方

  • SpringBoot实现加载yml文件中字典数据

    将字典数据,配置在 yml 文件中,通过加载yml将数据加载到 Map中 Spring Boot 中 yml 配置.引用其它 yml 中的配置.# 在配置文件目录(如:resources)下新建application-xxx 必须以application开头的yml文件, 多个文件用 "," 号分隔,不能换行 项目结构文件 application.yml server: port: 8088 application: name: VipSoft Env Demo spring: pro

  • Flutter加载图片流程之ImageProvider源码示例解析

    目录 加载网络图片 ImageProvider resolve obtainKey resolveStreamForKey loadBuffer load(被废弃) evict 总结 困惑解答 加载网络图片 Image.network()是Flutter提供的一种从网络上加载图片的方法,它可以从指定的URL加载图片,并在加载完成后将其显示在应用程序中.本节内容,我们从源码出发,探讨下图片的加载流程. ImageProvider ImageProvider是Flutter中一个抽象类,它定义了一种

  • Flutter加载图片流程之ImageCache源码示例解析

    目录 ImageCache _pendingImages._cache._liveImages maximumSize.currentSize clear evict _touch _checkCacheSize _trackLiveImage putIfAbsent clearLiveImages 答疑解惑 ImageCache const int _kDefaultSize = 1000; const int _kDefaultSizeBytes = 100 << 20; // 100 M

  • 一篇文章带你入门Springboot整合微信登录与微信支付(附源码)

    0. 前期准备 在使用微信支付前,默认小伙伴已经具备以下技能: 熟练使用springboot(SSM) + Mybatis(plus)/JPA + HttpClient + mysql5.x 了解JWT 权限校验 阅读过微信开放平台微信支付与微信登录相关文档,可以简单看懂时序图 有微信开放平台开发者资质认证账户,具备开通微信支付(如果不具备的小伙伴可以找身边有的人借一下) 1. 微信扫码登录 1.1 微信授权一键登录功能介绍 简介:登录方式优缺点和微信授权一键登录功能介绍 # 1.手机号或者邮箱

  • FCKEditor 自定义用户目录的修改步骤 (附源码)

    由于我这边的网络原因,没用从FCK的官网下载到源码... 这套源码是FCK2.2版反编译出来的 源码:点此下载 源码中主要修改的地方做了注释 大致的修改如下 : 获取用户目录的源码: FileWorkerBase.cs 这里主要是做了一些注释 在程序中可以直接在用户登录的时候指定 这个方案只是方便多用户使用的时候为用户指定不同的文件目录 Session["FCKeditor:UserFilesPath"]="用户文件相对目录"; 复制代码 代码如下: /// <

  • 自定义GridView并且实现拖拽(附源码)

    写在前面的话 本篇blog实现了GridView的拖拽功能.方法和上一篇自定义ListView实现拖拽ListItem项交换位置一个原理.只是在交换位置上记录了X轴的相关坐标,计算了X轴的相关变量. 实现效果图如下  说明: 本篇给出实现代码,但是不做任何说明.如需了解请看上一篇blog:自定义ListView实现拖拽ListItem项交换位置 文件代码: 1.MainActivity.java 复制代码 代码如下: package com.jay.draggridview; import ja

  • 自定义javascript验证框架示例【附源码下载】

    本文实例讲述了自定义javascript验证框架.分享给大家供大家参考,具体如下: 看过 jquery 验证框架,在使用的时候,其实还是很晕的,很麻烦,使用的时候代码也不简洁,因此才有了弄一个自己的jquery验证框架的计划,基本原理就是对 input ,select, textarea 这三类控件做校验,在里面定义自定义属性作为检验. 另外采用js 做i18n 国际化,通过cookies 中的语言,调用不同的js 语言包, 对于自己开发项目来说,足够用了,而且,还可以灵活扩展.个人用应该不错.

  • 微信小程序之自定义组件的实现代码(附源码)

    最近在项目开发中,遇到好多雷同的页面样式,就想着可以将常用的功能模块封装成组件,方便在项目中使用和修改,下面就参照微信小程序的文档分步骤写一个微信小程序的组件. 附上效果图: step1:创建文件并申明 与创建微信小程序的页面一样,一个自定义组件也需要json,wxml,wxss,js四个文件. 在项目根目录中创建文件夹,取名为:component,在该目录下继续创建文件夹successModal. 可以在开发工具中右键创建,选择component,默认自动会创建四个文件.如图: 在succes

随机推荐