三分钟读懂spring源码(怒肝8个月源码)
三分钟读懂spring源码(怒肝8个月源码)我先说说我自己的经历吧,在创作上篇文章的时候,笔者发现 Spring 在实例化对象的时候有这么一段代码,在org.springframework.beans.factory.support.ConstructorResolver#resolveConstructorArguments方法中:经历我最近一直在写Spring的文章,而且仅仅是 Spring FrameWork 的文章 从最开始的官网入门到现在源码的深度分析。主要就是三个系列:本文的主要目的是教(zhuang)学(bi)。就是从笔者的实际经验出发,谈一谈怎么成为一个开源项目的贡献者。
作者 | cxuan
来源 | 程序员cxuan
责编| 王晓曼
前言
我最近一直在写Spring的文章,而且仅仅是 Spring FrameWork 的文章 从最开始的官网入门到现在源码的深度分析。主要就是三个系列:
- 官网入门系列,Spring官网读书笔记,这一系列的文章是入门spring的不二之选,也是后续源码阅读的基础。
- 杂谈系列,Spring杂谈,这主要是一些补充内容,可以帮助大家更全面学习到Spring中的各个知识点,同时也会分享一些源码阅读技巧,个人学习心得之类的,杂谈嘛,就是不知道放哪里的文章都打算放这里,比如这篇文章。
- 源码分析系列,Spring源码解析,该专栏目前正在创作中,相对而言学习难度比较大,而且因为笔者写的比较细,估计大部分同学看起来会很费劲,不过如果你能认真看完,收获绝对巨大!
本文的主要目的是教(zhuang)学(bi)。
就是从笔者的实际经验出发,谈一谈怎么成为一个开源项目的贡献者。
经历
我先说说我自己的经历吧,在创作上篇文章的时候,笔者发现 Spring 在实例化对象的时候有这么一段代码,在org.springframework.beans.factory.support.ConstructorResolver#resolveConstructorArguments方法中:
// 本文不探讨技术细节,只是为了简单说明这个问题,所以省略无关代码
private int resolveConstructorArguments(String beanName RootBeanDefinition mbd BeanWrapper bw
ConstructorArgumentValues cargs ConstructorArgumentValues resolvedValues) {
// ....
for (Map.Entry<Integer ConstructorArgumentValues.ValueHolder> entry : cargs.getIndexedArgumentValues.entrySet) {
int index = entry.getKey;
if (index < 0) {
throw new BeanCreationException(mbd.getResourceDescription beanName
"Invalid constructor argument index: " index);
}
// 问题就出在这里
if (index > minNrOfArgs) {
minNrOfArgs = index 1;
}
// .....
上述代码中,minNrOfArgs 这个变量就是保存方法需要的最小参数个数,但是index是下标索引,索引是从0开始的,如果有下标为n的元素,那么最小的参数个数应该是n 1嘛,所以if中的逻辑是没有问题的,但是if这个判断是有问题的,正确的做法应该是:
if (index 1 > minNrOfArgs) {
minNrOfArgs = index 1;
}
这个问题的时候,第一反应就是肯定是我的姿势不对,错的怎么可能是代码,肯定是我!
调试
接下来,我就对这段代码进行了惨无人道的调试,在无数次 debug 后,我发现,这个地方确实有问题!
在确认了这个问题之后,我要思考的就是怎么把自己的想法反馈给 Spring ,换而言之,怎么为伟大的开源来做贡献呢?正常来要达到这个目的有两个方式:
-
提交 issue;
-
直接在 GitHub 上提交 PR(pull request)。
对应的就是在 GitHub 上点击下图红框选中的两个位置。
如果是使用提交 issue 的方式,相当于给官方团队提交了一个议题,这个议题可能是你发现代码中的某个 bug,也可能是你觉得官方的做法不够好,你有更好的想法等等。
感兴趣的话,大家可以去看看 Spring 中现在有哪些还未关闭的 issue,说不定其中一个你就能解决呢!
如果要采用提交 PR 的方式的话,首先你得将代码 fork 到自己的 GitHub 中,然后再从自己的 GitHub 检出到本地,在本地做完修改后,提交到 GitHub 仓库中,最后从自己的 GitHub 向 Spring 官方仓库发起一个 PR。
像我的话很早就已经将代码 fork 到了自己 GitHub。
上图中的第一个红框,说明我这个仓库是从 Spring 官方 fork 过来的,第二个红框就是可以从这里向 Spring 官方提交一个 PR。
关于详细的如何提交 PR,大家可以自行百度,这里不做详细的介绍了。
另外,说了这么多,先给大家看下我提交的 issue 吧。
issue链接:https://github.com/spring-projects/spring-framework/issues/25130
因为内容也不长,所以我这里把原文就直接放到下面了:
In ConstructorResolver:
private int resolveConstructorArguments(String beanName RootBeanDefinition mbd BeanWrapper bw
ConstructorArgumentValues cargs ConstructorArgumentValues resolvedValues) {
TypeConverter customConverter = this.beanFactory.getCustomTypeConverter;
// ...
for (Map.Entry<Integer ConstructorArgumentValues.ValueHolder> entry : cargs.getIndexedArgumentValues.entrySet) {
int index = entry.getKey;
if (index < 0) {
throw new BeanCreationException(mbd.getResourceDescription beanName
"Invalid constructor argument index: " index);
}
if (index > minNrOfArgs) {
minNrOfArgs = index 1;
}
// ....
}
// ....
return minNrOfArgs;
}
I assume that method resolveConstructorArguments is to resolve contructor arguments in the XML file and return the minimum number of parameters required by contructor. But if the first parameter is autowired the second parameter is config by XML file,the method will not work well.
Example:
public class FactoryObject {
public Dmzservice getDmz(String name int age Date birthDay OrderService orderService) {
public DmzService getDmz(OrderService orderService String name) {
return new DmzService(orderService name);
}
}
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"
default-autowire="constructor">
<bean id="factoryObject" class="com.dmz.spring.first.instantiation.service.FactoryObject"/>
<bean class="com.dmz.spring.first.instantiation.service.OrderService" id="orderService"/>
<bean id="dmzService" factory-bean="factoryObject" factory-method="getDmz">
<constructor-arg index="1" value="dmz"/>
</bean>
</beans>
The resolveConstructorArguments method will return 1 but correct answer is 2.
I think the problem arises because of this judgment:
if (index > minNrOfArgs) {
minNrOfArgs = index 1;
}
It might be better to change it to look like this.
if (index 1 > minNrOfArgs) {
minNrOfArgs = index 1;
}s
思路
我在提交 issue 时主要是按照这种思路:
-
首先摆出有问题的代码;
-
描述具体的问题,我是直接通过一个例子来描述的;
-
说出自己的建议。
这几天我又多看了看别人提交的issue,对比起来,我觉得至少应该还要添加一点:应该要明确的指出具体哪个版本上出现的问题。
碰到的问题
1、担心闹乌龙
虽然在之前我已经调试过了无数次代码,但是心里还是没谱啊。毕竟我这么谨(cai)慎(ji)的一个人,万一被人喷了怎么办?不知道你会不会这么想,反正我当时就是这么想的,如果你是这么想的,建议你去看看别人提交的 issue。搜索条件如下:
is:closed label:"status: invalid"
我觉得你看几个,自然就有信心了!
2、不知道要怎么提交
每个开源的项目,只要作者希望这个项目越来越好的话,都会详细的说明如何给这个项目做开源贡献,Spring肯定也不例外,这里还是以提交 issue 为例,当你点击 New issue 的时候会出现下面这张图:
在上图左边的框里很明确的告诉了你提交issue应该要注意什么:
-
首先,你应该要去 Stack Overflow 提问;
-
如果是 bug,你应该要指明版本以及你想要做什么;
-
如果是一个增强的话,要提供上下文并且描述清楚问题;
-
同一个问题,issue 跟 PR 最好只提交一个,因为 GitHub 认为它们是一样的,如果你还不能确定的话,先提交一个 issue。
而右上角还有更加详细的文档可供参考。
3、英文
大家应该看到了,整个 issue 都是用英文写的,那么英文不好怎么办呢?这个时候就要掏出我们的神器了:
嗯,就是词典,笔者习惯是使用有道词典。我建议英文不好的同学可以这样,先将整个 issue 用中文写好,如果你真的英文一窍不通的话,可以直接通过翻译软件逐句翻译,然后粘贴到 GitHub 上。但是千万千万不要使用中文,就像下面这个哥们:
issue 链接:https://github.com/spring-projects/spring-framework/pull/25127
像这种 issue 是会被直接打上 invalid(不合格)标签的,你就想想吧,你学不会英文,你指望我们的外国朋友能看懂中文嘛?是我中华上下五千年的文化不够博大精深吗?
4、担心问题描述的不清楚
其实这个问题就是因为英文不好衍生出来的。因为英文不好,自然就会担心我写的东西他能不能看懂呢?我的建议就是,结合你测试的代码去描述问题。你不用去担心别人看不懂你写的代码,就以我那个 issue 的处理流程为例吧。
在你刚刚提交 issue 时,有专门的 issuemaster (issue管理员)会给你提交的 issue 打上一个 wait-for-triage 的标签,标志这个 issue 是待处理的。
随后我提交的这个 issue,就被指派给了 jhoeller 。你要担心他看不懂代码吗?给你看两个东西吧。
你知道那个红框是啥意思吗?就是说我发现的那个有问题代码的类的作者就是他。
再看一张:
就是说,jhoeller 从 2003 年开始就已经是 Spring 这个项目的管理者以及发布经理了。2003 年,我还是一个小学生........
所以啊,只要你稍微正常点,基本上人家都能 get 到你的点。
建议
其实笔者从发现这个问题到最终提交 issue 大概经过了一周时间,期间一直在犹豫要不要提交 issue,就是因为上面提到的几个问题,一直踌躇不前。
但是等我下定决心要去做这件事的时候总共就花了几个小时的时间。包括研究issue 提交的规则以及写一篇英文版的 issue,并且我提交 issue 的第二天就马上被处理了,并且 jhoeller 在 f9aae8d 这个 commit 中已经接受我的建议。
所以我要说的就是,
真正动手的话,不管什么问题总能找到解决方案!
而只是停留在空想、在踌躇,你永远有一堆问题。
临渊羡鱼,不如退而结网。
以此文与君共勉!
☞阿里云科学家入选计算机顶会 HPCA 名人堂,他是什么来头?
☞屏保壁纸引发血案,三星手机瞬间变砖
☞可怕!CPU 竟成了黑客的帮凶
☞Gary Marcus:因果熵理论的荒诞和认知科学带给AI的11个启示 | 文末赠书
☞这 10 个云计算错误,会让你的业务一蹶不振
☞好扑科技结合区块链行业发展趋势,重磅推出“好扑区块链合伙人”计划