學習Spring——依賴注入


前言:

  又開始動筆開了“學習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. 微信

                      

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM