1. 程式人生 > >Spring之Bean的注入

Spring之Bean的注入

Bean的配置中介紹的是Bean宣告問題,在哪宣告怎麼宣告的問題。Bean的注入是怎麼例項化,怎麼注入的問題。Bean注入的方式有兩種,一種是在XML中配置,另一種則是使用註解的方式注入。

一、XML方式注入

XML方式注入一般有三種方式:屬性注入、建構函式注入和工廠方法注入。

一、屬性注入
在傳統的物件例項化時可以通過new class(),然後通過setXXX()方法設定物件的屬性值或依賴物件,屬性注入也是採用這種方式,只是Spring框架會在內部完成這些操作,它會先呼叫Bean的預設建構函式例項化Bean物件,然後通過反射的方式呼叫Setter方法注入屬性值。它會使用預設的建構函式(無引數建構函式),只需為注入的屬性設定set方法,可選擇性和靈活性比較高,所以也是比較常用的一種注入方式。這裡示例還是在IOC章節使用人和空氣的基礎上稍作修改來演示。IAir介面和CleanAir、DirtyAir類不變,這裡就不貼了。

1.新建XMLInstance類

package com.demo.model;

public class XMLInstance {
    
    
    private String name;
    
    public void setName(String name) {
        this.name = name;
    }
    private IAir air;
    
    public void setAir(IAir air) {
        this.air = air;
    }
    public void Breath()
    {
        System.out.println(
"Name:"+this.name+";Air:"+this.air.toString()); } public XMLInstance(String name, IAir air) { super(); this.name = name; this.air = air; } public XMLInstance() { } public void DestoryMethod() { System.out.println("DestoryMethod"); }
public void InitMethod() { System.out.println("InitMethod"); } }
View Code

在XMLInstance類中並未宣告建構函式,對於air屬性只設置了set方法,get方法也沒設定。

  <bean id="CleanAir" class="com.demo.model.CleanAir">
        <qualifier value="cleanair"/> 
  </bean> 
  <bean id="xmlinstance" class="com.demo.model.XMLInstance">
      <property name="air" ref="CleanAir"></property>
      <property name="name" value="abc"></property>
  </bean>

Xml中使用property類配置屬性,name是屬性名,value用來設定基本資料型別的屬性值。Spring配置檔案中bean之間可以相互引用,引用時可以用<ref>標籤配置bean的id屬性使用。<ref>可以用在<property>屬性中,也可以用在<construct-arg>建構函式的引數值,還可以用在其他地方,通過引用能減少bean的宣告。

二、建構函式注入
在屬性注入時先使用預設的建構函式(無引數建構函式)例項化,然後通過set方法注入屬性,在傳統例項化物件時可以自定義建構函式進行例項化,建構函式注入就是通過自定義建構函式來進行物件的例項化。這裡在XMLInstance類的基礎上增加了一個建構函式,第一個引數是String型別的name,第二個引數是IAir型別的air。

    public XMLInstance(String name, IAir air) {
        super();
        this.name = name;
        this.air = air;
    }

Xml中使用使用<construect-arg>來設定建構函式的引數,index屬性設定引數的順序,引數順序應該與建構函式的一致,ref設定引用bean的id,value設定建構函式引數的值。

  <bean id="xmlcontructinstance" class="com.demo.model.XMLInstance">
      <constructor-arg index="1" ref="CleanAir"></constructor-arg>
      <constructor-arg index="0" value="abc"></constructor-arg>
  </bean>

三、工廠方法注入
工廠方法注入參考的是工廠設計模式,通過在工廠類中實現物件的例項化。工廠類負責建立一個或多個目標類例項,工廠類方法一般以介面或抽象類變數的形式返回目標類例項,工廠類對外遮蔽了目標類的例項化步驟,呼叫者甚至不用知道具體的目標類是什麼。工廠方法也分靜態工廠方法和非靜態工廠方法,靜態工廠方式不用例項化工廠類,直接通過類名呼叫,非靜態工廠方法需要先例項化工廠類,然後通過工廠類物件呼叫獲取物件。這裡建立了一個工廠類XMLFactory,在類中定義了一個靜態方法,和一個例項方法用來例項化bean物件。

package com.demo.model;

public class XMLFactory {
    
    public XMLInstance CreateInstance()
    {
        return new XMLInstance("instance",new CleanAir());
    }
    
    public static XMLInstance CreateStaticInstance()
    {
        return new XMLInstance("static instance",new CleanAir());
    }
}

1.靜態工廠方法
只需設定工廠方法對應的類,以及對應的工廠方法。

<bean id="xmlfactorystaticinstance" class="com.demo.model.XMLFactory" factory-method="CreateStaticInstance"></bean>

2.例項工廠方法
需要先例項化工廠類,再通過工廠類物件呼叫例項方法獲取bean物件。

 <bean id="xmlfactoryinstance" factory-bean="xmlfactory" factory-method="CreateInstance" destroy-method="DestoryMethod" init-method="InitMethod"></bean>

四、常見資料型別注入

(1)List屬性注入
使用<list>配置java.util.List型別的屬性。List屬性中元素可以是任何資料型別的值,如果是Java物件可以使用ref指定,或使用<bean>定義新例項。如果是基礎資料型別可直接用字串。<list>中的元素會按配置的先後順序排序。

      <property name="lists">
         <list>
            <value>1</value>
            <ref bean="CleanAir" />
             <bean class="com.demo.model.CleanAir"/>
        </list>
    </property>

(2)Set屬性注入
使用<set>配置java.util.Set型別的屬性。Set屬性中元素可以是任何資料型別的值,如果是Java物件可以使用ref指定,或使用<bean>定義新例項。如果是基礎資料型別可直接用字串。<set>中的元素沒有先後順序。

      <property name="sets">
        <set>
            <value>1</value>
            <ref bean="CleanAir" />
             <bean class="com.demo.model.CleanAir"/>
        </set>
    </property>

(3)Map屬性注入
使用<map>配置java.util.Map型別的屬性。<entry>配置Map裡的元素,Key指定索引,value指定值。如果是Java物件可以使用ref指定,或使用<bean>定義新例項。

    <property name="maps">
        <map>
           <entry key="key1" value="1"></entry>
            <entry key="key2" value-ref="CleanAir"></entry>
            <entry key="key3" >
                 <bean class="com.demo.model.CleanAir"/>
            </entry>
        </map>
    </property>

(4)Properties屬性注入
使用<props>配置java.util.Properties型別的屬性。<props>配置一個Properties物件,<prop>配置一條屬性,屬性Key配置索引。

    <property name="pros">
        <props>
            <prop key="prokey1">prokeyA</prop>
            <prop key="prokey2">prokeyB</prop>
        </props>
    </property>

(5)自定義屬性編輯器

對於有一些屬性是沒法注入的,此時就需要自定義,比如日期型別。可以通過繼承PropertyEditorSupport的類,重寫setAsText方法來實現注入。這裡定義了CustomerProperty繼承PropertyEditorSupport,重寫了setAsText方法,並將該bean配置到xml中。

package com.demo.model;

import java.beans.PropertyEditorSupport;
import java.text.ParseException;
import java.text.SimpleDateFormat;

public class CustomerProperty extends PropertyEditorSupport {
    private String format="yyyy-MM-dd";
    public String getFormat() {
        return format;
    }
    public void setFormat(String format) {
        this.format = format;
    }
    @Override
    public void setAsText(String text) throws IllegalArgumentException {
        
        SimpleDateFormat sdf=new SimpleDateFormat(format);
        //super.setAsText(text);
        try {
            //轉換物件,能過setValue方法重新賦值
            this.setValue(sdf.parse(text));
        } catch (ParseException e) {
            e.printStackTrace();
        }
    }
}
 <bean id="customEditorConfigurer" class="org.springframework.beans.factory.config.CustomEditorConfigurer">
     <property name="customEditors">
          <map>
               <entry key="java.util.Date" value="com.demo.model.CustomerProperty"/>
           </map>
     </property>
</bean>

配置之後就可以注入Date型別的屬性了。

    <property name="date" value="2018-8-20"/>

這裡新建了XmlCollectionsDemo類,配置了上面的幾個型別的屬性來演示。

package com.demo.model;

import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;

import org.springframework.beans.factory.BeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class XmlCollectionsDemo {
    
    private List<Object> list;
    
    private Properties pros;
    
    private Set<Object> sets;
    
    private Map<String,Object> maps;
    
    private Date date;
    
    public Date getDate() {
        return date;
    }

    public void setDate(Date date) {
        this.date = date;
    }

    public List<Object> list() {
        return list;
    }

    public void setLists(List<Object> list) {
        this.list = list;
    }

    public Properties getPros() {
        return pros;
    }

    public void setPros(Properties pros) {
        this.pros = pros;
    }

    public Set<Object> getSets() {
        return sets;
    }

    public void setSets(Set<Object> sets) {
        this.sets = sets;
    }

    public Map<String, Object> getMaps() {
        return maps;
    }

    public void setMaps(Map<String, Object> maps) {
        this.maps = maps;
    }
    
    public static void main( String[] args ) throws Exception
    {

        ApplicationContext context=new ClassPathXmlApplicationContext(new String[]{"ApplicationContext.xml"});
        BeanFactory factory=context;
        XmlCollectionsDemo annontationInstance=(XmlCollectionsDemo)factory.getBean("xmlCollectionsDemo");
        System.out.println(annontationInstance.list);
        System.out.println(annontationInstance.pros);
        System.out.println(annontationInstance.sets);
        System.out.println(annontationInstance.maps);
        System.out.println(annontationInstance.date);
    }
}
View Code
  <bean id="xmlCollectionsDemo" class="com.demo.model.XmlCollectionsDemo">
      <property name="lists">
         <list>
            <value>1</value>
            <ref bean="CleanAir" />
             <bean class="com.demo.model.CleanAir"/>
        </list>
    </property>
      <property name="sets">
        <set>
            <value>1</value>
            <ref bean="CleanAir" />
             <bean class="com.demo.model.CleanAir"/>
        </set>
    </property>
    <property name="maps">
        <map>
           <entry key="key1" value="1"></entry>
            <entry key="key2" value-ref="CleanAir"></entry>
            <entry key="key3" >
                 <bean class="com.demo.model.CleanAir"/>
            </entry>
        </map>
    </property>
    <property name="pros">
        <props>
            <prop key="prokey1">prokeyA</prop>
            <prop key="prokey2">prokeyB</prop>
        </props>
    </property>
    <property name="date" value="2018-8-20"/>
  </bean>
View Code

 通過執行main方法,打印出屬性值。
[1, CleanAir, CleanAir]
{prokey2=prokeyB, prokey1=prokeyA}
[1, CleanAir, CleanAir]
{key1=1, key2=CleanAir, key3=CleanAir}
Mon Aug 20 00:00:00 CST 2018

五、初始化函式、銷燬函式
通過上面3種注入方式的學習也對通過xml對bean例項化有的瞭解,有的物件在例項化之後還需要執行某些初始化程式碼,但這些初始化程式碼還不能寫在建構函式中,此時可以將初始化程式碼寫到某個方法中,將init-method屬性值設定為該方法,Spring會強制執行該方法進行初始化。而又的物件在使用完畢之後需要釋放,可以使用destroy-method來進行銷燬。

    public void DestoryMethod()
    {
        System.out.println("DestoryMethod");
    }
    public void InitMethod()
    {
        System.out.println("InitMethod");
    }

這裡先在XMLInstance類中增加了上面兩個方法來模擬銷燬和初始化方法。然後在xml配置bean時就可以設定destroy-method、init-method屬性的值對應兩個方法的方法名。註解中@PostConstruct對應init-method,@PreDestory對應destroy-method。

<bean id="xmlfactoryinstance" factory-bean="xmlfactory" factory-method="CreateInstance" destroy-method="DestoryMethod" init-method="InitMethod"></bean>

二、註解注入方式

一、常用註解介紹
學習完XML注入之後再學習註解方式注入就容易的多,註解方式注入主要涉及到@Autowired,@Resource,@Required,@Qualifier,@Value這幾個註解。在第2章節的2.2.4IOC例項中定義Person時就使用過@Autowired、@Qualifier。下面來了解下它們具體用法。
@Autowired:預設是按型別匹配注入bean,它可以對類成員變數、方法及建構函式進行標註,完成自動裝配的工作。在使用@Autowired時,首先在容器中查詢對應型別的bean,如果查詢結果剛好為一個,就將該bean裝配給@Autowired指定的資料,如果查詢的結果不止一個,那麼@Autowired會根據名稱來查詢。如果查詢的結果為空,那麼會丟擲異常。解決方法時,使用required=false。
@Required:適用於bean屬性setter方法,並表示受影響的bean屬性必須在XML配置檔案在配置時進行填充。否則,容器會丟擲一個BeanInitializationException異常。
@Qualifier:@Autowired預設是單例項的,但是在面向介面程式設計中,如果把一個屬性設定為介面型別,一個介面可能有多個實現,那到底是注入哪一個呢?為了解決這個問題,就有了@Qualifier。
@Value:在xml配置屬性時可以通過property的value設定預設值,@Value也可以為屬性設定預設值。
@Resource:預設按名稱匹配注入bean。要求提供一個bean名稱的屬性,如果屬性為空,則自動採用標註處的變數名或方法名作為bean的名稱。如果我們沒有在使用@Resource時指定bean的名字,同時Spring容器中又沒有該名字的bean,這時候@Resource就會退化為@Autowired即按照型別注入。

package com.demo.model;

import javax.annotation.Resource;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Required;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

@Component
public class AnnontationInstance {
    
    @Value("abc")
    private String name;
    
    
    public void setName(String name) {
        this.name = name;
    }
    
    //@Resource與@Autowired兩者選其一
    //    @Autowired
    //    @Qualifier(value="cleanair")
    private IAir air;
    @Resource(name="CleanAir")
    public void setAir(IAir air) {
        this.air = air;
    }
    
    public void Breath()
    {
        System.out.println("Name:"+this.name+";Air:"+this.air.toString());
    }
}

上面程式碼使用@Value註解為name設定了預設值,使用@Resources設定bean的名稱為IAir屬性注入bean,也可以使用@[email protected]為IAir注入bean。

二、開啟註解
上面配置完註解之後,還要告訴Spring開啟註解,這樣@Autowired、@Resources這些註解才起作用。開啟有兩種比較簡單的方式。
1.在xml配置檔案中使用context:annotation-config

  <context:annotation-config />

2.在xml配置檔案中使用context:component-scan

<context:component-scan base-package="com.demo.model"/>

相關推薦

SSM框架專案搭建系列(五)—SpringBean的註解注入

applicationContext.xml <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/bea

SpringBean注入

Bean的配置中介紹的是Bean宣告問題,在哪宣告怎麼宣告的問題。Bean的注入是怎麼例項化,怎麼注入的問題。Bean注入的方式有兩種,一種是在XML中配置,另一種則是使用註解的方式注入。 一、XML方式注入 XML方式注入一般有三種方式:屬性注入、建構函式注入和工廠方法注入。 一、屬性注入在傳統的物件例項化

SSM框架專案搭建系列(四)— Springbean的XML注入方式

在XML中可使用兩種方式進行注入:建構函式注入和setter注入 建構函式注入constructor 直接傳值 applicationContext.xml <bean id="helloworldBeanId" class="com.ssm.b

Spring Bean的裝配

med post java set pac () 構造參數 單元 引用 Spring Bean的裝配分為3中: 1、隱式發現和自動裝配   @Component:將一個Java類聲明為Bean(組件類),等待Spring掃描發現。   @ComponentScan:啟用組件

SpringBean的註入

函數的參數 span sta 工廠類 false 介紹 類型 簡單 prope Bean的配置中介紹的是Bean聲明問題,在哪聲明怎麽聲明的問題。Bean的註入是怎麽實例化,怎麽註入的問題。Bean註入的方式有兩種,一種是在XML中配置,另一種則是使用註解的方式註入。 一、

SpringBean的作用域與生命周期

src efi lin 控制 初始化 troy [] 分享 isp 在前面博客中提到容器啟動獲得BeanDefinition對象中有一個scope 屬性。該屬性控制著bean對象的作用域。本章節介紹Bean的作用域及生命周期,了解bean是怎麽來的又怎麽沒的。 一、Bean

Spring Bean 的 Scope

Bean 的 Scope Scope 描述的是 Spring 容器如何新建 Bean  的例項的. Spring 的 Scope 有以下幾種,通過 @Scope 註解來實現. Singleton: 一個 Spring 容器中只有一個 Bena 的例項,此為 Spring

SpringBean的生命周期

web nec connector start jasper dep oca cep table ---恢復內容開始--- Spring中關於Bean的生命周期,我總結的大致過程如下: 1、用戶調用BeanFactory接口的getBean()方法請求一個

SpringBean學習

簡述:Spring框架主要是涉及到IOC(控制反轉)和AOP(切面程式設計)兩大重點 IOC和DI(依賴注入)其實就是等同的意思,就是建立物件和維護物件,放在一個容器裡,直接依賴注入即可使用 AOP的存在目的是為了解耦即高內聚,低耦合 Bean的取值範圍    &nb

Springbean例項的建立

在上一篇部落格中,我們已經對bean的載入跟著原始碼完整的走了一遍,程式碼讀起來很輕鬆,主要還是Spring的程式設計風格,它把每段程式碼分割成一個一個的小邏輯,使得每個邏輯處理起來都不是很負責,非常有利於我們學習。接下來,我們繼續對bean例項的建立進行閱讀。

也談Spring依賴注入DI/控制反轉IOC

首先提問, 什麼是 Spring IOC 容器?         Spring 框架的核心是 Spring 容器。容器建立物件,將它們裝配在一起,配置它們並管理它們的完整生命週期。Spring 容器使用依賴注入來管理組成應用程式的元件。容器通過讀取提供的配置元資料來接收物件

springBean注入和P標籤使用

1.構造方法引數 對應 配置檔案 <constructor-arg> 元素 可以index|name|type 三選一 、三選二  ; ref|value 二選一 2. setter方法注入(開發推薦) 為需要注入屬性提供setter方法 配置 每個注入

SpringBean管理------註解方式

編寫測試類 1,編寫相關的類 public interface UserDao { public void sayHello(); } public class UserDaoImpl implements UserDao { @Override public void sayHello() { S

SpringBean實現了ApplicationContextAware等aware介面,對於setApplicationContext方法執行時間點的說明

  在Spring中,如果Bean物件實現了ApplicationContextAware介面,則Spring在完成Bean的初始化後,會將ApplicationContext上下文物件注入至該Bean物件中,注入方法為呼叫Bean的setApplicationContex

springbean的Scope

上篇文章較為詳細了對各種情況下bean依賴的配置做了說明,但一直沒有對Scope這個屬性進行說明。本篇將一起學習。本文演示程式碼下載地址 當我們在xml配置檔案中配置一個bean的定義的時候,可以認為是配置了一個模板,可以根據這個模板來生成很多個物件來滿足整個應用程式的依賴

Springbean注入初始化方式—通過註解@Configuration @bean

雖然 2.0 版本釋出以來,Spring 陸續提供了十多個註解,但是提供的這些註解只是為了在某些情況下簡化 XML 的配置,並非要取代 XML 配置方式。這一點可以從 Spring IoC 容器的初始化類可以看出:ApplicationContext 介面的最常用的實現類是

Java多執行緒中SpringBean注入失敗

問題說明 : 在spring框架進行專案開發,平時遇到了需要批量處理的資料的時候,會選擇多執行緒進行資料批跑,但是會發現,啟動多執行緒後,執行緒會出現service或者mapper檔案注入失敗的問題,導致執行緒啟動失敗,其中bean的注入方式選擇的是spring常規的註解@A

spring依賴注入與控制反轉的區別

 IoC——Inversion of Control  控制反轉  DI——Dependency Injection   依賴注入         要想理解上面兩個概念,就必須搞清楚如下的問題: 參與者都有誰?依賴:誰依賴於誰?為什麼需要依賴? 注入:誰注入於誰?到底

SpringBean的作用域與生命週期

在前面部落格中提到容器啟動獲得BeanDefinition物件中有一個scope 屬性。該屬性控制著bean物件的作用域。本章節介紹Bean的作用域及生命週期,瞭解bean是怎麼來的又怎麼沒的。 一、Bean的作用域在Bean容器啟動會讀取bean的xml配置檔案,然後將xml中每個bean元素分別轉換成Be

SpringBean的配置方式

在部落格中為了演示容器Bean例項化時暴露出的幾個介面,將UserBean配置在XML中,其實常見的Bean的配置有3種。1.基於xml配置Bean 2.使用註解定義Bean 3.基於java類提供Bean定義資訊。 一、基於xml配置Bean 基於XML配置Bean時,Spring通過<bean>