文档章节

Springboot 随笔(2)-- Properties 配置一坑

alexqdjay
 alexqdjay
发布于 2016/10/09 15:18
字数 582
阅读 280
收藏 1
点赞 0
评论 0

SpringBoot的迁移过程中碰到的奇葩坑

什么坑?

原Spring项目迁移成SpringBoot项目,早前使用 PropertyPlaceholderConfigurer  配置properties引入,在使用properties中的配置项时报错,如 ${user.name} 配置项找不到,有时又可以但 application.properties 中配置项找不到。

要找到问题关键先要知道Spring处理配置项注入是怎么实现的。

Spring 配置项注入

1. Spring注入方式

  1. XML注入
    <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
              destroy-method="close">
        <property name="driverClassName" value="${spring.datasource.driver}"/>
        <property name="url" value="${spring.datasource.url}"/>
        <property name="username" value="${spring.datasource.username}"/>
        <property name="password" value="${spring.datasource.password}"/>
        <property name="initialSize" value="${spring.datasource.initialSize}"/>
        <property name="maxActive" value="${spring.datasource.maxActive}"/>
        <property name="maxIdle" value="${spring.datasource.maxIdle}"/>
        <property name="minIdle" value="${spring.datasource.minIdle}"/>
        <property name="maxWait" value="${spring.datasource.maxWait}"/>
    </bean>

     

  2. @Value Java代码中注入
    @Value("${user.name}")
    private String username;

     

2. 实现原理

2.1 XML

PropertyPlaceholderConfigurer 为例,实现 BeanFactoryPostProcessor  接口所以bean Definition 载入完毕后会被调用

postProcessBeanFactory()

在该方法中主要是遍历所有的BeanDefinition,找到那些 ${} 的配置项,然后替换掉

visitor.visitBeanDefinition(bd); // 遍历BeanDefinition

最后,将 StringValueResolver 加到 BeanFactory 中留作他用(如 AutowiredAnnotationBeanPostProcessor 有用,下面就分析)

beanFactoryToProcess.addEmbeddedValueResolver(valueResolver);

2.2 @Value

所有 @Value@Autowired  注解都是由 AutowiredAnnotationBeanPostProcessor 来实现处理的,由于实现了接口 InstantiationAwareBeanPostProcessor ,所以会自动在实例完后调用

PropertyValues postProcessPropertyValues(PropertyValues var1, PropertyDescriptor[] var2, Object var3, String var4)


public PropertyValues postProcessPropertyValues(PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeansException {
    InjectionMetadata metadata = this.findAutowiringMetadata(beanName, bean.getClass(), pvs);

    try {
        metadata.inject(bean, beanName, pvs); // 注入的主逻辑
        return pvs;
    } catch (BeanCreationException var7) {
        throw var7;
    } catch (Throwable var8) {
        throw new BeanCreationException(beanName, "Injection of autowired dependencies failed", var8);
    }
}

在 metadata.inject 中主要是调用 BeanFactory 的

value = AutowiredAnnotationBeanPostProcessor.this.beanFactory.resolveDependency(desc, beanName, autowiredBeanNames, typeConverter);

...

field.set(bean, value);
beanFactory.resolveDependency
  -> beanFactory.doResolveDependency
    -> beanFactory.resolveEmbeddedValue

public String resolveEmbeddedValue(String value) {
    String result = value;

    StringValueResolver resolver;
    for(Iterator var3 = this.embeddedValueResolvers.iterator(); var3.hasNext(); result = resolver.resolveStringValue(result)) {
        resolver = (StringValueResolver)var3.next();
        if(result == null) {
            return null;
        }
    }

    return result;
}

最终还是获取 embeddedValueResolvers 来处理

为什么会报错?

SpringBoot 默认就会注册一个 PropertySourcesPlaceholderConfigurer,当再配置一个 PropertyPlaceholderConfigurer 时就会存在两个,一部分properties在前者、一部分在后者,那么肯定会执行其中一个时报错。

在执行 resolver.resolveStringValue(result) 时,最终 PlaceholderResolvingStringValueResolver 的 helper 中

protected String parseStringValue(String strVal, PropertyPlaceholderHelper.PlaceholderResolver placeholderResolver, Set<String> visitedPlaceholders) {

  ...
  if (value != null) {
     ...
  } else {
    if(!this.ignoreUnresolvablePlaceholders) {
      throw new IllegalArgumentException("Could not resolve placeholder \'" + placeholder + "\'" + " in string value \"" + strVal + "\"");
    }
  }
}

就是解析不到${}时就会报错。

解决方法

  1. 将原来的 PropertySourcesPlaceholderConfigurer 去掉
  2. 改写 PropertySourcesPlaceholderConfigurer,将 Environment 加入
  3. 将两个Configurer的 ignoreUnresolvablePlaceholders 都配置成true

三种方式任选,建议(1)使用SpringBoot的最佳实践 

© 著作权归作者所有

共有 人打赏支持
alexqdjay
粉丝 35
博文 26
码字总数 31560
作品 0
浦东
高级程序员
yml中某些配置不生效的解决方案

起因 将springboot项目的properties配置文件改为yml之后redis死活连不上了。 找问题 springboot的配置文件有两种方式:properties和yml,之前properties时候是没有任何问题的,那么来看一下y...

梦想修补师 ⋅ 05/09 ⋅ 0

学习 Spring Boot 知识看这一篇就够了

从2016年因为工作原因开始研究 Spring Boot ,先后写了很多关于 Spring Boot 的文章,发表在技术社区、我的博客和我的公号内。粗略的统计了一下总共的文章加起来大概有六十多篇了,其中一部分...

ityouknow ⋅ 05/28 ⋅ 0

恒宇少年/spring-boot-chapter

简书整套文档以及源码解析 专题 专题名称 专题描述 001 Spring Boot 核心技术 讲解SpringBoot一些企业级层面的核心组件 002 Spring Cloud 核心技术 对Spring Cloud核心技术全面讲解 003 Quer...

恒宇少年 ⋅ 04/19 ⋅ 0

springboot打成jar包后配置外部资源映射成静态资源

很多的项目都要上传图片那些,然后通过打包jar包或者war包发布到服务器上,我们不可能把上传图片的文件夹放在jar包或者war包里面,那样会越来越大。所以有了下面的配置,其他框架都好说可以把...

duangecho ⋅ 05/09 ⋅ 0

SpringBoot 2.0 系列001 -- 入门介绍以及相关概念

SpringBoot 2.0 系列001 -- 入门介绍以及相关概念 什么是SpringBoot? 项目地址:http://projects.spring.io/spring-boot/ SpringBoot介绍 Spring Boot使开发独立的,产品级别的基于Spring的...

路上有你0314 ⋅ 05/10 ⋅ 0

(一)SpringBoot——helloworld

一、为什么会诞生SpringBoot? 先看看spring的优势: 1、代码解耦、简化开发:代码中不再需要new去构造对象,而是交由spring去管理对象。 2、支持AOP:面向切面的编程,方便进行权限拦截、日...

solidwang ⋅ 04/17 ⋅ 0

SpringBoot 整合(六)Security & Oauth2.0(完整篇)

1. 快速实现篇(实现最基本的登录): SpringSecurity 快速实现项目 2. 企业级封装篇 我的 Spring Security 文集 SpringBoot 整合 Security(一)实现用户认证并判断返回json还是view SpringBo...

FantJ ⋅ 05/22 ⋅ 0

SpringBoot 入门实例

SpringBoot 是由 pivotal 提供的 Java 开发框架,伴随着 spring 4.0 版本一起发布,旨在简化 Spring 项目的初始化及开发过程,框架本身为开发过程提供了大量的默认配置,当然我们也可以通过简...

Aotian ⋅ 05/29 ⋅ 0

springboot开发简单的web应用前篇

你已经会spring了,也非常熟悉springmvc的开发,平时你搭建个web应用简单吗?好像也不难!那么今天我来试试用springboot来开发个简单的web应用来试试。 在正式讲解springboot开发web应用之前...

GeCoder ⋅ 05/04 ⋅ 0

Docker部署SpringBoot项目简单实例

此类文章网上很多,但是自己按着做也会出各种各样的错误。记录我踩的坑 目标是在centos7中部署springboot项目,在外部能访问。 先上springboot代码简单的一批 @SpringBootApplication@RestC...

cgj296645438 ⋅ 04/19 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

HiSDP —— 高效的C++软件开发平台

目前阿里集团每天有近1000PB的数据是通过LogAgent采集的,为了让LogAgent做到资源占用节省和高效采集,背后是基于HiSDP去构建的。 缘由 当决定采用C++编程语言去开发一个软件时,紧接着所面临...

阿里云云栖社区 ⋅ 25分钟前 ⋅ 0

zookeeper-3.4.12 下载与安装教程

一、zookeeper下载地址 http://mirrors.hust.edu.cn/apache/zookeeper/ 二、启动教程 把压缩包放在指定目录下 第三: 进入 conf文件夹底下 zoo_sample.cfg 文件名改成 zoo.cfg 第四步: 进入b...

泉天下 ⋅ 26分钟前 ⋅ 0

Oracle 中文日期转换

SELECT TO_date('2011年11月11日', 'yy"年"mm"月"dd"日"') FROM DUAL; 1. Oracle无法识别中文格式,所以添加双引号。 2. 后面的格式是指字符串在转换前的格式,而不是指转换后的格式。...

江戸川 ⋅ 28分钟前 ⋅ 0

MySell:API Spring Boot

起步 类目 商品 订单

BeanHo ⋅ 30分钟前 ⋅ 0

Spring方法拦截器MethodInterceptor

参考资料 1、Spring方法拦截器MethodInterceptor 2、Sharding JDBC源码分析-JdbcMethodInvocation类的作用

哎小艾 ⋅ 33分钟前 ⋅ 0

正则表达式

元字符 元字符,又叫字符集,就是用一些特殊符号表示特定种类的字符或位置。 匹配字符 . 匹配除换行符以外的任意字符 \w 匹配字母或数字或下划线或汉字 \s 匹配任意的空白符 \d 匹配数字 匹配...

wangchen1999 ⋅ 33分钟前 ⋅ 0

数据库数据导入Elasticsearch案例分享

基于bboss持久层和bboss elasticsearch客户端实现数据库数据导入es案例分享(支持各种数据库和各种es版本) 1.案例对应的源码 https://gitee.com/bboss/bboss-elastic/blob/master/bboss-el...

bboss ⋅ 34分钟前 ⋅ 0

动手---sbt(2)

参考 https://blog.csdn.net/leishangwen/article/details/46225587 建立一个chisel_max目录,文件内容如后面所述,现在开始执行命令: joe@joe-Aspire-Z3730:/media/sdb4/download/scala$ c......

whoisliang ⋅ 41分钟前 ⋅ 0

纯js实现最简单的文件上传(后台使用MultipartFile)

<!DOCTYPE html><html><head> <meta charset="UTF-8"> <title>XMLHttpRequest上传文件</title> <script type="text/javascript"> //图片上传 var xhr......

孟飞阳 ⋅ 46分钟前 ⋅ 0

iOS宇宙大战游戏、调试工具、各种动画、AR相册、相机图片编辑等源码

iOS精选源码 日期时间选择器,swift Space Battle 宇宙大战 SpriteKit游戏源码 LLDebugTool - 便捷的IOS调试工具(新增截屏功能) 相机扫描or长按识别二维码、FMDB、键盘动态高度、定位等 动画...

sunnyaigd ⋅ 46分钟前 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部