

alibaba druid 在springboot start autoconfig 下的bug
source link: https://www.cnblogs.com/wangiqngpei557/p/7136455.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

alibaba druid 在springboot start autoconfig下的bug
标签(空格分隔):druid springboot start autoconfig
- 发现、分析过程
最近在使用alibaba druid进行多数据源连接的时候无意中发现一个小bug,已经提交github issue 官方已经fix。issue 地址:https://github.com/alibaba/druid/issues/1796
发现、分析过程
我们使用的java开发框架是封装好的。框架对数据源的支持是master、slave架构的,就是可以一组多从数据源,内部会自动进行主从写入、查询切换。
我们现在处于.net专java过程中,特殊场景下新java系统需要连接两个数据源,默认连接mysql数据源,但是有时候还需要查询sqlserver数据源来获取一些兼容性数据。
所以,在配置第二个数据源的时候,系统load就报错。
我们使用springboot框架,datasource config 基于springboot properties进行配置。然后使用configuration 进行自动druid daasource bean的创建。这看起来好像没什么问题。
@Bean(name = "dataSource")
@ConfigurationProperties(prefix = "ecommon.order.druid")
public DataSource getOrderDataSource() {
return new DruidDataSource();
}
如果不是springboot,一般都会自己来初始化所有的属性。从配置文件加载配置,然后手动设置DruidDataSource bean。
没多想,就直接用这种方式使用了。但是在启动的时候,初始化bean的时候就报错了。
'maxEvictableIdleTimeMillis' threw exception; nested exception is java.lang.IllegalArgumentException: maxEvictableIdleTimeMillis must be grater than minEvictableIdleTimeMillis
大概意思是说,'maxEvictableIdleTimeMillis'最大存活时间必须大于'minEvictableIdleTimeMillis'最小存活时间。
第一反应肯定是配置错了,检查配置。
##一个连接在池中最小生存的时间(ms)
ecommon.order.druid.minEvictableIdleTimeMillis=300000
##一个连接在池中最大生存的时间(ms)
ecommon.order.druid.maxEvictableIdleTimeMillis=600000
好像没错啊,然后在debug下,问题同样出现。minEvictableIdleTimeMillis属性和maxEvictableIdleTimeMillis属性的前后顺序好像也没问题。试试看的心里,将两个属性前后顺序交换下,问题还是出现。
蒙蔽状态_。
感觉这个问题有点诡异了,时间要紧,直接找到报错的地方,进行源码跟踪。
上 github search alibaba druid 首页,直接gith clone下来,定位到错误提示的位置。
全局查找的时候有两处有这个exception的throw。
一: init 方法
public void init() throws SQLException {
if (maxEvictableIdleTimeMillis < minEvictableIdleTimeMillis) {
throw new SQLException("maxEvictableIdleTimeMillis must be grater than minEvictableIdleTimeMillis");
}
为了便于阅读,我删掉了init中对我们分析问题来说无用的代码。
二:setMaxEvictableIdleTimeMillis 方法
public void setMaxEvictableIdleTimeMillis(long maxEvictableIdleTimeMillis) {
if (maxEvictableIdleTimeMillis < 1000 * 30) {
LOG.error("maxEvictableIdleTimeMillis should be greater than 30000");
}
if (maxEvictableIdleTimeMillis < minEvictableIdleTimeMillis) {
throw new IllegalArgumentException("maxEvictableIdleTimeMillis must be grater than minEvictableIdleTimeMillis");
}
this.maxEvictableIdleTimeMillis = maxEvictableIdleTimeMillis;
}
这两个方法逻辑都比较简单,init初始化的时候会检查这两个bean属性的值。setMaxEvictableIdleTimeMillis,设置这个最大存活时间的时候有一个检查。如果你的最大存活时间小于最小存活时间直接报错。
所以直接在这两个地方打上断点,然后debug,在跟踪下变量的值基本就知道问题在哪里了。
通过debug,发现直接new DruidDataSource()使用数据源,不会走到init方法。不会进入到触发报错的地方。貌似我的代码路径应该不会产生这个检查。继续运行,看setMaxEvictableIdleTimeMillis方法什么情况。
发现问题了,在进行setMaxEvictableIdleTimeMillis方法的时候,minEvictableIdleTimeMillis属性的值是1800000。
看下这个值哪里来的。
protected volatile long minEvictableIdleTimeMillis = DEFAULT_MIN_EVICTABLE_IDLE_TIME_MILLIS;
public static final long DEFAULT_MIN_EVICTABLE_IDLE_TIME_MILLIS =
1000L * 60L * 30L;
minEvictableIdleTimeMillis 属性有一个default值。单位是ms(millisecond),所以这里的default 值是30m(minute)分钟。
我们配置的是600000ms,所以比1800000小。但是这个就奇怪了,我们明明设置了minEvictableIdleTimeMillis 参数。为什么没起作用,一下子就想到是不是顺序问题。
然后继续debug,先绕过这个检查,看是不是setMinEvictableIdleTimeMillis 方法在setMaxEvictableIdleTimeMillis 方法之后执行,导致这个检查和配置顺序冲突。
debug下来,确实是这个问题。然后就比较好奇,我们现在所使用的这个框架帮我们封装了druid的时候是怎么处理的,通过查看框架源码,里面有一个hashcode的排序,解决了这个问题。(果然老司机,高手)这里就不展开了。
那么我们如果解决这个问题,其实很简单,知道问题在哪里绕过去还是很简单的。
一:先把配置的minEvictableIdleTimeMillis、maxEvictableIdleTimeMillis获取进来
@Data
@EqualsAndHashCode
@ConfigurationProperties(prefix = "ecommon.order.druid")
public class SqlServerDruidConfig {
private Long minEvictableIdleTimeMillis;
private Long maxEvictableIdleTimeMillis;
}
二:然后自己先设置一下这两个属性,springboot autoconfig 的时候就不会出错
@Autowired
private SqlServerDruidConfig druidConfig;
@Bean(name = "dataSource")
@ConfigurationProperties(prefix = "ecommon.order.druid")
public DataSource getOrderDataSource() {
DruidDataSource dataSource = new DruidDataSource();
/**setMinEvictableIdleTimeMillis需要先设置*/
dataSource.setMinEvictableIdleTimeMillis(druidConfig.getMinEvictableIdleTimeMillis());
dataSource.setMaxEvictableIdleTimeMillis(druidConfig.getMaxEvictableIdleTimeMillis());
return dataSource;
}
@Bean
public SqlServerDruidConfig getDruidConfig() {
return new SqlServerDruidConfig();
}
问题到这里分析就结束了。这个小bug,alibaba druid 已经fix。
如果你对如何fix感兴趣,请参看druid 有关于autoconfiger修复的代码:
https://github.com/lihengming/druid/commit/ca13e8ff5a78c83f953fa8fb320c56be223219e1
突然能明白,其实有关于开源的好处,你已经获益了。可以一起参与使用,一起参与发现问题,一起参与fixbug。这也许就是linux、git这类优秀艺术品背后的核心技术价值观。
github 地址:https://github.com/Plen-wang
Recommend
-
52
-
22
一、Druid介绍 Druid 是 MetaMarket 公司研发,专为海量数据集上的做高性能 OLAP (OnLine Analysis Processing)而设计的数据存储和分析系统,目前 Druid 已经在Apache基金会下孵化。Druid的主...
-
56
-
89
Druid 支持两种 Kafka 数据摄入方式: Push 通过 Tranquility; Pull 通过 Kafka Indexing Service。 Tranquility TODO Kafka Ind...
-
94
MiddleManager TODO Historical 堆内存 Historical 堆内存的使用: 部分未合并的 Segment 查询结果;
-
21
localdots — HTTPS domains for development Important As the title says, this tool is to be used for development. It is not meant to run at production and it hasn't been tested in CI environments e...
-
10
Springboot Druid 使用Slf4j输出可执行SQL 28 六月 2019 5:41:22 下午在开发中,为了数据安全,所有SQL语句肯定是用占位符的,但是在实际开发中,为了方便追踪问题,经常需要查看具体执行的SQL语句内容,而用了占位符之后,每次真实执行的语句只能...
-
9
Springboot Druid 自定义加密数据库密码 21 十二月 2020 3:01:14 下午开发过程中,配置的数据库密码通常是明文形式,这样首先第一个安全性不好(相对来说),不符合一个开发规范(如项目中不能出现明文账号密码),其实就是当出现特殊需求时,比如...
-
4
SpringBoot 整合druid 发表于 2018-09-05
-
9
userChromeJS Tested on Firefox Developer Edition 106.0b3. Instructions Video running installation steps below: https://youtu.be/_4fdUdp3G4o
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK