在面试某家单位的时候,碰到了一家单位线上考试,要求开发一个springboot后台。一眼看去都是正常的需求,突然我在里面发现了一个奇葩要求,要求数据库允许线上修改,并且不能通过修改配置文件的方式。可以简单理解成用rest请求也能修改数据库配置。说实话,这成功引起了我的注意,像这种网上千篇一律回答只有多数据源配置和数据库配置数据源的解决方案,我决定来找点刺激,最终成功在半小时内整了出来。
大家可以收藏下,我面试能碰到,你们也可以,嘿嘿嘿
反射修改代码如下
DynamicDataSource dataSource = Bean("dynamicDataSource");Field field = Class().getSuperclass().getDeclaredField("targetDataSources");field.setAccessible(true);Map map = (HashMap) (dataSource);DruidDataSourceWrapper wrapper = ((String());Field jdbcUrl Class().getSuperclass().getSuperclass().getDeclaredField("jdbcUrl");Field username Class().getSuperclass().getSuperclass().getDeclaredField("username");Field password Class().getSuperclass().getSuperclass().getDeclaredField("password");jdbcUrl.setAccessible(true);username.setAccessible(true);password.setAccessible(true);ReflectUtils.setFieldValue(wrapper, "jdbcUrl", vo.getHost());ReflectUtils.setFieldValue(wrapper, "username", vo.getUsername());ReflectUtils.setFieldValue(wrapper, "password", vo.getPassword());jdbcUrl.setAccessible(false);username.setAccessible(false);password.setAccessible(false);map.put(String(), wrapper);ReflectUtils.setFieldValue(dataSource, "targetDataSources", map);field.setAccessible(false);
这时候我发现,调接口修改配置之后再去查询,已经成功修改了数据源,在我很满意的时候,我手欠先点了查询,再去改配置,再去查询时候,果不其然数据库没切换过来,很容易就能想到这是数据库在建立连接之后,数据库已经初始化了,我再去修改配置在短时间内再去查询会继续沿用之前初始化的配置,聪明的我,就马上去找数据源各个父级里面初始化方法,结果还真让我找到了,在DruidDataSource这个类下,如下图
果然在这里可以看到有个inited参数在把关着初始化配置的读取,但是可千万别急着改inited属性,这种大工程的数据化初始肯定会设计到一堆线程池的调度,改一个inited肯定没什么卵用,我改过了,成功报了一堆错,但是好巧不巧给我发现了一个restart方法,不得不说数据库开发人员给自己留的后路真多,如下图
果然里面有一大票的参数初始化和重置操作,基操基操,那后面就很简单了,我们直接在反射里面调这个方法就能完成数据源初始化了吧,然后我兴冲冲的把代码写好了,如下
DynamicDataSource dataSource = Bean("dynamicDataSource");Field field = Class().getSuperclass().getDeclaredField("targetDataSources");field.setAccessible(true);Map map = (HashMap) (dataSource);DruidDataSourceWrapper wrapper = ((String());// 数据源的配置存放点Field jdbcUrl Class().getSuperclass().getSuperclass().getDeclaredField("jdbcUrl");Field username Class().getSuperclass().getSuperclass().getDeclaredField("username");Field password Class().getSuperclass().getSuperclass().getDeclaredField("password");// 重启方法Method restartMethod = Class().getSuperclass().getDeclaredMethod("restart");jdbcUrl.setAccessible(true);username.setAccessible(true);password.setAccessible(true);ReflectUtils.setFieldValue(wrapper, "jdbcUrl", vo.getHost());ReflectUtils.setFieldValue(wrapper, "username", vo.getUsername());ReflectUtils.setFieldValue(wrapper, "password", vo.getPassword());jdbcUrl.setAccessible(false);username.setAccessible(false);password.setAccessible(false);map.put(String(), wrapper);ReflectUtils.setFieldValue(dataSource, "targetDataSources", map);field.setAccessible(false);// 重启重启重启restartMethod.invoke(wrapper);
DynamicDataSource dataSource = Bean("dynamicDataSource");Field field = Class().getSuperclass().getDeclaredField("targetDataSources");field.setAccessible(true);Map map = (HashMap) (dataSource);DruidDataSourceWrapper wrapper = ((String());// 数据源的配置存放点Field jdbcUrl Class().getSuperclass().getSuperclass().getDeclaredField("jdbcUrl");Field username Class().getSuperclass().getSuperclass().getDeclaredField("username");Field password Class().getSuperclass().getSuperclass().getDeclaredField("password");// 重启方法Method restartMethod = Class().getSuperclass().getDeclaredMethod("restart");Field poolingCount = Class().getSuperclass().getDeclaredField("poolingCount");jdbcUrl.setAccessible(true);username.setAccessible(true);password.setAccessible(true);poolingCount.setAccessible(true);ReflectUtils.setFieldValue(wrapper, "jdbcUrl", vo.getHost());ReflectUtils.setFieldValue(wrapper, "username", vo.getUsername());ReflectUtils.setFieldValue(wrapper, "password", vo.getPassword());// 一定要清,关系到数据库连接的新建,restart方法没有自动清0,导致restart之后查询获取不到线程ReflectUtils.setFieldValue(wrapper, "poolingCount", 0);jdbcUrl.setAccessible(false);username.setAccessible(false);password.setAccessible(false);poolingCount.setAccessible(false);map.put(String(), wrapper);ReflectUtils.setFieldValue(dataSource, "targetDataSources", map);field.setAccessible(false);// 重启重启重启restartMethod.invoke(wrapper);
本文发布于:2024-01-30 19:55:27,感谢您对本站的认可!
本文链接:https://www.4u4v.net/it/170661572822445.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
留言与评论(共有 0 条评论) |