AutoWire可以注入列表和字典

目前我们业务代码里有一种常见的模式,定义一个接口,接着通过多个handler类实现这个接口, 在面对不同的情况时通过调用不同的handler类来处理业务代码,通常这些handler类都会继承一个公用的父类,父类中会有一些公共的方法。 本文不讨论这种模式的合理性,单纯从技术角度分析实现的方案。因为在Java生态下,都是使用spring框架。所以之前的业务代码中都会把这些handler做成bean,而如何使用这些bean,实现方案千奇百怪。有交给spring ioc容器管理后,自行从context中根据bean name获取的。也有手动注入到一个大map中的。 其实官方文档里指出里Autowired注解是可以自动注入map和list的,这句话有点奇怪,我还是直接show code吧。 我使用的java版本是 openjdk 21.0.2 2024-01-16 OpenJDK Runtime Environment (build 21.0.2+13-58) OpenJDK 64-Bit Server VM (build 21.0.2+13-58, mixed mode, sharing) 对于使用spring的ioc容器和bean而言,只需要spring-context依赖即可。 <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>6.1.4</version> </dependency> 首先我们定义一个接口IMan和它的两个字类Teacher和Student, 为了方便我们不加入额外的逻辑和属性 public interface IMan {} public class Teacher implements IMan{} public class Student implements IMan{} 我们在实现一个ClassRoom类,该类使用@AutoWried注解注入一个元素类型为IMan的list和一个key为String, Value类型为IMan的map public class ClassRoom { @Autowired IMan[] people; @Autowired Map<String, IMan> categories; } 同时,使用xml配置自动装配和相关的bean <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www....

February 23, 2024 · 1 min

993. 二叉树的堂兄弟节点

题目 在二叉树中,根节点位于深度 0 处,每个深度为 k 的节点的子节点位于深度 k+1 处。 如果二叉树的两个节点深度相同,但 父节点不同 ,则它们是一对堂兄弟节点。 我们给出了具有唯一值的二叉树的根节点 root ,以及树中两个不同节点的值 x 和 y 。 只有与值 x 和 y 对应的节点是堂兄弟节点时,才返回 true 。否则,返回 false。 卡点 这道题我想到了使用bfs遍历树并且去记录深度,但有两点未思考到 深度记录的方式应该是和节点绑定,即每个节点应该有自己的深度变量。我试图通过一个变量记录深度,结果难以通过队列的变化确定(应该可以通过遍历前记录队列中节点数量,然后for循环遍历完成后对全局深度+1) dfs和bfs都可以在遍历前去获取到父节点信息,而且是要在对节点进行操作之前,bfs是在入队列前,而我在思考的时候是思考的节点进入队列后如何判断它的父节点。当然这里也可以判断,如果我不使用队列,而是使用一个数据,元素不停的加入,而元素的pop是通过移动一个队首的指针完成,那么我就可以通过下标运算得到父节点的值,但这样内存消耗会大一些。 答案 # Definition for a binary tree node. # class TreeNode: # def __init__(self, val=0, left=None, right=None): # self.val = val # self.left = left # self.right = right # dfs class Solution: def isCousins(self, root: Optional[TreeNode], x: int, y: int) -> bool: queue = [] queue....

February 8, 2024 · 1 min

记录一下我Mac上安装的一些工具

全局包管理工具 brew python (system) pyenv(install by brew) echo 'export PYENV_ROOT="$HOME/.pyenv"' >> ~/.zshrc echo '[[ -d $PYENV_ROOT/bin ]] && export PATH="$PYENV_ROOT/bin:$PATH"' >> ~/.zshrc echo 'eval "$(pyenv init -)"' >> ~/.zshrc poetry(install by brew) poetry install poetry env remove 3.12 go (install with official installer) warp (终端)

February 8, 2024 · 1 min

python3.12安装numpy1.25.2不兼容问题

• Installing numpy (1.25.2): Failed ChefBuildError Backend 'setuptools.build_meta:__legacy__' is not available. Traceback (most recent call last): File "/opt/homebrew/Cellar/poetry/1.7.1/libexec/lib/python3.12/site-packages/pyproject_hooks/_in_process/_in_process.py", line 77, in _build_backend obj = import_module(mod_path) ^^^^^^^^^^^^^^^^^^^^^^^ File "/opt/homebrew/Cellar/python@3.12/3.12.1_1/Frameworks/Python.framework/Versions/3.12/lib/python3.12/importlib/__init__.py", line 90, in import_module return _bootstrap._gcd_import(name[level:], package, level) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "<frozen importlib._bootstrap>", line 1387, in _gcd_import File "<frozen importlib._bootstrap>", line 1360, in _find_and_load File "<frozen importlib._bootstrap>", line 1310, in _find_and_load_unlocked File "<frozen importlib._bootstrap>", line 488, in _call_with_frames_removed File "<frozen importlib._bootstrap>", line 1387, in _gcd_import File "<frozen importlib....

February 4, 2024 · 2 min

vscode-godot-配置

.vscode/lanch.json { // Use IntelliSense to learn about possible attributes. // Hover to view descriptions of existing attributes. // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 "version": "0.2.0", "configurations": [ { "name": "GDScript Godot", "type": "godot", "request": "launch", "project": "${workspaceFolder}", "port": 6007, "address": "tcp://127.0.0.1", "launch_game_instance": true, "launch_scene": false } ] } .vscode/settings.json { "godot_tools.editor_path": "/Applications/Godot.app/Contents/MacOS/Godot", "godot_tools.gdscript_lsp_server_port": 6005, }

January 14, 2024 · 1 min

海的信徒

我生在海边 但一生只见过一次大海 我的母亲提醒我 “不要开口” 推开车门海边的喧嚣闯入我被匆匆挤出 海浪扑打瞳孔中蓝色沸腾我匆忙捂住嘴巴 不要 开口 堤坝空荡没有过客 世界很大,呼啸的海风将每个人隔绝 海在轰鸣 我松开双手,向海吼叫 海风带走我发出的每一句声响

January 7, 2024 · 1 min

双十一线上事故复盘

事故一 背景: 服务old一个前后端不分离的老项目,服务new是一个前后端分离的新服务。部分功能从服务old迁移到服务new,采用了请求重定向的方式,前端请求服务old的老接口后重定向到新服务。 现象: 大促前5分钟,应用tp99,tp999开始有个别报警超时,tp999响应时间超过20s。 事故二 经验: 永远不相信任何服务提供方,永远不强依赖服务提供方。 熔断、降级 熔断机制: 对R2M依赖过强,当R2M出现不可用了,实名没有熔断机制。 合理的设计应该是,假如分布式缓存服务不可用,则启用本地缓存并使用LRU机制,放弃峰值TPS和一定的成功率保证服务可用。 降级: 任何一个服务都要提供日志降级方式(这里又要引入熔断机制,假如依赖的动态配置服务挂了,那么所有的配置项应该启用默认配置,并且该配置应该是优先保证服务可用,可以牺牲可观察性,牺牲服务能力)

November 4, 2023 · 1 min

软件工程实践指南

本文记载我在软件工程实践过程中总结的经验 1、在生产环境为测试环境的凭证设置特殊报错 在实际开发过程中,我们可能会有各种各样的环境,这些环境可能会提供给业务方使用。我们的工程中经常会有权限校验操作,在测试环境为了方便可能会给业务方分配一个统一的凭证,而生产环境会分配单独的凭证。如果是这样,那么建议生产环境校验时为这个特殊凭证单独设置错误提示,以通知用户错误的将测试环境的凭证用于生产环境。 2、不要为pin等字段设置默认值 用户会使用pin,而有的时候我们会想要获取这些pin做日志等分析处理,如果获取不到这些pin应该使用null标记这些字段,而不是设置“unknown”等默认字段,因为客户可能会使用这些字段作为pin。 3、预防型捕获异常可以有,但是一定要在日志中指出是意料之外的异常 在业务导向比较强的代码中,可以在一些不必加try catch的地方显示捕获异常。因为一些代码在业务导向强的项目中属于边缘代码,比如埋点、日志等,对于一些业务比如个人实名来说这些代码可以失败但不能阻塞流程。预防性try catch能保证这部分代码不出问题,但是我无法保证同事或者其他中间件等

October 13, 2023 · 1 min

使用Spring自动注入时必须使用构造函数注入方式!

https://docs.spring.io/spring-framework/docs/5.3.25/reference/html/core.html#spring-core The Spring team generally advocates constructor injection, as it lets you implement application components as immutable objects and ensures that required dependencies are not null. Furthermore, constructor-injected components are always returned to the client (calling) code in a fully initialized state. As a side note, a large number of constructor arguments is a bad code smell, implying that the class likely has too many responsibilities and should 技术角度上说,依赖注入可以有field注入,setter注入方式和构造函数注入方式。技术角度上看,构造函数的优势在于保证返回的bean是完整的,且bean中依赖的其他类不为空。 然而在实际生产过程中,spring官方给的技术优势大部分开发并不关注,还是直接写一个域然后标一个autowired。...

September 19, 2023 · 1 min

翻译】每个开发者都必须了解的unicode和character sets(字符集)知识点

原文地址:https://www.joelonsoftware.com/2003/10/08/the-absolute-minimum-every-software-developer-absolutely-positively-must-know-about-unicode-and-character-sets-no-excuses/ 你有没有想过content-type这个Tag是做什么的?就是当你写HTML时应该写的但是你从来不知道应该填什么的content-type。 Content-Type: text/html; charset=utf-8 Content-Type: multipart/form-data; boundary=something 你有没有收到过一份邮件里面有一行“????????????“ 我惊讶地发现有太多的开发者并不了解character sets, encodings, Unicode这些东西。 几年前,一个测试问我FogBUGZ(译者注:可能是原作者开发的一个软件)能不能用日语处理收到的邮件。日语?他们有用日语写的邮件?我完全没想过这回事。当我们仔细检查用来解析MIME邮件的商用版ActiveX control时,我们发现它确实错误处理了字符集(character sets),所以我们不得不写了一份代码去回滚它的错误并且重新对邮件进行解析。当我去看另一个商用版库的源代码时,我发现它的字符代码实现也非常差劲。我联系了这个包的开发者,他说他“对这个包也做不了更多的事“。就像很多程序员一样,他只想这件事就这样过去得了。 但是这件事不会就这样过去!当我发现主流的web开发工具PHP竟然有一个完全忽视字符集编码的issue(complete ignorance of character encoding issues),blithely使用了8个bit处理字符(characters),导致他妈的几乎不可能拿php开发出好的互联网应用。我觉得,这一切都该结束了。 在此我宣誓:如果你是一个在2003年工作的程序员,而你不知道characters, character sets, encodings和Unicode的基础知识。假设你被我逮着了,那我就要惩罚你在潜艇里切6个月洋葱。我发誓我会这样做的。 还有一件事: 它没有那么难。 在本文我将告诉你每一个在职程序员都应该知道的基础知识。“普通文本等于ASCII等于字符(characters)都是8比特的”这种想法,不仅是错误的,而且是非常错误的。如果你还带着这种想法编程,那你差不多相当于一个不懂细菌的医生。求你在没读完这篇文章前不要再写任何一行代码了。 在开始之前,我有一个提醒,如果你是那种比较罕见的懂国际化(internationalization)的人,你会发现我接下来的讨论有点过于简单了。我只想把最简单的教给大家,这样每个人都知道发生什么事了,并且能编写可以处理各种语言的代码而不是只有英语(甚至不能带重读符号)。我还要提醒你,字符处理知识创建国际化软件的一小部分,我有时间可以写点其他方面的,但今天我们只讲字符集(character sets)。 历史角度 了解一件事情最简单的方式就是跟着时间了解它。 你可能认为我会讲一些上古时期的字符集(character sets)比如EBCDIC。但是我不会。EBCDIC跟你的生活一点关系也没有。我们不会讲这么远的事。 在中古时期,当Unix被发明出来而K&R正在写《The C Programming Language》的时候,一切都很简单。EBCDIC正在退出历史舞台了。唯一需要处理的字符是哪些不带重音的英文字母。我们有一套叫做ASCII的编码可以用32到127之间的数据代表每一个字符。空格是32,字母‘A’是65,诸如此类。这些数字可以很方便地用7个比特存储下来。那时候大部分电脑都是用8bit的字节(8-bit bytes), 所以你不仅可以存下每一个ASCII字符,你还多出来整整1个bit。如果你耍点小聪明,这1个比特可以用于自己的目的。WordStar中的那群傻瓜就把最高位用于表示每个单词的最后一个字母,导致WordStar只能打印英语。用小于32的数字表示的字符是无法打印的(unprintable),被用于诅咒别人。开个玩笑。它们被当作控制字符使用(control characters),比如7会让计算机蜂鸣,12会导致打印机上的当前纸张飞出,让新纸填入。 这一切都很美好,如果你是一个英语使用者的话。 因为每个字节使用了8个比特,许多人就想到,“我们可以把128-255的数字给自己用”。问题在于很多人同时有了相同的想法,而且他们对于128到255的数字的用法都有自己独特的想法。IBM-PC 有一些后来被称为 OEM 字符集的东西,它为欧洲语言提供了一些重音字符和一系列线条绘制字符… … 水平条、垂直条、右边有小铃铛悬挂的水平条等等。 你可以用这些线条字符在屏幕上画好看的盒子和直线,用这些字符集画的画你仍然能在你的干洗机上的8088电脑上看到。事实上,当人们开始在美国以外购买个人电脑时,各种不同的OEM字符集就被设想出来了,这些字符集都是为了自己的目的而使用前128个字符。比如130在一些电脑上会被显示为é,但是在以色列售卖的电脑会将130显示为希伯来语Gimel(译者注:原文的字符打不出来),所以当美国人发送résumés到以色列时,以色列人会收到r(Gimel)sum(Gimel)s。在很多情况下,比如在俄罗斯,关于如何使用前128个字符有非常多的想法,所以交换两个俄语文档都是可能有问题的。 这种OEM混战的情况最终被ANSI标准敲定下来。在ANSI标准中,大家对小于128的数字该做什么都取得了一致认知,这点很像ASCII,但是从128开始的数字根据你所在的地区不同就有很多不同的方式处理了。这些不同的处理系统叫做*code pages。*比如以色列的DOS用的code page叫做862, 而希腊人使用的是737。小于128都是一样的,但是从128开始都完全不同了,而很多有趣的字母就出现在128之上(包括128)。MS-DOS的国际化版本有许多code page, 这些code page能处理各种语言,从英语到冰岛语,它们甚至还有一些多语言(multilingual)的code page可以同时在一台电脑上处理世界语和加利西亚语。哇!但是,在同一台计算机上同时显示希伯来语和希腊语是完全不可能的,除非你编写自己的自定义程序,使用位图图形显示所有内容,因为希伯来语和希腊语需要不同的代码页,对大数有不同的解释。 与此同时,亚洲的有成千上万的文字(letter),这些文字用8个比特是不可能装的下的。有一种糟糕的系统叫做DBCS(double byte character set)用来解决这类问题。在DBCS中,一些文字用1个字节存储,而另一些则使用两个字节存储。在字符串中向前移动很容易,但向后移动却几乎不可能。我们鼓励程序员不要使用 s++ 和 s- 来前后移动字符串,而是调用 Windows 的 AnsiNext 和 AnsiPrev 等函数,它们知道如何处理整个混乱的字符串。...

August 1, 2023 · 2 min