Spring的配置形式有兩種:基於XML配置和基於註解配置。
Bean的配置方式有以下幾種:
通過全類名,即通過反射的方式;
通過工廠方法,有靜態工廠方法和實例工廠方法;
通過FactoryBean配置;
通過XML文件配置bean
本篇文章將按照下面的目錄來說明基於XML的方式配置bean
JavaBean的創建
通過XML配置的方式來配置bean
屬性注入
構造器注入
工廠方法注入(很少使用)
XMLbean的配置;
spring的依賴注入的方式
測試方法
通過id
通過類型
ApplicationContext的簡單說明;
IoC容器的實例化;
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>
這種配置方式,有以下幾個特點:
通過bean標籤配置;
class屬性制定bean的全類名,通過反射的方式在IoCr容器中創建bean,被指定的類需要有一個無參的構造方法。大家可以嘗試着給HelloSpring類只提供一個帶參數的構造,並進行測試。
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:
對於字面值除了上面的配置方法,可以使用下面的配置方法,即通過使用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容器實現:
BeanFactory,IoC容器基本的實現;
ApplicationContext,提供了更多的高級特性,是BeanFactory的子接口,其實它也是一個 接口。BeanFactory 是Spring框架的基礎設施,面向Spring本身;ApplicationContext面向使用Spring框架的開發者,幾乎所有的應用場合都直接使用ApplicationContext而非底層的BeanFactory。無論採用哪種方式,配置方式都是一樣的
下面我們來看一下ApplicationContext的類圖,可以看到它本身是一個接口,下面有很多抽象類都實現了這個接口,它有兩個主要的實現類,一個是我們已經使用了的ClassPathXmlApplicationContext,另外一個是FileSystemXmlApplicationContext。
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:
Bean的獲取方法
通過id獲取,即在xml文件中配置bean的時候,設定的id,需要強制類型轉換,上面使用的就是這種方法;
通過類型獲取,代碼實例如下:
//通過id獲取,需要類型轉換 HelloSpring helloSpring_1 = (HelloSpring) ctx.getBean("helloSpring"); //通過類型獲取,不需要類型轉換,缺點是當配置了多個相同類型的bean時,不知道該注入哪一個bean,就會拋出異常 HelloSpring helloSpring = ctx.getBean(HelloSpring.class);
暫時先寫到這裏,關於自動裝配,bean之間的繼承依賴,bean的作用域等等,後面再寫。。。
上面是自己學習Spring的一些簡單的記錄和一些個人的理解,如果有不對的地方,希望大家能夠給幫忙指正,歡迎大家來討論。