解析Spring DI 依赖注入的5种方式

一、什么是DI

案例工程代码下载
DI,是dependence injection的简称,译为依赖注入,和上一篇解释的IOC控制反转思想是一个意思,IOC是用来创建对象的思想,DI依赖注入,就是在配置Spring容器(xxx.xml文件)创建对象的同时为对象注入属性值。而依赖注入的方式有5种:Setter注入(set方法注入)、interface注入(接口注入)、constructor注入(构造注入)、autowire注入(自动注入)、Annotation注入(注解注入)。

二、5种依赖注入方式

(一)Setter注入

用Setter注入方式的类中必须提供set方法生效,否则会报错。我们来实现实现一下Setter注入方式:

1.创建ClassB类,定义属性和提供set方法,重写toString方法(更改输出格式,输出属性值,也可以不重写)。
package testspringIOCDI.id;
import java.util.Date;

/**数据bean,类ClassB
 * @author CenterLogo
 *create date :2019年4月25日 下午7:05:56
 */
public class ClassB {
	 private String userid;
	 private String username;
	 private Date hiraedate;
	 
	public void setUserid(String userid) {
		this.userid = userid;
	}
	
	public void setUsername(String username) {
		this.username = username;
	}

	public void setHiraedate(Date hiraedate) {
		this.hiraedate = hiraedate;
	}

	@Override
	public String toString() {
		return "ClassB [userid=" + userid + ", username=" + username + ", hiraedate=" + hiraedate + "]";
	}
	 public void method(){
		 System.out.println("I'm classB");
	 }
}
2.在Spring容器(我这里创建的是SpringDI.xml)中配置信息,实现Setter注入。在SpringDI中配置如下:
<?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">
<!-- setter注入(属性值),条件是类中必须有对应set方法 -->
       <!-- 创建classb对象 -->
		<bean id="classb" class="testspringIOCDI.id.ClassB">
		<!-- setter注入,给属性赋值,这里的作用是调用setUserid(10010)方法 -->
		   <property name="userid" value="100010"></property>
		   <property name="username">
		     <value>Lily</value>
		  
		  <!-- 属性值是对象(日期对象),在property属性标签中添加gbean标签,此处 相当于classb.setHiredate(new java.util.Date()); -->
		   </property>
		   <property name="hiraedate">
		    <bean  class="java.util.Date"></bean>
		   </property>
		</bean>
</beans>
3.创建ClassB的测试类,用来测试是否能成功获取Setter注入后ClassB类的对象。
package testspringIOCDI.id;
import static org.junit.Assert.*;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
 * @author CenterLogo
 *create date :2019年4月25日 下午:22:43
 */
public class DITest {
	@Test
	public void test() {
		//获取上下文实例,使用ClassPathXmlApplicationContext不需要写路径,只需要写xml文件名
		ApplicationContext context=new ClassPathXmlApplicationContext("SpringDI.xml");
		//从容器中获取具体对象
		ClassB cb=context.getBean("classb",ClassB.class);
		 System.out.println(cb);
	}
}

测试成功的结果如此下,控制台输出:

ClassB [userid=100010, username=Lily, hiraedate=Sun Apr 28 15:46:31 CST 2019]

(二)interface注入

interface注入原理和Setter注入一样,只不过是类的属性定义中存在接口,我们需要在Spring容器中创建接口的实现类对象,将实现类对象赋值给接口。具体实现方式如下:

1.创建InterfaceA接口
//InterfaceA接口
package testspringIOCDI.ioc;
public interface InterfaceA {
   public String getInfo();
	 public void method();
}
2.创建InterfaceA接口的实现类ClassA
//创建InterfaceA的实现类
package testspringIOCDI.ioc;
public class ClassA implements InterfaceA {
	public ClassA(){}
	public String getInfo() {
		// TODO Auto-generated method stub
		return "企业管理系统模块:实现公告发布、修改、删除等操作";
	}
	 public void method(){
		 System.out.println("I'm classA");	 
	 }
}
3.创建ClassC,当中具有一个InterfaceA属性,并提供set方法。
package testspringIOCDI.id;
import testspringIOCDI.ioc.InterfaceA;
/**
 * @author CenterLogo
 *create date :2019年4月25日 下午9:12:23
 */
public class ClassC {
private InterfaceA ia;
public void setIa(InterfaceA ia) {
	this.ia = ia;
}
public void mentho(){
	System.out.println("interface注入:"+ia.getInfo());
}
}
4.配置Spring容器(SpringDI.xml)文件,实现interface注入。
<?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">
		                    
		<!-- interface注入 --><!-- 有interface属性,必须有set方法 -->
		<bean id="classa" class="testspringIOCDI.ioc.ClassA"></bean><!-- 获取实现接口类的对象 -->
		<bean id="classc" class="testspringIOCDI.id.ClassC"><!-- 将获取实现接口类的对象作为属性注入 -->
		<property name="ia" ref="classa"></property>
		</bean>
</beans>
5.创建ClassC的测试类,测试注入是否成功。
package testspringIOCDI.id;
import static org.junit.Assert.*;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
 * @author CenterLogo
 *create date :2019年4月25日 下午9:24:53
 */
public class InterfaceTest {
	@Test
	public void test() {
		ApplicationContext context=new ClassPathXmlApplicationContext("SpringDI.xml");
		ClassC cc=(ClassC) context.getBean("classc");
		cc.mentho();
	}
}

测试成功的结果在控制台显示如下:

interface注入:企业管理系统模块:实现公告发布、修改、删除等操作

(三)constructor注入(构造注入)

constructor注入,要想以这种方式给类注入属性,该类必须同时含有无参构造方法和有参构造方法(不需要set方法)。其原理是Spring容器会根据类的有参构造方法去给属性赋值。演示实现constructor注入如下:

1.创建ClassB,定义属性,提供无参和有参构造。
package testspringIOCDI.id;
import java.util.Date;
/**数据bean
 * @author CenterLogo
 *create date :2019年4月25日 下午7:05:56
 */
public class ClassB {
	 private String userid;
	 private String username;
	 private Date hiraedate;
	public ClassB() {}//无参构造
	public ClassB(String userid, String username, Date hiraedate) {//有参构造
		super();
		this.userid = userid;
		this.username = username;
		this.hiraedate = hiraedate;
	}
	@Override
	public String toString() {
		return "ClassB [userid=" + userid + ", username=" + username + ", hiraedate=" + hiraedate + "]";
	}
	 public void method(){
		 System.out.println("I'm classB"); 
	 }
}
2.在Spring容器(SpringDI.xml)文件中配置constructor注入方式,通过参数下标注入。
<?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 id="date" class="java.util.Date"></bean>
		<bean id="classbct" class="testspringIOCDI.id.ClassB">
		  <constructor-arg index="0" value="20"/>
		  <constructor-arg index="1" value="center"/>
		  <constructor-arg index="2" ref="date"/>
		</bean>  
</beans>
3.创建ClassB的测试类,测试constructor注入是否成功。
package testspringIOCDI.id;
import static org.junit.Assert.*;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
 * @author CenterLogo
 *create date :2019年4月25日 下午9:58:10
 */
public class ConstructorTest {
	@Test
	public void test() {
		ApplicationContext context=new ClassPathXmlApplicationContext("SpringDI.xml");
		ClassB cb=(ClassB) context.getBean("classbct");
		System.out.println(cb);
	}
}

测试成功的结果在控制台显示如下:

ClassB [userid=20, username=center, hiraedate=Sun Apr 28 16:27:42 CST 2019]

(四)autowire注入(自动注入)

autowrie注入,必须提供set方法。Spring容器可以通过类中定义的属性类(类中有属性,这个属性的类型是一个类)的类型或名字来确定用哪一个对象赋值。但是要保证容器中的类的类型必须唯一或者保证成员变量名与容器中的id必须保持一致。演示autowrie注入实现如下:

1.创建ClassE,定义属性有ClassA类和ClassC类(已经创建好),并提供set方法。
package testspringIOCDI.id;
import testspringIOCDI.ioc.ClassA;
/**
 * @author CenterLogo
 *create date :2019年4月26日 下午8:16:58
 */
public class ClassE {
  private ClassC classc;
  private ClassA classa;

public void setClassc(ClassC classc) {
	this.classc = classc;
}
public void setClassa(ClassA classa) {
	this.classa = classa;
}
public void  method(){
	  classc.mentho();
	  classa.method();
	  System.out.println("succeed");
  }
}
2.配置Spring容器(Spring.xml)文件,采用aotuwire注入方式。
<?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">
		<!-- interface注入 --><!-- 有interface属性,必须有set方法 -->
		<bean id="classa" class="testspringIOCDI.ioc.ClassA"></bean><!-- 获取实现接口类的对象 -->
		<bean id="classc" class="testspringIOCDI.id.ClassC"><!-- 将获取实现接口类的对象作为属性引入 -->
		<property name="ia" ref="classa"></property>
		</bean>

      <!-- autowire注入 -->
       <!-- 方式一:byName 条件:classc和classa的id必须和ClassE中的成员变量名一致 -->
      <bean id="cename" class="testspringIOCDI.id.ClassE" autowire="byName"/>
      <!-- 方式二:byType 条件:容器中必须ClassA和ClassC的类型对象分别只能有一个-->
    <bean id="cetype" class="testspringIOCDI.id.ClassE" autowire="byType"/> 
</beans>
2.创建ClassE的测试类,测试autowire注入是否成成功。
package testspringIOCDI.id;
import static org.junit.Assert.*;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.ClassPathBeanDefinitionScanner;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
 * @author CenterLogo
 *create date :2019年4月26日 下午8:29:54
 */
public class autowireTest {
	@Test
	public void test() {
		ApplicationContext context=new ClassPathXmlApplicationContext("SpringDI.xml");
		ClassE cename=(ClassE) context.getBean("cename");
		ClassE cetype=(ClassE) context.getBean("cetype");
		cename.method();
		cetype.method();
}
}

测试成功结果在控制台输出如下:

interface注入:企业管理系统模块:实现公告发布、修改、删除等操作
I’m classA
succeed
interface注入:企业管理系统模块:实现公告发布、修改、删除等操作
I’m classA
succeed

(五)annotation注入(自动注入)

annotation注入较为简单,也使代码更为简洁,一般作为注入都首选。annotation注入需要的条件为:一是需要类提供注解方式;二是需要在Spring中开启注解和对属性类的声明。
演示实现annotation如下:

1.创建ClassF,定义接口InterfaceA(前提是已创建InterfaceA类和其实现类,代码详见interface注入)并提供注解。
package testspringIOCDI.id;
import javax.annotation.Resource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import testspringIOCDI.ioc.InterfaceA;
/**
 * @author CenterLogo
 *create date :2019年4月26日 下午8:58:50
 */
public class ClassF {
@Resource      //注解1
private InterfaceA ia1;
@Resource(name="classa")//注解2
private InterfaceA ia2;
@Autowired  //注解3
private InterfaceA ia3;
@Autowired  //注解四
@Qualifier("classa")
private InterfaceA ia4;
public void method(){
	System.out.println(ia1.getInfo());
	System.out.println(ia2.getInfo());
	System.out.println(ia3.getInfo());
	System.out.println(ia4.getInfo());
	System.out.println(ia1.getInfo());//只能使用接口中存在的方法
	ia1.method();
}
}

代码部分解释:
(1)@Resoure 先根据容器中类的类型匹配,如果类型匹配不到,则根据名字匹配。
(2)@Resoure(name=“classa”) 根据id名字匹配
(3)@Autowired 自动匹配,根据类型。
(4)@Autowired
@Qualifier(“classa”) 根据Spring中指定的id名字自动匹配
(5)@Resoure 是jdk自带的注解,@Autowired是Spring beans提供的注解。

2.在Spring容器中添加context规则,开启注解,并声明bean对象。
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
		xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
		xmlns:context="http://www.springframework.org/schema/context"
		xsi:schemaLocation="http://www.springframework.org/schema/beans
		                    http://www.springframework.org/schema/beans/spring-beans.xsd
		                    http://www.springframework.org/schema/context
		                    http://www.springframework.org/schema/context/spring-context.xsd">
    <!-- annotation注入,开启注解 -->
    <context:annotation-config/>
    
      <!-- 声明对象 -->
  <bean id="classa" class="testspringIOCDI.ioc.ClassA"></bean><!-- 获取实现接口类的对象 -->
    <bean id="classf" class="testspringIOCDI.id.ClassF" />
</beans>
3.创建ClassF测试类,测试annotation是否成功。
package testspringIOCDI.id;
import static org.junit.Assert.*;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
 * @author CenterLogo
 *create date :2019年4月26日 下午9:18:54
 */
public class annotationTest {
	@Test
	public void testMethod() {
		ApplicationContext context=new ClassPathXmlApplicationContext("SpringDI.xml");
         ClassF cf=(ClassF) context.getBean("classf");
         cf.method();
	}
}

测试成功结果在控制太显示如下:

企业管理系统模块:实现公告发布、修改、删除等操作
企业管理系统模块:实现公告发布、修改、删除等操作
企业管理系统模块:实现公告发布、修改、删除等操作
企业管理系统模块:实现公告发布、修改、删除等操作
企业管理系统模块:实现公告发布、修改、删除等操作
I’m classA

  • 3
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值