前言:
又開始動筆開了“學習Spring”系列的頭……
其實一開始寫“學習SpringMVC”的幾篇文章是出於想系統的了解下Spring以及SpringMVC,因為平時在公司中雖然每天都在使用Spring相關的框架或者其他,但是絕大部分都是已經寫好配置文件,做好相關配置,而我們能做的就是寫一些與業務邏輯有關的Controller層面或者Service層面的代碼。畢竟所做的產品成熟了,或者說框架越來越成熟了,我們對於底層原理的東西關注的就少了,認識也淺了。
個人感覺,頗具諷刺意味的是,“SpringMVC”系列的HelloWorld篇發出去后,每日閱讀量出現了比以外任何一篇都要快的尷尬式增長,如今已經成為我第一篇超過5位數閱讀量的文章,汗-_-!
本來只是想在了解了SpringMVC的套路后,稍稍的看下佟剛老師的Spring視頻就算了。可是后來有網友問SpringMVC系列是否還有后續,我想了一下,那如果有的話可能就是Spring基礎相關了吧;而且,有些東西只是抱着看一看的心態,最后得到的也就是看一看的反饋,一個小時又或是一天之后就完全忘得一干二凈了。所以,算是一份筆記吧,這里開了個頭。
通過之前SpringMVC的學習,似乎在某些瞬間,我似乎看到了一些與自己項目中似曾相識的套路,只是之前因為項目過大,或者自己做的只是一些細微的調整,很難發現項目的大森林全貌。學習Spring的時候,我也希望能夠重現類似的橋段,這樣的學習就是有回報的,值得的。
毫無意外可言,第一篇講的還是HelloWorld(主要是依賴注入的特性)。
Spring
Spring 是一個開源框架。
Spring 是一個 IOC(DI) 和 AOP 容器框架(Spring的兩大法寶)。
Spring框架是由於軟件開發的復雜性而創建的。Spring使用的是基本的JavaBean來完成以前只可能由EJB完成的事情。然而,Spring的用途不僅僅限於服務器端的開發。從簡單性、可測試性和松耦合性的角度而言,絕大部分Java應用都可以從Spring中受益(總而言之,Spring就是很膩害)。
官網:https://spring.io/
HelloWorld實例對比
首先,需要新建一個Java Project,新建完成目錄結構如下:
如你所見,這里還要一些需要用到的jar。
沒有使用Spring的那一套
不可否認,在Spring沒有橫空出世的時候,太陽依舊是東起西落,地球如斯旋轉。大概是這個樣子:
新建HelloWorld類
public class HelloWorld { private String name; public HelloWorld() { System.out.println("HelloWorld's constructor..."); } public void setName(String name) { this.name = name; } public void hello(){ System.out.println("Hello: " + name); } }
新建測試方法
public class Main { public static void main(String[] args) { HelloWorld helloWorld = new HelloWorld(); helloWorld.setName("Jackie"); helloWorld.hello(); } }
最終你會如願以償的得到你期望的結果:“Hello:Jackie”
使用Spring后的這一套
使用Spring框架后,我們不能單純的新建兩個類就完事了,怎么說也對不起框架這兩個字,於是我們需要:
新建一個Spring的配置文件beans.xml
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:util="http://www.springframework.org/schema/util" xmlns:p="http://www.springframework.org/schema/p" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.0.xsd"> <!-- 配置一個 bean --> <bean id="helloWorld" class="com.jackie.spring.helloworld.HelloWorld"> <!-- 為屬性賦值 --> <property name="name" value="Jackie"></property> </bean> </beans>
測試方法
這里我們大致分為如下幾步:
1. 創建 Spring 的 IOC 容器
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("beans.xml");
2. 從創建的 IOC 容器中獲取 bean 的實例
HelloWorld helloWorld = (HelloWorld) ctx.getBean("helloWorld");
3. 使用 bean實例
helloWorld.hello();
注意:
- ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("beans.xml");HelloWorld helloWorld = (HelloWorld) ctx.getBean("helloWorld");實際上是容器初始化操作,包括本例子中執行helloWorld的構造函數以及執行setName方法
- 這里的ctx.getBean("helloWorld"),是在beans.xml中配置過的,getBean后的名字必須要和beans.xml中定義的id名稱一致,否則無法獲取該HelloWorld bean的實例
- 同時,我們發現,這里不再需要new了,我們只需要在一個稱為IOC的容器中抓我們想要的對象即可,其實本質上來說,這不僅是一個框架的使用,更是一種編程思想的轉變。沒有使用Spring前,好比買菜要到菜市場,你得提個籃子去菜市場,可是有了Spring,我們輕松多了,把你的籃子甩到門口,自然就有人敲門送菜了。利用佟剛老師的話來說就是“傳統的資源查找方式要求組件向容器發起請求查找資源. 作為回應, 容器適時的返回資源. 而應用了 IOC 之后, 則是容器主動地將資源推送給它所管理的組件, 組件所要做的僅是選擇一種合適的方式來接受資源. 這種行為也被稱為查找的被動形式”
依賴注入
Spring IOC容器之所以能取到HelloWorld類,完全是基於依賴注入機制,骨子里就是反射機制,但是依賴注入的方式有多種,這里做一個簡單介紹
屬性注入
正如上面beans.xml中聲明的那樣,定義一個bean,id為helloWorld,class即類的全路徑為com.jackie.spring.helloworld.HelloWorld
使用<property>元素為bean注入值,name是bean的屬性名稱,這里正好也是name,value是bean屬性對應的值,其實相當於調用了setName方法,將Jackie傳給了HelloWorld的成員變量name。所以如果使用屬性注入,需要在bean中定義好相應的set方法。
構造器注入
屬性注入是通過set方法注入值,這里的構造器注入,顯然是通過構造函數注入值的。舉例來說:
新建bean Car類
public class Car { private String company; private String brand; private int maxSpeed; private float price; public Car(String company, String brand, float price) { super(); this.company = company; this.brand = brand; this.price = price; } public Car(String company, String brand, int maxSpeed) { super(); this.company = company; this.brand = brand; this.maxSpeed = maxSpeed; } public Car(String company, String brand, int maxSpeed, float price) { super(); this.company = company; this.brand = brand; this.maxSpeed = maxSpeed; this.price = price; } @Override public String toString() { return "Car [company=" + company + ", brand=" + brand + ", maxSpeed=" + maxSpeed + ", price=" + price + "]"; } }
相應的,在beans.xml中定義如下
<bean id="car" class="com.jackie.spring.helloworld.Car"> <constructor-arg value="DaZhong" index="1"></constructor-arg> <constructor-arg value="Shanghai" index="0"></constructor-arg> <constructor-arg value="250000" type="float"></constructor-arg> </bean>
這里是根據car類的構造函數來的,value對應構造函數中每個參數的具體值,對應順序通過index來標示,但是如果car中有多個構造函數像上面的car類,這時候可以通過type參數指定參數的類型是什么,從而決定重載的是那個構造函數。
在測試方法中加入
Car car = (Car) ctx.getBean("car"); System.out.println(car);
得到結果
Car [company=Shanghai, brand=DaZhong, maxSpeed=0, price=250000.0]
同時這里簡單介紹下如何在beans.xml中聲明一個bean引用其他bean
新建User類
public class User { private String userName; private List<Car> cars; private String wifeName; public String getWifeName() { return wifeName; } public void setWifeName(String wifeName) { System.out.println("setWifhName: " + wifeName); this.wifeName = wifeName; } public String getUserName() { return userName; } public void setUserName(String userName) { this.userName = userName; } public List<Car> getCars() { return cars; } public void setCars(List<Car> cars) { this.cars = cars; } public User() { System.out.println("User's Construtor..."); } @Override public String toString() { return "User [userName=" + userName + ", cars=" + cars + "]"; } public void init(){ System.out.println("init method..."); } public void destroy(){ System.out.println("destroy method..."); } }
在beans.xml中聲明
<bean id="user" class="com.atguigu.spring.helloworld.User"> <property name="userName" value="Jackie"></property> <property name="car" ref="car"></property> </bean>
測試類中加入
User user = (User) ctx.getBean("user"); System.out.println(user);
最終得到結果
User [userName=Jackie, cars=[Car [company=Shanghai, brand=DaZhong, maxSpeed=0, price=250000.0]]
注意:這里也可以使用內部bean的方式,而不需要通過ref屬性指定其他bean
<bean id="user" class="com.atguigu.spring.helloworld.User"> <property name="userName" value="Jack"></property> <property name="car"> <bean class="com.jackie.spring.helloworld.Car"> <constructor-arg value="DaZhong" index="1"></constructor-arg> <constructor-arg value="Shanghai" index="0"></constructor-arg> <constructor-arg value="250000" type="float"></constructor-arg> </bean> </property> </bean>
至此,我們了解了
- Spring是什么
- 如何創建一個Spring工程
- 如何寫基於Spring框架的HelloWorld
- 兩種依賴注入的方式屬性注入和構造器注入
- bean與bean之間的相互引用以及內部bean的概念
如果您覺得閱讀本文對您有幫助,請點一下“推薦”按鈕,您的“推薦”將是我最大的寫作動力!如果您想持續關注我的文章,請掃描二維碼,關注JackieZheng的微信公眾號,我會將我的文章推送給您,並和您一起分享我日常閱讀過的優質文章。
友情贊助
如果你覺得博主的文章對你那么一點小幫助,恰巧你又有想打賞博主的小沖動,那么事不宜遲,趕緊掃一掃,小額地贊助下,攢個奶粉錢,也是讓博主有動力繼續努力,寫出更好的文章^^。
1. 支付寶 2. 微信