Spring 中用 XML 裝配 Bean,居然有五種姿式!

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 指定相關的屬性值,咱們有幾種不一樣的方式:

1.構造方法指定

首先咱們能夠經過構造方法指定 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 的時候,就能夠看到這些屬性了。

2.經過屬性注入

固然也能夠經過屬性注入,這是一種更爲常見的方式:

<bean class="org.javaboy.spring.Book" id="book4">    <property name="id" value="99"/>    <property name="name" value="水滸傳"/>    <property name="price" value="99"/></bean>複製代碼

3.p名稱空間注入

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

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

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 的一個簡單介紹,比較簡單,可是爲了知識的完整性,我仍是稍微寫了下,能看到這裏的都是真愛啊!

相關文章
相關標籤/搜索