如何看Spring原始碼

lawt發表於2019-05-08

想要深入的熟悉瞭解Spring原始碼,我覺得第一步就是要有一個能跑起來的極盡簡單的框架,下面我就教大家搭建一個最簡單的Spring框架,而且是基於Java Config形式的零配置Spring框架。

首先第一步建立一個空的maven web專案,這步很簡單,自行百度。

在maven專案的pom.xml檔案中新增Spring基礎依賴:

<properties>
            <spring.version>4.3.7.RELEASE</spring.version>
            <slf4j.version>1.7.21</slf4j.version>
            <log4j.version>2.8.2</log4j.version>
            <logging.version>1.2</logging.version>
        </properties>

        <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-framework-bom</artifactId>
                <version>${spring.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-beans</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aop</artifactId>
        </dependency>

        <!-- log配置:Log4j2 + Slf4j -->
        <dependency>
            <groupId>org.apache.logging.log4j</groupId>
            <artifactId>log4j-api</artifactId>
            <version>${log4j.version}</version>
        </dependency>
        <dependency>
            <groupId>org.apache.logging.log4j</groupId>
            <artifactId>log4j-core</artifactId>
            <version>${log4j.version}</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/org.apache.logging.log4j/log4j-web -->
        <dependency>
            <groupId>org.apache.logging.log4j</groupId>
            <artifactId>log4j-web</artifactId>
            <version>${log4j.version}</version>
        </dependency>
        <dependency> <!-- 橋接:告訴Slf4j使用Log4j2 -->
            <groupId>org.apache.logging.log4j</groupId>
            <artifactId>log4j-slf4j-impl</artifactId>
            <version>${log4j.version}</version>
        </dependency>
        <dependency> <!-- 橋接:告訴commons logging使用Log4j2 -->
            <groupId>org.apache.logging.log4j</groupId>
            <artifactId>log4j-jcl</artifactId>
            <version>${log4j.version}</version>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
            <version>${slf4j.version}</version>
        </dependency>

    </dependencies>

我推薦搭建基於Java Config形式的Spring框架,不需要配置檔案,全部使用Java程式碼形式來定義,簡潔明瞭,對於想要深入瞭解Spring原始碼來說這點很重要,否則可能需要看非常多的Spring解析XML配置檔案的解析類,對於任何人都不是很容易的功夫。而使用Java Config形式能直接看到配置類的執行流程,對了解Spring原始碼很有幫助。

要搭建基於Java Config形式的Spring框架,要求Servlet-api版本3.0以上,同時推薦Spring版本4.0以上,日誌可以使用我另一篇部落格上的log4j2的配置,自己修改下輸出日誌檔案路徑就可以了。

public class WebContextInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
    @Override
    protected Class<?>[] getRootConfigClasses() {
        return new Class<?>[] {RootContextConfig.class};
    }
}

@Configuration
@ComponentScan
public class RootContextConfig {
    @Bean
    public Child child() {
        return new Child();
    }
}
public class Child {
}

@Component
public class Mother {
}

把這幾個類都放在一個包下,然後啟動tomcat,應該就可以啟動Spring了,這就是一個最基本的Spring框架,而且包含了Java Config的Bean的定義以及元件掃描,RootContextConfig這個類就是容器的配置類,之後就可以開始跟著Spring框架的啟動流程看了,DEBUG跟著一步一步的走。

WebContextInitializer 的父類的將RootContextConfig 當做配置類生成一個AnnotationConfigWebApplicationContext 

型別ApplicationContext容器,注入到ContextLoaderListener中。 

......
    protected WebApplicationContext createRootApplicationContext() {
        Class<?>[] configClasses = getRootConfigClasses();
        if (!ObjectUtils.isEmpty(configClasses)) {
            AnnotationConfigWebApplicationContext rootAppContext = new AnnotationConfigWebApplicationContext();
            rootAppContext.register(configClasses);
            return rootAppContext;
        }
        else {
            return null;
        }
    }
    ......
    protected void registerContextLoaderListener(ServletContext servletContext) {
        WebApplicationContext rootAppContext = createRootApplicationContext();
        if (rootAppContext != null) {
            ContextLoaderListener listener = new ContextLoaderListener(rootAppContext);
            listener.setContextInitializers(getRootApplicationContextInitializers());
            servletContext.addListener(listener);
        }
        else {
            logger.debug("No ContextLoaderListener registered, as " +
                    "createRootApplicationContext() did not return an application context");
        }
    }

不要對Tomcat內的原始碼花時間,主要是看Spring的原始碼,之後就可以看ContextLoaderListener的contextInitialized(…)方法了,Spring容器就是在這個方法裡初始化生成的。如何初始化,這個太複雜了,需要花非常多的時間去看,去思考的,這裡就不講了,不過我可以說一些我自己總結的小技巧:

 

說是看原始碼,其實應該叫看和想。Spring原始碼很複雜,我覺得花在思考上的時間至少要和看的時間對等。看了,如果沒有花時間想明白,等於白看。

理解重於記憶。Spring的流程很長,東西很多,如果單純靠記憶肯定記不過來的,知道每個元件的大體作用以及作用的節點就夠了,原始碼就在那裡,又不會跑,記不清了翻翻就看到了,多翻幾次就能夠慢慢記住了,最開始看的時候不要執著於記憶。

多做筆記。Spring元件很多,在最開始看的時候,推薦做些筆記,將每個重要介面的作用及關鍵程式碼記錄下,有時間就看看,最先了解的元件是你切入Spring原始碼的切口,藉助他們能關聯到其他的元件。

多百度。在看一些關鍵介面或者類時,如果其程式碼很複雜,先百度下吧,先對其功能有個瞭解,然後對照著功能看程式碼會有很大的幫助。

要多遍地看,反覆地看。別想著看一遍就能看明白,在最開始的幾次跟著初始化流程看原始碼時,不要執著於某個細節。先對Spring所有的元件功能有個大體瞭解,對初始化流程有個大體的瞭解,這是深入的基礎。

多看日誌,多DEBUG。多看日誌能夠提高你對Spring流程的瞭解程度,而且在排錯時能有效提高效率;DEBUG是看原始碼最好的一種方式,是解疑的最直接途徑,對於有些執行時難以觸及的程式碼,需要你手動創造條件讓流程走入此處。

多總結,多動手。不要僅侷限於看和思考,要動手。原始碼看的仔細,基本能從原始碼上看出很多Spring元件的使用方式,總結各種元件的使用方法,然後自己定義相應的元件,將其引入Spring中,檢視其作用流程,這是你擴充Spring的第一步,既能增強對Spring的理解,也能提高你對Spring的擴充能力。

不斷完善框架。每熟悉一種元件的使用,就新增到自己的 框架中,不斷完善自己的框架,到最後你的框架能夠整合Spring大部分好用元件,也是你以後回顧Spring框架的最大助力。

多看註釋,看方法的名稱,引數和返回值。看註釋,理解類,屬性和方法的作用,著重第一段註釋;看方法的名稱,引數和返回值能對方法的作用有很明顯的說明。

 

以上就是我自己看Spring總結的一些小技巧,希望對你們有些助益。

 

後面持續更新相關文章,敬請期待!

 

相關文章