天天看點

Spring進階之路(1)-Spring核心機制:依賴注入/控制反轉 依賴注入與控制反轉 依賴注入兩種方式 設值注入和構造注入的對比

我們經常會遇到這樣一種情景,就是在我們開發項目的時候經常會在一個類中調用其他的類中的方法,來完成我們期望的任務,大部分的情況下往往會采用在目前需要的這個類裡面new一個執行個體出來,然後調用他的方法,那麼這樣的話會有個問題,就是有一天我想改變下這個類,改為其他的名稱,那麼這時候必須要做的是同時去調用方的類檔案中改變這個改變的類的名稱。這樣的情況是因為代碼的耦合帶來了後期維護成本的增加,那麼spring的出現就可以很好的起到解耦的作用,而他的核心機制就是依賴注入。

依賴注入:對于spring而言,将自己置身于spring的立場上去看,當調用方需要某一個類的時候我就為你提供這個類的執行個體,就是說spring負責将被依賴的這個對象指派給調用方,那麼就相當于我為調用方注入了這樣的一個執行個體。從這方面來看是依賴注入。

控制反轉:對于調用方來說,通常情況下是我主動的去建立的,也就是對于這個對象而言我是控制方,我有他産生與否的權力,但是,現在變了,現在變為spring來建立對象的執行個體,而我被動的接受,從這一點上看,是控制反轉。

這兩者的意思是一緻的,就看你從誰的角度去看這個問題。不同的角度那麼看到的問題可能是不一樣的。

設值注入:通過set的方式注入值.Ioc容器通過成員變量的setter方法來注入被依賴的對象,這種注入方式簡單,直覺,因而在spring中大量的使用。

下面我們采用實際的例子來體會一下:

假設這樣的一個場景,我想列印消息,這樣一件事情

首先定義一個MessageService的接口。

package com.siti.spring20160227;  

public interface MessageService {  

    /** 

     * 消息列印 

     */  

    public void printMessage();  

}  

然後實作這個接口,并實作這個方法。

public class MessagePrinter implements MessageService {  

    @Override  

    public void printMessage() {  

        System.out.println("輸出消息!");  

    }  

那麼對于我而言,我也定義一個person的接口

public interface Person {  

     * 人發送消息 

    public void sendMessage();  

我來實作人這個接口

public class WangYang implements Person{  

    private MessageService service;  

    public void setService(MessageService service) {  

        this.service = service;  

    public void sendMessage() {  

        this.service.printMessage();  

Spring的配置檔案:

<?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 definitions here -->  

    <bean id = "messageService" class = "com.siti.spring20160227.MessagePrinter"></bean>  

    <bean id = "wy" class = "com.siti.spring20160227.WangYang">  

        <property name="service" ref="messageService"></property>  

    </bean>  

</beans>  

測試類如下:

import org.springframework.context.ApplicationContext;  

import org.springframework.context.support.ClassPathXmlApplicationContext;  

public class MainTest {  

    public static void main(String[] args) {  

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

        Person person = context.getBean("wy", Person.class);  

        person.sendMessage();  

通過構造函數的方式注入。spring以反射的方式執行帶指定參數的構造器,當執行帶參數的構造器時就可以通過構造器的參數指派給成員變量,完成構造注入。

那麼現在需求變了,我需要改一些東西,下面可以注意下我主要改動了哪裡:

在WangYang這個類中添加有參數和無參數的構造函數:

    <span style="color:#33ff33;">public WangYang() {  

        super();  

    public WangYang(MessageService service) {  

    </span>public void setService(MessageService service) {  

在Spring配置檔案中,稍微改動,即将原來的設值注入換為構造注入即可。

        <!-- <property name="service" ref="messageService"></property> -->  

        <span style="color:#33ff33;"><constructor-arg ref="messageService"></constructor-arg></span>  

這樣再次運作MainTest類,程式正常運作。是以從這裡也可以體會到,spring這種解耦的友善性和重要性。

這兩種方式,效果是一樣的,注入的時機不同,設值注入是先調用無參的構造函數,建立出執行個體後然後調用set方法注入屬性值。而構造輸入是通過在調用構造函數初始化執行個體的同時完成了注入。

1. 通過set的方式設定依賴關系顯得更加直覺,自然,和javabean寫法類似。

2. 複雜的依賴關系,采用構造注入會造成構造器過于臃腫,spring 執行個體化的時候同時執行個體化其依賴的全部執行個體,導緻性能下降,set方式可以避免這些問題。

3. 在成員變量可選的情況下,構造注入不夠靈活。

某些特定的情況下,構造注入比設值注入好一些。

1. 構造注入可以在構造器中決定依賴關系的注入順序,優先依賴的優先注入,構造注入可以清楚的厘清注入的順序。

2. 元件的調用者無需知道元件内部的依賴關系,符合高内聚原則。