想要深入的熟悉瞭解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總結的一些小技巧,希望對你們有些助益。
後面持續更新相關文章,敬請期待!