Spring框架 - IoC容器依賴注入

依賴注入

強依賴

public class ScrewDriver {
    private Header header = new StraightHeader();
    
    public void use(){
            System.out.println("Use straight screwdriver");
        }
}

若是咱們這裏須要更換成爲十字刀類,咱們就須要從新編譯程序java

public class ScrewDriver {
    private Header header = new CrossHeader();
    
    public void use(){
            System.out.println("Use cross screwdriver");
        }
}

若是咱們這裏須要修改實現類的屬性和參數spring

public class ScrewDriver {
    private Header header = new StraightHeader("green",15);
    
    public void use(){
            System.out.println("Use straight screwdriver");
        }
}

這種狀況下Header與具體實現類,產生強依賴。只能經過修改代碼,纔可以處理。app

public class ScrewDriver {
    private Header header;

    public ScrewDriver(Header header){
        this.header = header;
    }
    
    public void use(){
            System.out.println("Use " + header.getType() + " screwdriver");
        }
}

IoC

  • 定義接口
  • 實現接口
  • 以接口爲基礎注入

依賴注入方式

  • 基於構造函數
public class ScrewDriver {
    private Header header;

    public ScrewDriver(Header header){
        this.header = header;
    }
}
  • 基於Setter方法
public class ScrewDriver {
    private Header header;

    public setHeader(Header header)
        this.header = header;
    }
}

注入方式的選擇

若是是強依賴咱們使用構造函數,若是是可選依賴,咱們使用Setter方法。強依賴舉例,咱們的螺絲刀必須有刀頭,可選以來就是一些可配置的內容,好比顏色 輸入圖片說明函數

依賴注入類型

  • 基本類型(int,String)
  • 集合
  • Bean
  • 配置文件

代碼示例

經過構造函數的方式

定義接口this

package com.netease.course;

public interface Header {
	public void doWork();
	public String getInfo();
}

接口實現spa

package com.netease.course;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

@Component("header")
public class StraightHeader implements Header {
	@Value("${color}")
	private String color;
	@Value("${size}")
	private int size;

	@PostConstruct
	public void init() {
		System.out.println("init the header");
	}

	@PreDestroy
	public void destroy() {
		System.out.println("destroy the header");
	}

	public void doWork() {
		System.out.println("Do work with straight header");
	}

	public String getInfo() {
		return "StraightHeader: color=" + color + ", size=" + size;
	}
}

最重要的部分Bean的注入配置可使用如下三種方式都可以配置注入
方式一.net

<bean id="header" class="com.netease.course.CrossHeader" >
		<constructor-arg index="0" value="green"/>
		<constructor-arg index="1" value="15"/>
	</bean>

方式二prototype

<bean id="header" class="com.netease.course.CrossHeader" >
		<constructor-arg index="0" type="java.lang.String" value="green"/>
		<constructor-arg index="1" type="int" value="15"/>
	</bean>

方式三code

<bean id="header" class="com.netease.course.CrossHeader" >
		<constructor-arg name="size" value="green"/>
		<constructor-arg name="color" value="15"/>
	</bean>

使用component

package com.netease.course;

import org.springframework.context.ApplicationContext;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class TestContainer {
	public static void main(String[] args) {
		ApplicationContext context = new ClassPathXmlApplicationContext("application-context.xml");

		Header header = context.getBean("header", CrossHeader.class);
		System.out.println(header.getInfo());
		header.doWork();

		((ConfigurableApplicationContext) context).close();
	}
}

輸出結果

com.netease.course.CrossHeader@6325a3ee green 15
doWork

經過構造函數注入集合

public CrossHeader(Map<String,String> params)
    {
        this.color = params.get("color");
        this.size = Integer.valueOf(params.get("size"));
    }

注入配置

<bean id="header2" class="com.netease.course.CrossHeader" >
		<constructor-arg>
			<map>
				<entry key="color" value="red"/>
				<entry key="size" value="15"/>
			</map>
		</constructor-arg>
	</bean>

經過構造函數注入prop

<bean id="header_prop" class="com.netease.course.CrossHeader" >

		<constructor-arg type="java.util.Properties">
			<props>
				<prop key="color">red</prop>
				<prop key="size">14</prop>
			</props>
		</constructor-arg>
	</bean>

待注入類

public CrossHeader(Properties properties)
    {
        this.color = properties.getProperty("color");
        this.size = Integer.parseInt(properties.getProperty("size"));
    }

Spring加載配置文件

<bean id="header_file" class="com.netease.course.CrossHeader" >
		<constructor-arg index="0" value="${color}"/>
		<constructor-arg index="1" value="${size}"/>
	</bean>

	<!-- Spring加載配置文件 -->
	<bean id="headerProperties"
		class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
		<property name="location" value="classpath:header.properties"  />
	</bean>

配置文件

color=yellow111
size=22

運行結果

com.netease.course.CrossHeader@2d6eabae yellow111 22
doWork

經過構造函數注入Bean

<bean id="screwDriver" class="com.netease.course.ScrewDriver" scope="prototype" init-method="init" destroy-method="destroy">
		<constructor-arg ref="header_file"/>
	</bean>

注入類

package com.netease.course;

public class ScrewDriver {

	private Header header;

	public ScrewDriver(Header header)
	{
		this.header = header;
	}

	public String color = "red";

	public void use(){
		System.out.println("color " + color + " use " + this);
		header.getInfo();
		header.doWork();
	}
}

輸出結果

Init com.netease.course.ScrewDriver@10bbd20a
color red use com.netease.course.ScrewDriver@10bbd20a
doWork

經過Setter注入基本類型

<bean id="straightHeader" class="com.netease.course.StraightHeader">
		<property name="color" value="${color}" />
		<property name="size" value="${size}" />
	</bean>

所注入的類

package com.netease.course;

public class StraightHeader implements Header {

	private String color;
	private int size;

	public String getColor() {
		return color;
	}

	public void setColor(String color) {
		this.color = color;
	}

	public int getSize() {
		return size;
	}
}

自動裝配

Spring爲了方便添加依賴,防止不少依賴,添加了自動裝配(Autowiring)的機制。不須要增長配置文件,經過添加註解的方式自動添加依賴注入。而不須要修改已有的配置文件。

自動裝配類型

  • byName:根據Bean名稱
  • byType:根據Bean類型
  • constructor:構造函數,根據類型

byName方式

若是經過byName會自動去查找對應名稱 相對應的Bean名稱進行自動裝配工做

<bean id="screwDriver_autowire" class="com.netease.course.ScrewDriver" autowire="byName">

	</bean>

byType

若是經過byType會自動去查找對應類型的對應Bean,注意重要的是,不可以出現多個相同類型的Bean對象。

<bean id="screwDriver_autowire" class="com.netease.course.ScrewDriver" autowire="byType">

	</bean>

若是具備多個相同類型的Bean,則會出現如下異常

NoUniqueBeanDefinitionException: No qualifying bean of type [com.netease.course.Header] is defined: expected single matching bean but found 5: header,header_map,header_prop,header_file,straightHeader

##經過Annotation註解方式進行注入 XML的方式雖然繁瑣,可是代碼是獨立,Annotation雖然簡單,可是代碼耦合。
當咱們定義Controller、Service定義一些基本的配置
當對外部組件時,使用XML配置更加合理

Annotation方式比較分散 輸入圖片說明

Annotation比較方便的注入

  • @Component:定義Bean
  • @Value:properties注入
  • @Autowired & @Resource 自動裝配依賴
    因爲@Autowired是Spring所獨有的,@Resource是javax當中定義的,則若是後續模塊想脫離Spring則使用@Resource的Annotation註解
  • @PostConstruct & @PreDestroy:生命週期

自動掃描配置

若是要啓動Annotation則必須使用自動掃描

<context:component-scan base-package="com.netease.course" />

自動注入類,無需在配置文件當中添加配置

package com.netease.course;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

@Component("header_annotation")
public class StraightHeader implements Header {
	@Value("${color}")
	private String color;
	@Value("${size}")
	private int size;

        // Getter and Setter

	@PostConstruct
	public void init() {
		System.out.println("init the header");
	}

	@PreDestroy
	public void destroy() {
		System.out.println("destroy the header");
	}
}

在Bean類中使用所注入的Bean對象

public class ScrewDriver {

		@Resource
	private Header header;
}

配置

<bean id="screwDriver_autowire" class="com.netease.course.ScrewDriver"></bean>

或者

public class ScrewDriver {

		@Autowired
	private Header header;
}

Bean初始化與銷燬注入

@PostConstruct
	public void init() {
		System.out.println("init the header");
	}

	@PreDestroy
	public void destroy() {
		System.out.println("destroy the header");
	}
相關文章
相關標籤/搜索