Spring學習系列之——第三章:Spring中Bean的配置(一)

  Spring的配置形式有兩種:基於XML配置和基於註解配置。

  Bean的配置方式有以下幾種:


    1. 通過全類名,即通過反射的方式;

    2. 通過工廠方法,有靜態工廠方法和實例工廠方法;

    3. 通過FactoryBean配置;



通過XML文件配置bean

本篇文章將按照下面的目錄來說明基於XML的方式配置bean

  1. JavaBean的創建

  2. 通過XML配置的方式來配置bean

    1. 屬性注入

    2. 構造器注入

    3. 工廠方法注入(很少使用)

    1. XMLbean的配置;

    2. spring的依賴注入的方式

  3. 測試方法 

    1. 通過id

    2. 通過類型

    3. ApplicationContext的簡單說明;

    1. IoC容器的實例化;

    2. bean的獲取方法

  使用XML配置bean,需要通過bean標籤完成,通過bean標籤的class屬性來指定全類名,id屬性指定一個唯一標識,這個標識需要在IoC容器中是唯一的。如果不指定的話,spring將會自動的將權限定性類名作爲id。實際上這種方式已經在第一篇文章《Spring學習系列之——第一章:Spring版本的HelloWorld》中使用了,下面對這種方式進行一個簡單的總結。


1、JavaBean的創建

  首先創建一個JavaBean,重寫toString()方法是爲了方便測試看結果,這個JavaBean什麼都沒有,只有一個屬性和對應的getter和setter方法,我們都知道,在不定義構造方法的時候,會自動生成一個無參的構造方法。

package com.spring.blog.helloworld;

public class HelloSpring {
	private String str;

	public String getStr() {
		return str;
	}

	public void setStr(String str) {
		this.str = str;
	}

	@Override
	public String toString() {
		return "HelloSpring [str=" + str + "]";
	}
	
}


2、通過XML配置的方式來配置Bean


a、通過XML配置的方式配置bean

  接下來看一下怎麼配置這個bean,下面是applicationContext.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"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
	
	<!-- 配置Springbean -->
	<bean id="helloSpring" class="com.spring.blog.helloworld.HelloSpring">
		<property name="str" value="Spring is good!"></property>
	</bean>
</beans>

  這種配置方式,有以下幾個特點:


    1. 通過bean標籤配置;

    2. class屬性制定bean的全類名,通過反射的方式在IoCr容器中創建bean,被指定的類需要有一個無參的構造方法。大家可以嘗試着給HelloSpring類只提供一個帶參數的構造,並進行測試。

    3. id是bean在IoC容器中的標識,需要是唯一的。

b、spring依賴注入的方式

    屬性注入:最常用的注入方式

  上面的配置方式就是屬性注入方式,需要注意的是:name是和setter方法保持一致的!什麼意思,請看下面的代碼:

//str屬性不變
private String str;
//setStr改爲setStr2
public void setStr2(String str) {
	this.str = str;
}

相對於的xml配置文件中bean的定義應該如下:name是str2,而不是str

<!-- 配置Springbean -->
<bean id="helloSpring" class="com.spring.blog.helloworld.HelloSpring">
	<property name="str2" value="Spring is good!"></property>
</bean>

    構造方法注入

新建JavaBean,Car類,定義了兩個構造方法:

package com.study.spring;

public class Car {
	private String brand;
	private String corp;
	private double price;
	private int maxSpeed;

	public Car(String brand, String corp, double price) {
		super();
		this.brand = brand;
		this.corp = corp;
		this.price = price;
	}
	public Car(String brand, String corp, int maxSpeed) {
		super();
		this.brand = brand;
		this.corp = corp;
		this.maxSpeed = maxSpeed;
	}

}

下面看一下XML文件的配置方式:

<!-- 通過構造方法配置Bean 通過構造器注入屬性值可以指定參數的位置(index指定)和參數的類型(type指定)已區分構造器 -->
<!--  使用第二個構造方法 -->
<bean id="car" class="com.study.spring.Car">
	<constructor-arg value="Audi" index="0"></constructor-arg>
	<constructor-arg value="Shanghai" index="1"></constructor-arg>
	<constructor-arg value="3000" index="2" type="double"></constructor-arg>
</bean>
<!--  使用第二個構造方法  -->
<bean id="car2" class="com.study.spring.Car">
	<constructor-arg value="Audi" type="java.lang.String"></constructor-arg>
	<constructor-arg value="Shanghai" type="java.lang.String"></constructor-arg>
	<constructor-arg value="240" type="int"></constructor-arg>
</bean>

通過bean的子標籤:constructor-arg注入到對象中區,其中index屬性可以指定構造方法中的參數的順序,type可以指定參數的類型,這樣就可以明確要使用的構造器。考慮一下,重載方法:參數個數不同或者參數類型不同,但是名稱相同的方法。我認爲這裏可以這麼理解:這裏的index屬性可以類比爲個數,type屬性類比爲參數類型。


  但是看到上面的配置方式,不知道大家有沒有疑問,第一個構造方法三個參數分別是String、String、double類型,第二個構造方法三個參數分別是String、String、int類型的。而我們的配置文件,統統採用的是value="參數值"的形式,但是程序可以運行沒有錯誤,很明顯這是spring爲我們做了相關的工作,自動的完成了相關的類型轉換,像這種可用字符串表示的值,我們稱之爲字面值。既然是這樣的話,不難想象,如果我們不指定type屬性,IoC容器在創建bean的時候肯定會使用找到的第一個匹配的構造方法進行創建。下面是去掉type屬性之後的運行結果截圖,可以看到都把第三個參數賦值給了price:

wKioL1VHbkTTW0laAACI2qzmBCY501.jpg

  對於字面值除了上面的配置方法,可以使用下面的配置方法,即通過使用constructor-arg的子標籤value標籤進行賦值,對於有特殊符號的,可以使用表達式<![CDATA[]]>把值給包裹起來,例如這裏要給第二個參數賦值爲<shanghai^>,尖括號(<、>)在XML中是特殊符號

<bean id="car3" class="com.study.spring.Car">
	<constructor-arg value="Audi" type="java.lang.String"></constructor-arg>
	<!-- 如果字面包含特殊字符,可以使用 <![CDATA[]]包裹起來 -->
	<!-- 屬性值可以使用value子節點進行配置 -->
	<constructor-arg type="java.lang.String">
		<value><![CDATA[<ShangHai^>]]></value>
	</constructor-arg>
	<constructor-arg type="int">
		<value>270</value>
	</constructor-arg>
</bean>


  小結:對於字面值,可以使用字符串表示的值,我們可以通過constructor-arg標籤的value屬性進行賦值,也可以通過constructor-arg的子標籤<value></value>進行賦值,對包含特殊字符的情況可以使用表達式<![CDATA[]]>把值給包裹起來。Java中的基本數據類型及其封裝類型(Integer、Long等)和String類型都可以使用上面的字面值的注入方法。


測試方法的解讀

 這一部分通過下面兩個方面來進行分析:一是IoC容器的實例化;二是如何獲取bean?

  接下來看一下測試類:

package com.spring.blog.helloworld;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Main {
	public static void main(String[] args) {
		//實例化一個IoC容器
		ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
		//從IoC容器中獲取bean實例
		HelloSpring helloSpring = (HelloSpring) ctx.getBean("helloSpring");
		//測試獲取到的bean實例
		System.out.println(helloSpring);
	}
}


IoC容器的實例化

  說了這麼多,一直都在說IoC容器,到底什麼是IoC容器?

  Spring 提供了兩種類型的IOC容器實現:


    1. BeanFactory,IoC容器基本的實現;

    2. ApplicationContext,提供了更多的高級特性,是BeanFactory的子接口,其實它也是一個 接口。BeanFactory 是Spring框架的基礎設施,面向Spring本身;ApplicationContext面向使用Spring框架的開發者,幾乎所有的應用場合都直接使用ApplicationContext而非底層的BeanFactory。無論採用哪種方式,配置方式都是一樣的

 

  下面我們來看一下ApplicationContext的類圖,可以看到它本身是一個接口,下面有很多抽象類都實現了這個接口,它有兩個主要的實現類,一個是我們已經使用了的ClassPathXmlApplicationContext,另外一個是FileSystemXmlApplicationContext。

wKioL1VA2fXg8rRHAAKXjTs8P8g533.jpg

 ClassPathXmlApplicationContext:類路徑下加載配置文件,可以理解爲根目錄是src,相對於src目錄來寫配置文件的位置;

 FileSystemXmlApplicationContext:文件系統中加載配置文件。假如我們的配置文件application-context.xml放在D:/config 目錄下面,我們可以通過這個類,傳入參數D:\\config\\application-context.xml來初始化IoC容器。

 ConfigurableApplicationContext擴展於ApplicationContext,新增加了兩個主要方法:refresh()和close(),讓 ApplicationContext具有啓動、刷新和關閉上下文的能力。

 ApplicationContext在初始化上下文時就實例化所有單例的Bean。這意味着不管你是否立即使用註冊在IoC容器的bean,IoC容器都會創建所有的單例的Bean。關於這一點,我們可以通過提供無參的構造方法,在構造方法中添加輸入語句,例如:

//提供無參的構造方法,輸出語句是驗證用的
public HelloSpring() {
	System.out.println("HelloSpring's constructor...");
}

然後測試類的main方法中只保留下面一句話:

ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");

其實是可以看到下面的輸出信息的,說明確實是在初始化IoC容器的時候,實例化了bean:

wKiom1VA3a6RtTO4AAMsnNOtMPE504.jpg


Bean的獲取方法 

  1. 通過id獲取,即在xml文件中配置bean的時候,設定的id,需要強制類型轉換,上面使用的就是這種方法;

  2. 通過類型獲取,代碼實例如下:

//通過id獲取,需要類型轉換
HelloSpring helloSpring_1 = (HelloSpring) ctx.getBean("helloSpring");

//通過類型獲取,不需要類型轉換,缺點是當配置了多個相同類型的bean時,不知道該注入哪一個bean,就會拋出異常
HelloSpring helloSpring =  ctx.getBean(HelloSpring.class);


 暫時先寫到這裏,關於自動裝配,bean之間的繼承依賴,bean的作用域等等,後面再寫。。。


 上面是自己學習Spring的一些簡單的記錄和一些個人的理解,如果有不對的地方,希望大家能夠給幫忙指正,歡迎大家來討論。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章