【Spring源碼分析】預備篇
- 2020 年 4 月 24 日
- 筆記
- spring源碼分析
前言
最新想學習一下Spring源碼,開篇部落格記錄下學習過程,歡迎一塊交流學習。
作為預備篇,主要演示搭建一個最簡單的Spring項目樣例,對Spring進行最基本梳理。
構建一個最簡單的spring項目
Spring中最核心的Jar包有四個:spring-beans、spring-context、spring-core、spring-expression。
以前做spring項目有個誤區,什麼包都一個個導入進來,其實一個最最簡單的Spring項目,理論上就需要引入一個jar包spring-context就夠了,靠它的依賴關係,其他核心包都會自動導入進來(只是核心包,實際真實項目需要其他功能再額外導入)。
1、在一個空項目里 添加Spring項目模組 Maven->jdk1.8>webapp 模板
2、這裡在pom中只額外添加 spring-context依賴
(它依賴其他幾個核心jar包 會自動導入依賴)
<properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <maven.compiler.source>1.7</maven.compiler.source> <maven.compiler.target>1.7</maven.compiler.target> <spring.version>5.1.3.RELEASE</spring.version> </properties> <dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.11</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-classic</artifactId> <version>LATEST</version> </dependency> </dependencies>
實際引入的包及依賴關係:
1 package cn.eport.jason.bean; 2 3 @Component 4 public class Student { 5 6 private String username = "WPC"; 7 8 private String password; 9 10 public String getUsername() { 11 return username; 12 } 13 14 public void setUsername(String username) { 15 this.username = username; 16 } 17 18 public String getPassword() { 19 return password; 20 } 21 22 public void setPassword(String password) { 23 this.password = password; 24 } 25 }
寫一個測試方法,(因為本例中是在源程式碼下編寫的單元測試,所以需要先在pom中去掉Junit 作用域為test的限制,不然在業務程式碼區使用@Test註解時會提示找不到)
<dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.11</version> <!--<scope>test</scope>--> </dependency>
MyTest.java 測試類
package cn.eport.jason.test; import cn.eport.jason.bean.Student; import org.junit.Test; import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.AnnotationConfigApplicationContext; public class MyTest { @Test public void Test1(){ //基於註解的方式載入Spring容器 ApplicationContext applicationContext = new AnnotationConfigApplicationContext("cn.eport"); Student student =(Student) applicationContext.getBean("student"); System.out.println(student.getUsername()); } }
運行單元測試方法Test1 控制台輸出結果:
D:\DevTool\Java\jdk1.8.0_101\bin\java.exe ... cn.eport.jason.test.MyTest,Test1
WPC
Process finished with exit code 0
說明Spring ioc容器功能已生效,已屬於spring項目。
spring容器啟動的4種方式
-
1、類路徑獲取配置文件載入容器
ApplicationContext applicationContext= new ClassPathXmlApplicationContext(“spring.xml”);
-
2、文件系統路徑獲取配置文件【絕對路徑】不常用
ApplicationContext applicationContext = new FileSystemXmlApplicationContext(“E:\\idea\\public\\springdemo\\src\\main\\resources\\spring.xml”);
-
3、無配置文件載入容器(註解方式) 單元測試中常用
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(“cn.eport”);
-
4、springboot載入容器
ApplicationContext applicationContext = new EmbeddedWebApplicationContext();
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="//www.springframework.org/schema/beans"
xmlns:xsi="//www.w3.org/2001/XMLSchema-instance"
xmlns:context="//www.springframework.org/schema/context"
xsi:schemaLocation="//www.springframework.org/schema/beans
//www.springframework.org/schema/beans/spring-beans.xsd
//www.springframework.org/schema/context
//www.springframework.org/schema/context/spring-context.xsd">
<!-- 方式1、批量註冊 包掃描+註解 -->
<context:component-scan base-package="cn.eport"/>
<!-- 方式2、手動註冊bean 。 id不寫 默認為類全限定名-->
<bean class="cn.eport.jason.bean.Student"> </bean> </beans>
這裡通過兩種方式註冊了Student實例:
- 一個ComonentScan掃描+註解的方式(BeanName默認類名小寫)
- 一個配置註冊bean的方式(默認BeanName為類全限定名)
ps:<context:component-scan>這種帶有前綴的標籤 為自定義標籤,spring原始組件只有 spring-core和spring-bean ,常用的context、aop、tx組件其實都是擴展組件,Spring靠的就是自定義標籤在核心組件上擴展使得spring更加強大,在配置文件中使用擴展標籤需要引入相應的xsd;在標籤對應的jar包下面找到對應的spring.schemas,在這個文件中就會有對應的XSD路徑和命名空間xmlns(xml namespaceUri) (類似於java中的Import)
2、編寫對應的測試方法 使用 ClassPathXmlApplicationContext 讀取配置文件載入容器獲取bean對象 進行測試:
@Test public void Test2(){ //讀取類路徑下xml配置文件的方式載入spring容器 ApplicationContext applicationContext = new ClassPathXmlApplicationContext("Spring.xml"); Student student1 =(Student) applicationContext.getBean("student");//取得為包掃描+註解 方式註冊的 beanId是類名小寫 Student student2 =(Student) applicationContext.getBean("cn.eport.jason.bean.Student");//取得為配置文件中預設id 的那個bean System.out.println(student1.getUsername());//WPC System.out.println(student2.getUsername());//WPC System.out.println(student1==student2);//false 不同的註冊方式註冊的兩個不同的實例對象 }
結果:
WPC WPC false Process finished with exit code 0
Spring容器一樣也載入成功了,由此可以看出項目中只添加Spring-context 的依賴,一個最基礎的Spring的項目即可搭建好(這裡說的不是SpringMVC工程)
根據測試列印結果可以發現個問題,程式並沒有列印出Spring的日誌,原因為pom中未添加spring日誌依賴logback:
<!--一個空的spring工程是不能列印日誌的,要導入spring依賴的日誌jar--> <dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-classic</artifactId> <version>LATEST</version> </dependency>
再次執行下測試方法,控制台列印出Spring的日誌:
由此,構建一個帶日誌的最基礎Spring項目,只需要在pom中添加context、logback兩個依賴即可
<dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>${spring.version}</version> </dependency> <!--一個空的spring工程是不能列印日誌的,要導入spring依賴的日誌jar--> <dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-classic</artifactId> <version>LATEST</version> </dependency>
但是實際上由於jar包相互依賴,項目中maven會自動導入其他依賴,實際導入的包遠遠不止這兩個:
實際導入的包及依賴關係如下:

結語
作為開篇內容相對簡單些,經過演示我們看到了pom中只添加context、logback兩個依賴就可以搭建一個帶日誌最基本的spring項目,以及我們知道了spring源碼的入口類,後續我們進行源碼分析~