学习源码的第八个月,我成了Spring的开源贡献者
@
我的经历
关注我的朋友都知道,关注两个字划重点,要考!

我最近一直在写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
resolveConstructorArgumentsis 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
resolveConstructorArgumentsmethod 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中已经接受我的建议。
所以我要说的就是,
真正动手的话,不管什么问题总能找到解决方案
而只是停留在空想,在踌躇,你永远有一堆问题
临渊羡鱼,不如退而结网
以此文与君共勉!
如果本文对你由帮助的话,记得点个赞吧!也欢迎关注我的公众号,微信搜索:程序员DMZ,或者扫描下方二维码,跟着我一起认认真真学Java,踏踏实实做一个coder。

我叫DMZ,一个在学习路上匍匐前行的小菜鸟!
本文由博客群发一文多发等运营工具平台 OpenWrite 发布
学习源码的第八个月,我成了Spring的开源贡献者的更多相关文章
- 框架源码系列五:学习源码的方法(学习源码的目的、 学习源码的方法、Eclipse里面查看源码的常用快捷键和方法)
一. 学习源码的目的 1. 为了扩展和调优:掌握框架的工作流程和原理 2. 为了提升自己的编程技能:学习他人的设计思想.编程技巧 二. 学习源码的方法 方法一: 1)掌握研究的对象和研究对象的核心概念 ...
- libevent源码深度剖析八
libevent源码深度剖析八 ——集成信号处理 张亮 现在我们已经了解了libevent的基本框架:事件管理框架和事件主循环.上节提到了libevent中I/O事件和Signal以及Timer事件的 ...
- springboot学习源码
springbootTest 学习源码链接 启动前,需要创建数据库表,修改自己的链接配置 create database test01; use test01; CREATE TABLE catego ...
- NLP大赛冠军总结:300万知乎多标签文本分类任务(附深度学习源码)
NLP大赛冠军总结:300万知乎多标签文本分类任务(附深度学习源码) 七月,酷暑难耐,认识的几位同学参加知乎看山杯,均取得不错的排名.当时天池AI医疗大赛初赛结束,官方正在为复赛进行平台调 ...
- netty源码分析(十八)Netty底层架构系统总结与应用实践
一个EventLoopGroup当中会包含一个或多个EventLoop. 一个EventLoop在它的整个生命周期当中都只会与唯一一个Thread进行绑定. 所有由EventLoop所处理的各种I/O ...
- Netty 源码解析(八): 回到 Channel 的 register 操作
原创申明:本文由公众号[猿灯塔]原创,转载请说明出处标注 今天是猿灯塔“365篇原创计划”第八篇. 接下来的时间灯塔君持续更新Netty系列一共九篇 Netty 源码解析(一): 开始 Netty 源 ...
- 【转】python:让源码更安全之将py编译成so
python:让源码更安全之将py编译成so 应用场景 Python是一种面向对象的解释型计算机程序设计语言,具有丰富和强大的库,使用其开发产品快速高效. python的解释特性是将py编译为独有的二 ...
- python 协程库gevent学习--源码学习(一)
总算还是要来梳理一下这几天深入研究之后学习到的东西了. 这几天一直在看以前跟jd对接的项目写的那个gevent代码.为了查错,基本上深入浅出了一次gevent几个重要部件的实现和其工作的原理. 这里用 ...
- 06.ElementUI 2.X 源码学习:源码剖析之工程化(一)
0x.00 前言 在用了5章篇幅 ElementUI源码学习:从零开始搭建Vue组件库汇总 讲解了如何编写一个组件.发布npm以及生成展示文档之后.接下来将分析Element项目的代码结构,学习其工程 ...
随机推荐
- C# 基础知识系列- 17 小工具优化
0. 前言 不知道有没有动手能力强的小伙伴照着上一篇的内容写过程序呢?如果有的话,应该会在使用的时候发现以下几个问题: 每次启动都需要经过漫长的时间去遍历磁盘里的文件目录 因为数据是用的字典保存的,所 ...
- JavaWebCase
目录 案例:用户登录 用户登录案例需求 分析 开发步骤 创建项目 创建数据库环境 创建包 com.my.domain,创建类User 创建包 com.my.dao,创建类UsesrDao,提供logi ...
- Code::Blocks无法调试 Starting the debuggee failed: No executable specified, use `target exec'
1.必须建立工程 2.工程名不可有特殊字符或空格,可以有字母.数字.下划线 2.编译器设置里勾选-g(产生调试符号) 3.重新编译项目(如果之前编译过了) 4.调试器设置 > Default & ...
- 使用PXE+Kickstart无人值守安装服务
一. 配置DHCP服务程序 1) 按照图在虚拟机的虚拟网络编辑器中关闭自身的DHCP服务. 2) 当挂载好光盘镜像并把Yum仓库文件配置妥当后,就可以安装DHCP服务程序 ...
- ocaml 和coq 安装
安装opam 参考官网安装步骤即可,比如对于centos系统,以root用户执行如下指令 cd /etc/yum.repos.d/ wget http://download.opensuse.org/ ...
- [hdu1847]博弈,推理
题意:一堆石子,有n个,两个人轮流取,每次都只能取2的幂次方个数,不能取的人输 思路:首先0是必败态,2的所有幂次都是必胜态.由于选的数模3只能是1或2,恰好又都是2的幂次,0,.3都为必败态,猜想3 ...
- C#winform跨窗体传值和调用事件的办法
有三个窗体,分别是Main主窗体,Form1窗体1,From2窗体2,其中Main是主窗体,Form1窗体1是一个消息通知窗体,Form2窗体2主窗体的一个子窗体,程序启动时,消息框窗体1弹出,通过消 ...
- 枚举:Enum-Int-String之间的转换与扩展
示例枚举: public enum Color { [Description("红色")] Red, [Description("绿色")] Green = 7 ...
- react+express实现跨域
1. 首先复习一下跨域的几种主要方式: a. jsonp b. cors c. 代理服务(开发环境下常用) 2. 代理服务器:可实现转发请求.即浏览器在3000端口发出请求,通过代理转发,将请求发送给 ...
- P3254 圆桌问题 网络流
P3254 圆桌问题 #include <bits/stdc++.h> using namespace std; , inf = 0x3f3f3f; struct Edge { int f ...