天天看點

學習源碼的第八個月,我成了Spring的開源貢獻者 ----《我和開源的故事》我的經曆碰到的問題給你的建議

學習源碼的第八個月,我成了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;
}           

當發現這個問題的時候,第一反應就是肯定是我的姿勢不對,錯的怎麼可能是代碼,肯定是我!

學習源碼的第八個月,我成了Spring的開源貢獻者 ----《我和開源的故事》我的經曆碰到的問題給你的建議

接下來,我就對這段代碼進行了慘無人道的調試,在無數次

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時主要是按照這種思路

  1. 首先擺出有問題的代碼
  2. 描述具體的問題,我是直接通過一個例子來描述的
  3. 說出自己的建議

這幾天我又多看了看别人送出的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上。但是千萬千萬不要使用中文,就像下面這個哥們

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,一個在學習路上匍匐前行的小菜鳥!