Spring Boot 系列還在不斷的更新,有小夥伴和鬆哥抱怨對 Spring 還不太懂,其實我 2016 年的時候寫過一點點 Spring 的教程,可是不夠詳細,所以,最近決定再挖一個坑,和你們聊聊 Spring 的一些常見用法,也順便聊聊源碼。java
Spring 和 Spring Boot 強相關,所以,相信這個系列不會爛尾。web
本想寫一些高大上的架構方面的,但是考慮到有不少讀者是剛入行的狀態,所以仍是決定先把 Spring 也和你們過一遍,固然這些東西會穿插着來,儘可能知足每個小夥伴的需求。spring
今天就先來和你們聊一聊 Spring 中 XML 裝配 Bean 的一些常常被人忽略的細節。數組
使用 XML 配置 Spring ,不少人都用過,可能有的小夥伴沒認真總結過,今天咱們就來稍微總結下,算是開啓咱們的 Spring 之旅。bash
XML 配置是最原始最古老的 Bean 的裝配方案,曾經咱們的項目離不開它,而現在,咱們卻在慢慢的拋棄它,沒辦法,時代在進步,咱們也要進步呀。爲了能看懂前輩們寫的代碼,咱們仍是有必要來看一下如何經過 XML 來裝配 Bean。架構
首先咱們來建立一個普通的 Maven 工程(不用建立成 web 工程),建立成功以後,引入 Spring 相關的依賴,這裏只要引入 spring-context 便可,以下:ui
<dependencies> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>5.1.5.RELEASE</version> </dependency></dependencies>複製代碼
建立成功以後,咱們再來建立一個 Book 類,以下:this
public class Book { private Integer id; private String name; private Double price; //省略 getter/setter}複製代碼
而後再在 resources 目錄下建立一個 beans.xml 文件,做爲 Spring 的配置文件,而後在裏邊配置一個 Book bean,以下:spa
<?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"> <bean class="org.javaboy.spring.Book" id="book"/></beans>複製代碼
在這裏,咱們在 class 屬性中配置類的全路徑,id 則表示 bean 的名稱,也能夠經過 name 屬性來指定 bean 的名稱,大部分場景下二者無任何差異,會有一些特殊場景下(例如用,隔開多個實例名,二者的處理方案不一樣),二者有區別。code
而後咱們在 Java 代碼中加載這個配置文件:
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("classpath:beans.xml");複製代碼
題外話:
ClassPathXmlApplicationContext 是配置文件衆多的加載方式之一,表示從 classpath 下加載配置文件,這也是較經常使用的加載方式之一。其餘常見的加載方式以下:
從這些不一樣的實現類中能夠看到,咱們也能夠直接從文件系統中加載 Spring 的 XML 配置文件,使用 FileSystemXmlApplicationContext 類便可。
配置文件加載完成後,咱們就能夠從 Spring 容器中去獲取這些 Bean 了,方式以下:
Book book = (Book) ctx.getBean("book");複製代碼
這個表示根據 id 獲取相應的 Bean ,咱們也能夠經過類型來獲取,方式以下:
Book b1 = ctx.getBean(Book.class);複製代碼
兩種方式推薦第一種。
第二種經過類型獲取 Bean 的方式存在一個問題,就是容器中同一個類若是存在多個實例,經過類型獲取確定會出錯。
可是此時咱們獲取到的 Bean 中的屬性所有爲 null,沒有值,這是由於咱們在配置的時候沒有給屬性指定值。
在配置 Bean 時,給 Bean 指定相關的屬性值,咱們有幾種不一樣的方式:
首先咱們能夠經過構造方法指定 bean 的屬性值,前提是咱們爲 Book 類提供一個有參構造方法(你們在建立有參構造方法時,必定記得再順手加一個無參構造方法):
public class Book { private Integer id; private String name; private Double price; public Book() { } public Book(Integer id, String name, Double price) { this.id = id; this.name = name; this.price = price; } //省略 getter/setter}複製代碼
而後在 XML 文件中,咱們就能夠經過構造方法注入相關值了:
<bean class="org.javaboy.spring.Book" id="book2"> <constructor-arg name="id" value="99"/> <constructor-arg name="name" value="三國演義"/> <constructor-arg name="price" value="99"/></bean>複製代碼
使用構造方法注入相關值的時候,也可使用下標來描述參數的順序,注意若是使用下標,參數順序不能錯:
<bean class="org.javaboy.spring.Book" id="book3"> <constructor-arg index="0" value="99"/> <constructor-arg index="1" value="紅樓夢"/> <constructor-arg index="2" value="100"/></bean>複製代碼
注入成功以後,當咱們再次去獲取 Bean 的時候,就能夠看到這些屬性了。
固然也能夠經過屬性注入,這是一種更爲常見的方式:
<bean class="org.javaboy.spring.Book" id="book4"> <property name="id" value="99"/> <property name="name" value="水滸傳"/> <property name="price" value="99"/></bean>複製代碼
p 名稱空間本質上仍是經過屬性注入的,只不過寫法有些差別,p 名稱空間注入方式以下:
<bean class="org.javaboy.spring.Book" id="book5" p:id="100" p:name="西遊記" p:price="40"/>複製代碼
以上三種不一樣的屬性注入方式,我給你們演示的都是注入基本數據類型,若是注入的是一個對象的話,只須要經過 ref 屬性來指明對象的引用便可。
除了這些基本屬性以外,還有一些特殊屬性,例如集合、數組、map 等。咱們分別來看。
集合/數組的注入方式基本一致,首先咱們給項目添加一個集合屬性,以下:
public class Book { private Integer id; private String name; private Double price; private List<String> authors; //省略 getter/setter}複製代碼
屬性注入時,能夠經過 array 節點注入值:
<bean class="org.javaboy.spring.Book" id="book4"> <property name="id" value="99"/> <property name="name" value="水滸傳"/> <property name="price" value="99"/> <property name="authors"> <array> <value>zhangsan</value> <value>lisi</value> <value>javaboy</value> </array> </property></bean>複製代碼
也能夠經過 list 節點注入值:
<bean class="org.javaboy.spring.Book" id="book4"> <property name="id" value="99"/> <property name="name" value="水滸傳"/> <property name="price" value="99"/> <property name="authors"> <list> <value>zhangsan</value> <value>lisi</value> <value>javaboy</value> </list> </property></bean>複製代碼
還有一個可能你們使用比較少的方式,就是經過 utils:list 來建立集合屬性,而後配置到 Book 屬性中去,便可:
<bean class="org.javaboy.spring.Book" id="book4"> <property name="id" value="99"/> <property name="name" value="水滸傳"/> <property name="price" value="99"/> <property name="authors" ref="authors" /></bean><utils:list id="authors"> <value>javaboy</value> <value>zhangsan</value></utils:list>複製代碼
這種方式比較少見。
map 的注入也有幾種不一樣的方式,能夠經過屬性指定,也能夠經過 utils 來搞定,先來看第一種:
public class Book { private Integer id; private String name; private Double price; private List<String> authors; private Map<String, Object> info; //省略 getter/setter}複製代碼
在 xml 文件中經過以下方式指定屬性值:
<bean class="org.javaboy.spring.Book" id="book4"> <property name="id" value="99"/> <property name="name" value="水滸傳"/> <property name="price" value="99"/> <property name="authors" ref="authors" /> <property name="info"> <map> <entry key="name" value="zhangsan"/> <entry key="age" value="99"/> </map> </property></bean>複製代碼
也能夠經過 utils 來指定 map 的值,以下:
<bean class="org.javaboy.spring.Book" id="book4"> <property name="id" value="99"/> <property name="name" value="水滸傳"/> <property name="price" value="99"/> <property name="authors" ref="authors" /> <property name="info" ref="info"/></bean><utils:map id="info"> <entry key="name" value="lisi"/> <entry key="age" value="98"/></utils:map>複製代碼
properties 屬性也是同樣的配置方案。既能夠經過 props 屬性指定,也能夠經過 utils 來指定,例如:
public class Book { private Integer id; private String name; private Double price; private List<String> authors; private Map<String, Object> info; private Properties info2; //省略 getter/setter}複製代碼
經過 props 屬性指定方式以下:
<bean class="org.javaboy.spring.Book" id="book4"> <property name="id" value="99"/> <property name="name" value="水滸傳"/> <property name="price" value="99"/> <property name="authors" ref="authors" /> <property name="info" ref="info"/> <property name="info2"> <props> <prop key="name">zhangsan</prop> <prop key="age">99</prop> </props> </property></bean>複製代碼
經過 utils 指定方式以下:
<bean class="org.javaboy.spring.Book" id="book4"> <property name="id" value="99"/> <property name="name" value="水滸傳"/> <property name="price" value="99"/> <property name="authors" ref="authors"/> <property name="info" ref="info"/> <property name="info2" ref="info2"/></bean><utils:properties id="info2"> <prop key="name">zhangsan</prop> <prop key="age">99</prop></utils:properties>複製代碼
除了這幾種裝配方式以外,咱們也能夠經過工廠方法裝配。
工廠方法裝配能夠分爲靜態工廠和實例工廠兩種方式,咱們分別來看。
靜態工廠方法裝配須要咱們先建立一個靜態工廠方法,像下面這樣:
public class BookFactory { public static Book getInstance() { return new Book(); }}複製代碼
而後在 XML 文件中裝配:
<bean class="org.javaboy.spring.BookFactory" id="book6" factory-method="getInstance"/>複製代碼
此時咱們去容器中獲取 book6 這個實例,拿到的就是你在靜態工廠中返回的 Book 實例。
實例工廠方法則是指工廠方法是一個普通方法,不是靜態的,像下面這樣:
public class BookFactory2 { public Book getInstance() { return new Book(); }}複製代碼
而後在 XML 文件中,咱們須要首先配置 BookFactory2 的實例,而後才能調用實例中的方法獲取 Book 對象,以下:
<bean class="org.javaboy.spring.BookFactory2" id="bookFactory2"></bean><bean class="org.javaboy.spring.Book" id="book7" factory-bean="bookFactory2" factory-method="getInstance"/>複製代碼
工廠方法裝配的價值在哪裏呢?
例如 Druid 中的 DataSource 對象,經過 DruidDataSourceBuilder.create().build()
方法來構建,若是咱們想在 XML 中作這個配置,顯然不太容易,此時就可使用工廠方法裝配了。
好了,這就是 XML 裝配 Bean 的一個簡單介紹,比較簡單,可是爲了知識的完整性,我仍是稍微寫了下,能看到這裏的都是真愛啊!