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");
	}
相关文章
相关标签/搜索