网易首页 > 网易号 > 正文 申请入驻

工作十年,看到这样的代码,内心五味杂陈...

0
分享至

Java精选面试题(微信小程序):5000+道面试题和选择题,真实面经简历模版,包含Java基础、并发、JVM、线程、MQ系列、Redis、Spring系列、Elasticsearch、Docker、K8s、Flink、Spark、架构设计、大厂真题等,在线随时刷题!

看到这样的代码,内心五味杂陈

那天下午,看到了令我终生难忘的代码,那一刻破防了......

本文记录那些年的 Java 代码轶事

ヾ(•ω•`) 故事还得从半年前数据隔离的那个事情说起......

历史背景

数据隔离

预发,灰度,线上环境共用一个数据库。每一张表有一个 env 字段,环境不同值不同。特别说明:env 字段即环境字段。如下图所示:

隔离之前

️插曲:一开始只有 1 个核心表有 env 字段,其他表均无该字段;有一天预发环境的操作影响到客户线上的数据。为了彻底隔离,剩余的二十几个表均要添加上环境隔离字段。

「当时二十几张表已经大量生产数据,隔离需要做好兼容过渡,保障数据安全。」

隔离改造

其他表历史数据很难做区分,于是新增加的字段 env 初始化 all ,表示预发线上都能访问。以此达到历史数据的兼容。

每一个环境都有一个自己独立标志;从 application.properties 中读该字段;最终到数据库执行的语句如下:

隔离方案

「最拉胯的做法:每一张表涉及到的 DO、Mapper、XML等挨个添加 env 字段。但我指定不能这么干!!!」

具体方案:自定义 mybatis 拦截器进行统一处理。通过这个方案可以解决以下几个问题:

  • 业务代码不用修改,包括 DO、Mapper、XML等。只修改 mybatis 拦截的逻辑。

  • 挨个添加补充字段,工程量很多,出错概率极高

  • 后续扩展容易

最终落地

在 mybatis 拦截器中, 通过改写 SQL。新增时填充环境字段值,查询时添加环境字段条件。真正实现改一处即可。考虑历史数据过渡,将 env = ${当前环境} 修改成 env in (${当前环境},'all')

具体实现逻辑如下图所示:

  1. 其中 env 字段是从 application.properties 配置获取,全局唯一,只要环境不同,env 值不同

  2. 借助 JSqlParser 开源工具,改写 sql 语句,修改重新填充、查询拼接条件即可。链接https://github.com/JSQLParser/JSqlParser

思路:自定义拦截器,填充环境参数,修改 sql 语句,下面是部分代码示例:

@Intercepts(         {@Signature(type = Executor.class, method = "update", args = {MappedStatement.class, Object.class})} ) @Component public class EnvIsolationInterceptor implements Interceptor {     ......     @Override     publicObjectintercept(Invocation invocation) throwsThrowable {         ......         if (SqlCommandType.INSERT == sqlCommandType) {             try {                 // 重写 sql 执行语句,填充环境参数等                 insertMethodProcess(invocation, boundSql);             } catch (Exception exception) {                 log.error("parser insert sql exception, boundSql is:" + JSON.toJSONString(boundSql), exception);                 throwexception;             }         }         returninvocation.proceed();     } }

一气呵成,完美上线。

发展演变

业务需求

「随着业务发展,出现了以下需求:」

  • 上下游合作,我们的 PRC 接口在匹配环境上与他们有差异,需要改造

  • 有一些环境的数据相互相共享,比如预发和灰度等

  • 开发人员的部分后面,希望在预发能纠正线上数据等


SELECT * FROM ${tableName} WHERE bizId = ${bizId} and env in (?,'all')

初步沟通

这个需求的落地交给了来了快两年的小鲜肉。在开始做之前,他也问我该怎么做;我简单说了一些想法,比如可以跳过环境字段检查,不拼接条件;或者拼接所有条件,这样都能查询;亦或者看一下能不能注解来标志特定方法,你想一想如何实现......

(●ˇ∀ˇ●)年纪大了需要给年轻人机会。

勤劳能干

小鲜肉,没多久就实现了。不过有一天下午他遇到了麻烦。他填充的环境字段取出来为 null,看来很久没找到原因,让我帮他看看。(不久前也还教过他 Arthas 如何使用呢,这种问题应该不在话下吧)

具体实现

大致逻辑:在需要跳过环境条件判断的方法前后做硬编码处理,同环切面逻辑, 一加一删。填充颜色部分为小鲜肉的改造逻辑。

大概逻辑就是:将 env 字段填充所有环境。条件过滤的忽略的目的。

SELECT * FROM ${tableName} WHERE env in ('pre','gray','online','all') AND ${其他条件}

错误原因

经过排查是因为 API 里面有多处对 threadLoal 进行处理的逻辑,方法之间存在调用。简化举例:A 和 B 方法都是独立的方法, A 在调用 B 的过程,B 结束时把上下文环境字段删除, A 在获取时得到 null。具体如下:

五味杂陈

当我看到代码的一瞬间,彻底破防了......

「queryProject 方法里面调用 findProjectWithOutEnv, 在两个方法中,都有填充处理 env 的代码。」

遍地开花

然而,这三行代码,随处可见,在业务代码中遍地开花.......

// 1. 变量保存 oriFilterEnv String oriFilterEnv = UserHolder.getUser().getFilterEnv(); // 2. 设置值到应用上下文 UserHolder.getUser().setFilterEnv(globalConfigDTO.getAllEnv()); //....... 业务代码 .... // 3. 结束复原 UserHolder.getUser().setFilterEnv(oriFilterEnv);

改了个遍,很勤劳......

灵魂开问

「难道真的就只能这么做吗,当然还有......」

  • 开闭原则符合了吗

  • 改漏了应该办呢

  • 其他人遇到跳过的检查的场景也加这样的代码吗

  • 业务代码和功能代码分离了吗

  • 填充到应用上下文对象 user 合适吗

「大量魔法值,单行字符超500,方法长度拖几个屏幕也都睁一眼闭一只眼了,但整这一出,还是破防......」

内心涌动,我觉得要重构一下。

重构一下

困难之处

「在 mybatis intercept 中不能直接精准地获取到 service 层的接口调用。只能通过栈帧查询到调用链。」

问题列表

  • 尽量不要修改已有方法,保证不影响原有逻辑;

  • 尽量不要在业务方法中修改功能代码;关注点分离;

  • 尽量最小改动,修改一处即可实现逻辑;

  • 改造后复用能力,而不是依葫芦画瓢地添加这种代码

实现分析

用独立的 ThreadLocal,不与当前用户信息上下文混合使用

注解+APO,通过注解参数解析,达到目标功能

对于方法之间的调用或者循环调用,要考虑优化

「同一份代码,在多个环境运行,不管如何,一定要考虑线上数据安全性。」

使用案例

改造后的使用案例如下,案例说明:「project 表在预发环境校验跳过」 。

@SneakyThrows @GetMapping("/importSignedUserData") @InvokeChainSkipEnvRule(skipEnvList = {"pre"}, skipTableList = {"project"}) public void importSignedUserData(     ......     HttpServletRequest request,     HttpServletResponse response) {     ...... }

「在使用的调用入口处添加注解。」

具体实现

  1. 方法上标记注解, 注解参数定义规则

  2. 切面读取方法上面的注解规则,并传递到应用上下文

  3. 拦截器从应用上下文读取规则进行规则判断

注解代码

@Target({ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) public @interface InvokeChainSkipEnvRule {     /**      * 是否跳过环境。默认 true,不推荐设置 false      *      * @return      */     booleanisKip() defaulttrue;     /**      * 赋值则判断规则,否则不判断      *      * @return      */     String[]skipEnvList() default {};     /**      * 赋值则判断规则,否则不判断      *      * @return      */     String[]skipTableList() default {}; }

不足之处

  1. 整个链路上的这个表操作都会跳过,颗粒度还是比较粗

  2. 注解只能在入口处使用,公共方法调用尽量避免

那还要不要完善一下,还有什么没有考虑到的点呢?拿起手机看到快12点的那一刻,我还是选择先回家了......

总结思考

隔离总结

这是一个很好参考案例:在应用中既做了数据隔离,也做了数据共享。通过自定义拦截器做数据隔离,通过自定注解切面实现数据共享。

编码总结

「同样的代码写两次就应该考虑重构了」

  • 尽量修改一个地方,不要写这种边边角角的代码

  • 善用自定义注解,解决这种通用逻辑

  • 可以妥协,但是要有底线

场景总结

「简单梳理,自定义注解 + AOP 的场景」

自定义注解很灵活,应用场景广泛,可以多多挖掘。

反思总结

  • 如果一开始就做好技术方案或者直接使用不同的数据库

  • 是否可以拒绝那个所谓的需求

  • 先有设计再有编码,别瞎搞

最后感想

在这个只讲业务结果,不讲技术氛围的环境里,突然有一些伤感;身体已经开始吃不消了,好像也过了那个对技术较真死抠的年纪;突然一想,这么做的意义又有多大呢?

来源:https://juejin.cn/post/7294844864020430902

公众号“Java精选”所发表内容注明来源的,版权归原出处所有(无法查证版权的或者未注明出处的均来自网络,系转载,转载的目的在于传递更多信息,版权属于原作者。如有侵权,请联系,笔者会第一时间删除处理!

最近有很多人问,有没有读者交流群!加入方式很简单,公众号Java精选,回复“加群”,即可入群!

文章有帮助的话,点在看,转发吧!

特别声明:以上内容(如有图片或视频亦包括在内)为自媒体平台“网易号”用户上传并发布,本平台仅提供信息存储服务。

Notice: The content above (including the pictures and videos if any) is uploaded and posted by a user of NetEase Hao, which is a social media platform and only provides information storage services.

相关推荐
热点推荐
第6胎!理想汽车老板李想又要当爸爸了!妻子挺孕肚现身阿那亚,即将临盆

第6胎!理想汽车老板李想又要当爸爸了!妻子挺孕肚现身阿那亚,即将临盆

火山詩话
2026-08-02 05:29:42
菲方操作:法理基础全面崩塌之下……

菲方操作:法理基础全面崩塌之下……

新民周刊
2026-08-02 09:08:44
浙大副校长:“贪污”1.3亿入狱3年,为啥出狱后获国家支持2758万​

浙大副校长:“贪污”1.3亿入狱3年,为啥出狱后获国家支持2758万​

社会日日鲜
2026-08-02 09:30:32
莫斯科餐厅爆炸致3死:事发时正举行私人婚礼,运送炸弹女子或不知道包裹是炸弹,其告诉保安是礼物;俄将此案作为恐怖主义犯罪展开调查

莫斯科餐厅爆炸致3死:事发时正举行私人婚礼,运送炸弹女子或不知道包裹是炸弹,其告诉保安是礼物;俄将此案作为恐怖主义犯罪展开调查

极目新闻
2026-08-02 12:43:13
湖北电梯打人的宝妈已“社会性死亡”:名声没了,儿子也被牵连

湖北电梯打人的宝妈已“社会性死亡”:名声没了,儿子也被牵连

仙味少女心
2026-08-01 23:16:29
决裂到底!苏瑞彻底改母姓出道,阿汤哥终成最陌生的巨星父亲

决裂到底!苏瑞彻底改母姓出道,阿汤哥终成最陌生的巨星父亲

新民周刊
2026-08-02 13:13:52
朝鲜发生重大变化,金正恩做出决定,金珠爱“高调”亮相重要场合

朝鲜发生重大变化,金正恩做出决定,金珠爱“高调”亮相重要场合

张嘴说财经
2026-08-02 13:56:27
说句“电影难看”被扣上孙子,可怕吗?

说句“电影难看”被扣上孙子,可怕吗?

胖胖说他不胖
2026-08-02 04:16:38
西班牙休达“丧尸围城”,欧洲的“圣母婊们”求仁得仁了

西班牙休达“丧尸围城”,欧洲的“圣母婊们”求仁得仁了

百味朱砂
2026-08-01 14:55:21
太子集团“幕后大哥”胡小伟已离开日本,被遣送至美国

太子集团“幕后大哥”胡小伟已离开日本,被遣送至美国

红星新闻
2026-08-01 19:27:14
迈阿密国际2-2哥伦布机员,苏牙传射,卡塞米罗乌龙,梅西替补出场

迈阿密国际2-2哥伦布机员,苏牙传射,卡塞米罗乌龙,梅西替补出场

懂球帝
2026-08-02 10:14:12
8月2号,人社部财政部关于2026年调整退休人养老金通知,有没有公布?

8月2号,人社部财政部关于2026年调整退休人养老金通知,有没有公布?

小谈食刻美食
2026-08-02 08:35:43
“咖啡续命”实锤了?最新13年超35万人研究:长期喝黑咖啡,与更低肝脏脂肪、更少纤维化显著相关,新活性物质通过“控糖”从源头减负

“咖啡续命”实锤了?最新13年超35万人研究:长期喝黑咖啡,与更低肝脏脂肪、更少纤维化显著相关,新活性物质通过“控糖”从源头减负

华医网
2026-08-01 05:42:46
老年单身女人最难熬的日子是什么?67岁阿姨感慨:不是寂寞孤单

老年单身女人最难熬的日子是什么?67岁阿姨感慨:不是寂寞孤单

热心柚子姐姐
2026-08-01 15:19:43
“丈夫与第三者伪造结婚证做试管婴儿”当事人讲述维权之路:亲友统一口径劝我接受现实,坚持不光为自己,更希望曝光辅助生殖证件核查漏洞

“丈夫与第三者伪造结婚证做试管婴儿”当事人讲述维权之路:亲友统一口径劝我接受现实,坚持不光为自己,更希望曝光辅助生殖证件核查漏洞

大风新闻
2026-08-01 23:04:10
亲人遇交通事故受伤,5次住院治疗后家属坚持出院,结果出院次日死亡,家属未做尸检便将其遗体火化,保险公司:死因不明拒赔……法院判了

亲人遇交通事故受伤,5次住院治疗后家属坚持出院,结果出院次日死亡,家属未做尸检便将其遗体火化,保险公司:死因不明拒赔……法院判了

都市快报橙柿互动
2026-08-02 12:19:17
超强台风 “白海豚”或成今年“风王”!官方:关键在6日到8日前后,不要只盯登陆点

超强台风 “白海豚”或成今年“风王”!官方:关键在6日到8日前后,不要只盯登陆点

南方都市报
2026-08-02 09:48:43
万幸摊主没还手!砸瓜一家躲过鬼门关 网友:昆山正当防卫浮现脑海

万幸摊主没还手!砸瓜一家躲过鬼门关 网友:昆山正当防卫浮现脑海

离离言几许
2026-08-01 18:19:23
外媒:伊朗伊斯兰革命卫队称又摧毁3架美军F-35

外媒:伊朗伊斯兰革命卫队称又摧毁3架美军F-35

参考消息
2026-08-02 14:18:10
持续发酵!婚外胚胎案后续:丈夫反击,漂亮三姐正脸曝光,细节太讽刺

持续发酵!婚外胚胎案后续:丈夫反击,漂亮三姐正脸曝光,细节太讽刺

小鋭有话说
2026-08-02 13:42:34
2026-08-02 16:20:49
Java精选
Java精选
一场永远也演不完的戏
1797文章数 3859关注度
往期回顾 全部

科技要闻

零跑月销10万破纪录!比亚迪奇瑞海外卖爆

头条要闻

男子买到破损游泳"跟屁虫" 退货遭怼"几十块保你啥命"

头条要闻

男子买到破损游泳"跟屁虫" 退货遭怼"几十块保你啥命"

体育要闻

1米76的他,为什么是史上最强中卫之一?

娱乐要闻

一天5瓜!“做头发”事件另有玄机?

财经要闻

长鑫科技四万亿市值背后的资本与周期

汽车要闻

历史性里程碑时刻 零跑7月交付达101267台

态度原创

时尚
家居
旅游
手机
数码

伊姐周六热推:电视剧《御廷谣》;电视剧《九门》......

家居要闻

2026建博会(广州) 公装联探展交流活动

旅游要闻

湖南张家界:清凉避暑引客来

手机要闻

绿厂首款万级大电池手机 OPPO A7 Pro Max挑战2000℃火箭发射尾焰冲击

数码要闻

泰坦军团推出T500 PRO显示器支架臂:最大承重12kg,299元

无障碍浏览 进入关怀版