Spring IoC-依賴注入與屬性裝配(1)-自動裝配

概述

Spring容器能夠通過檢查ApplicationContext中的內容來實現依賴自動裝配.

自動轉配的模式

Spring IoC定義了幾種裝配模式可供選擇:

模式 解釋
no 不開啓自動裝配
byName 通過名稱自動裝配, 在容器中查找名稱然後裝配
byType 通過類型自動裝配, 容器在內部查找匹配的類型進行自動裝配, 如果存在多個會引發致命錯誤, 如果不村子一個則不會報錯
constructor 通過構造函數自動裝配, 和byType類似, 如果不存在bean, 則會報錯

自動裝配示例

使用註解方式實現自動裝配, 首先需要對Bean的類標註@Component或則類似註解來指示Spring IoC這是一個可以由Spring容器管理的Bean的類. 再在需要註釋的構造函數或者字段或則setter方法上標註@Autowired註解來實現自動注入.

簡單示例

@Component
public class Keyboard {
    private String name;

    public Keyboard() { }

    public Keyboard(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return "Keyboard{" +
                "name='" + name + '\'' +
                '}';
    }
}

@Component
public class Computer {
    private Keyboard keyboard;

    @Autowired
    public Computer(Keyboard keyboard) {
        this.keyboard = keyboard;
    }

    @Override
    public String toString() {
        return "Computer{" +
                ", keyboard=" + keyboard +
                '}';
    }
}

public class DIDemo {
    public static void main(String[] args) {
        String scanPackages = "lab.anoper.ioc.di.computer.component";
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(scanPackages);
        Computer computer = context.getBean("computer",
                lab.anoper.ioc.di.computer.component.Computer.class);
        System.out.println(computer);
    }
}

輸出結果:

Computer{, keyboard=Keyboard{name='null'}}

多個同類型報錯示例

java代碼:

@Configuration
public class ComputerConfig {
    @Bean
    public Keyboard keyboard1() {
        return new Keyboard("keyboard1");
    }

    @Bean
    public Keyboard keyboard2() {
        return new Keyboard("keyboard2");
    }
}

@Component
public class Computer {
    private Keyboard keyboard;

    @Autowired
    public Computer(Keyboard keyboard) {
        this.keyboard = keyboard;
    }

    @Override
    public String toString() {
        return "Computer{" +
                ", keyboard=" + keyboard +
                '}';
    }
}

public class Keyboard {
    private String name;

    public Keyboard() { }

    public Keyboard(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return "Keyboard{" +
                "name='" + name + '\'' +
                '}';
    }
}

public class DIDemo {
    public static void main(String[] args) {
        String scanPackages = "lab.anoper.ioc.di.computer";
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(scanPackages);
        Computer computer = context.getBean("computer",
                lab.anoper.ioc.di.computer.component.Computer.class);
        System.out.println(computer);
    }
}

輸出結果:

Caused by: org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'lab.anoper.ioc.di.computer.component.Keyboard' available: expected single matching bean but found 2: keyboard1,keyboard2
Caused by: org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'lab.anoper.ioc.di.computer.component.Keyboard' available: expected single matching bean but found 2: keyboard1,keyboard2

說明構造函數自動裝配模式下, 當有超過一個同類型bean時候, 會報出致命錯誤.

  • 解決方案1: 修改代碼, 使用@Primary註解標註一個主要的bean, 則可以成功.
@Configuration
public class ComputerConfig {
    @Bean
    @Primary
    public Keyboard keyboard1() {
        return new Keyboard("keyboard1");
    }

    @Bean
    public Keyboard keyboard2() {
        return new Keyboard("keyboard2");
    }
}
  • 解決方案2: 使用@Qualifier註解明確需要裝配的bean的名稱.
@Component
public class Computer {
    private Keyboard keyboard;

    @Autowired
    public Computer(@Qualifier("keyboard2") Keyboard keyboard) {
        this.keyboard = keyboard;
    }

    @Override
    public String toString() {
        return "Computer{" +
                ", keyboard=" + keyboard +
                '}';
    }
}

優缺點

優點:

  • 減少了屬性配置或者是構造函數配置.
  • 在更新代碼時候, 更懂更小, 不必更新依賴關係.

缺點:

  • 顯式的申明總是會覆蓋掉自動裝配.
  • 不如顯式裝配精確.
  • 如果有同一個類型的多個值存在, 可能引發錯誤.

總結

使用@Autowired註解可以實現自動注入. 配置在屬性字段名上使用setter方法注入, 配置在構造函數上將使用構造函數方式注入. 如果有個同類型的bean則會導致致命注入失敗, 可以使用@Prmiary註解來確定一個主要組件, 或者在注入點使用@Qualifier來註明使用的bean的名字.

參考

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章