测试同学上手Spring 之DI深入解析

开发 前端
前面已经介绍了如何上手Spirng编码以及IOC的核心概念,今天给大家讲解Spring的另一个重点——DI。

[[389055]]

前面已经介绍了如何上手Spirng编码以及IOC的核心概念,今天给大家讲解Spring的另一个重点——DI。

Spring核心模块

DI概念

IoC 其实有两种方式,一种就是 DI(Dependency Injection) ,而另一种是 DL(Dependency Lookup)即依赖查找。前者是当前组件被动接受IoC容器注入的依赖组件,而后者则是组件主动去某个服务注册地查找其依赖的组件,我们这里重点介绍DI。

IoC的一个重点是在系统运行中,动态的向某个对象提供它所需要的其他对象。这一点是通过DI来实现的。比如对象A需要操作数据库,以前我们总是要在A中自己编写代码来获得一个Connection对象,有了spring我们就只需要告诉spring,A中需要一个Connection,至于这个Connection怎么构造,何时构造,A不需要知道。通过依赖注入机制,我们只需要通过简单的配置,而无需任何代码就可指定目标需要的资源,完成自身的业务逻辑,而不需要关心具体的资源来自何处,由谁实现。在系统运行时,spring会在适当的时候制造一个Connection,然后像打针一样,注射到A当中,这样就完成了对各个对象之间关系的控制。A需要依赖Connection才能正常运行,而这个Connection是由spring注入到A中的,依赖注入的名字就这么来的。Spring是通过反射技术实现注入的,它允许程序在运行的时候动态的生成对象、执行对象的方法、改变对象的属性。

简单的总结一下依赖注入:

  • 依赖 : 指Bean对象的创建依赖于容器 。
  • 注入 : 指Bean对象所依赖的资源 , 由容器来设置和装配。

注入的方式主要包括Setter注入(重点)、构造器注入和参数直接注入。还有拓展方式注入,即:p命名空间注入和c命名空间注入,这里就不再展开介绍了,有兴趣的同学可以自行研究。

Setter注入

IoC 容器使用 setter 方法注入被依赖的实例。通过调用无参构造器或无参 static 工厂方法实例化 bean 后,调用该 bean的setter 方法(类中必须有属性的set方法),即可实现基于setter的DI

代码如下:

  1. public class Address { 
  2.     private String address; 
  3.     public String getAddress() { 
  4.         return address; 
  5.     } 
  6.     public void setAddress(String address) { 
  7.         this.address = address; 
  8.     } 

  1. import java.util.List; 
  2. import java.util.Map; 
  3. import java.util.Properties; 
  4. import java.util.Set
  5. public class Student { 
  6.     private String name
  7.     private Address address; 
  8.     private String[] books; 
  9.     private List<String> hobbys; 
  10.     private Map<String,String> card; 
  11.     private Set<String> games; 
  12.     private String wife; 
  13.     private Properties info; 
  14.     public void setName(String name) { 
  15.         this.name = name
  16.     } 
  17.     public String getName() { 
  18.        return this.name
  19.     } 
  20.     public void setAddress(Address address) { 
  21.         this.address = address; 
  22.     } 
  23.    public void setBooks(String[] books) { 
  24.         this.books = books; 
  25.     } 
  26.     public void setHobbys(List<String> hobbys) { 
  27.         this.hobbys = hobbys; 
  28.     } 
  29.     public void setCard(Map<String, String> card) { 
  30.         this.card = card; 
  31.     } 
  32.     public void setGames(Set<String> games) { 
  33.         this.games = games; 
  34.     } 
  35.     public void setWife(String wife) { 
  36.         this.wife = wife; 
  37.     } 
  38.     public void setInfo(Properties info) { 
  39.         this.info = info; 
  40.     } 
  41.     public void show(){ 
  42.         System.out.println("name="name 
  43.                 +",address="+ address.getAddress() 
  44.                 +",books=" 
  45.         ); 
  46.         for (String book:books){ 
  47.             System.out.print("<<"+book+">>\t"); 
  48.         } 
  49.         System.out.println("\nhobbys:"+hobbys); 
  50.         System.out.println("card:"+card); 
  51.         System.out.println("games:"+games); 
  52.         System.out.println("wife:"+wife); 
  53.         System.out.println("info:"+info); 
  54.     } 

 配置文件

  1. <bean id="student" class="com.my.demo.Student"
  2.      <property name="name" value="小明"/> 
  3.  </bean> 

配置文件中把name 赋值为小明,即完成了对代码 private String name的注入。

测试类

  1. public static void main(String[] args) { 
  2.            ApplicationContext context = new ClassPathXmlApplicationContext("bean1.xml"); 
  3.            Student student=(Student)context.getBean("student"); 
  4.            System.out.println(student.getName()); 
  5.         } 

 运行结果,输出:小明

常见注入方式的xml 配置如下:

bean注入

使用ref进行引入其他bean

  1. <bean id="student" class="com.my.demo.Student"
  2.      <property name="name" value="小明"/> 
  3.     <property name="address" ref="addr"/> 
  4. </bean> 

数组注入

  1. <property name="books"
  2.          <array> 
  3.              <value>数学</value> 
  4.              <value>语文</value> 
  5.              <value>英语</value> 
  6.          </array> 
  7.     </property> 

 List注入

  1. <property name="hobbys"
  2.      <list> 
  3.          <value>听歌</value> 
  4.          <value>看电影</value> 
  5.          <value>打游戏</value> 
  6.      </list> 
  7.   </property> 

 Map注入

  1. <property name="card"
  2.      <map> 
  3.          <entry key="招行" value="123456789"/> 
  4.          <entry key="工行" value="987654321"/> 
  5.      </map> 
  6.  </property> 

set注入

  1. <property name="games"
  2.      <set
  3.          <value>CS</value> 
  4.          <value>斗地主</value> 
  5.          <value>消消乐</value> 
  6.      </set
  7.  </property> 

 Null注入

  1. <property name="wife"><null/></property> 

Properties注入

  1. <propertyname="info"
  2.      <props> 
  3.          <propkey="学号">123456</prop> 
  4.          <propkey="性别">男</prop> 
  5.          <propkey="姓名">小明</prop> 
  6.      </props> 
  7.  </property> 

 测试方法

  1. public static void main(String[] args) { 
  2.            ApplicationContextcontext = new ClassPathXmlApplicationContext("bean1.xml"); 
  3.            Studentstudent=(Student)context.getBean("student"); 
  4.            student.show();  
  5.         } 

 运行结果,输出:

name=小明,address=北京,books=

<<数学>> <<语文>> <<英语>>

hobbys:[听歌, 看电影, 打游戏]

card:{招行=123456789, 工行=987654321}

games:[CS, 斗地主, 消消乐]

wife:null

info:{学号=123456, 性别=男, 姓名=小明}

构造器注入

指IoC 容器使用构造方法注入被依赖的实例。基于构造器的 DI 通过调用带参数的构造方法实现,每个参数代表一个依赖。

代码如下:

  1. public class Student2{ 
  2.        private String name
  3.        public Student2(String name) { 
  4.           this.name = name
  5.       } 
  6.        public void setName(String name) { 
  7.           this.name = name
  8.       } 
  9.        public void show(){ 
  10.           System.out.println("name="name ); 
  11.       } 
  12.     } 

 配置文件中设置

  1.  <!-- 第一种根据index参数下标设置 --> 
  2. <bean id="student1" class="com.my.demo.Student2"
  3.    <!-- index是构造方法 , 下标从0开始 --> 
  4.    <constructor-arg index="0" value="kevin1"/> 
  5. </bean> 
  6. <!--第二种根据参数名字设置 --> 
  7. <bean id="student2" class="com.my.demo.Student2"
  8.    <!-- name指参数名 --> 
  9.    <constructor-arg name="name" value="kevin2"/> 
  10. </bean> 
  11. <!--第三种根据参数类型设置(不推荐使用) --> 
  12. <bean id="student3" class="com.my.demo.Student2"
  13.    <constructor-arg type="java.lang.String" value="kevin3"/> 
  14. </bean> 

测试代码

  1. public static void main(String[] args) { 
  2.            ApplicationContextcontext = new ClassPathXmlApplicationContext("bean3.xml");        
  3.            Student2 user = (Student2) context.getBean("student1"
  4.            user.show(); 
  5.         } 

 运行结果:

name=kevin1

参数直接注入

主要通过注解@Autowired、@Qualifier和@Resource来实现

@Autowired

@Autowired是按类型自动转配的,不支持id匹配。

需要导入 spring-aop的包

配置文件中设置<

context:annotation-config/>

代码:

  1. public class Animal {    
  2. @Autowired    private Cat cat; //运行时spring通过DI会把Cat类实例化    
  3. @Autowired private Dog dog;//运行时spring通过DI会把Dog类实例化    
  4.        public void printCatshot() { 
  5.               cat.shout();      
  6.   }   
  7.         public void printDogshot() { 
  8.                 dog.shout(); 

 @Qualifier

@Autowired是根据类型进行自动装配的。如果当Spring上下文中存在一个类型的不同bean时,就会抛出BeanCreationException异常;我们可以使用@Qualifier配合@Autowired来解决这些问题。

代码:

  1. @Autowired 
  2. @Qualifier(value= "dog1"
  3. private Dog dog1; 
  4. beans.xml 
  5. <bean id="dog1" class="com.my.demo.Dog"/> 
  6. <bean id="dog2" class=" com.my.demo.Dog"/> 

 @Resource

@Resource是J2EE提供的, 需导入Package: javax.annotation.Resource;

@Resource如有指定的name属性,先按该属性进行byName方式查找装配,其次再进行默认的byName方式进行装配,都不成功,则报异常。

代码

  1. @Resource(name = "dog2"
  2. private Dog dog; 
  3. beans.xml 
  4. <bean id="dog1" class=" com.my.demo.Dog "/> 
  5. <bean id="dog2" class="com.my.demo.Dog "/> 

 最简单的解释

IoC通过DI技术主要实现了以下两点:

  • 在系统运行中,动态地向某个对象提供它所需要的其他对象;
  • 在系统运行中,动态地从配置文件中读取数据来为对象的属性进行赋值。

 【编辑推荐】

 

责任编辑:姜华 来源: 今日头条
相关推荐

2021-03-16 08:22:49

SpringIoCAOP

2021-03-30 08:49:27

测试Spring AOP

2021-03-10 09:21:00

Spring开源框架Spring基础知识

2023-02-04 18:19:39

2011-04-02 10:57:41

2019-12-03 11:00:08

spring bootspring-kafkJava

2022-12-07 08:02:43

Spring流程IOC

2011-04-06 10:23:46

2020-04-23 15:59:04

SpringKafka集群

2011-04-06 10:31:53

2011-04-06 10:36:21

2016-05-18 17:15:17

互动出版网

2023-12-26 08:08:02

Spring事务MySQL

2021-04-15 09:03:33

框架 Pytest测试

2011-01-27 10:11:46

J2EEjavaspring

2011-03-09 16:10:34

MAC地址二层组播IGMP

2014-01-22 10:00:10

Android SDKAndroid开发

2023-10-09 08:20:12

整洁架构软件设计原则

2010-10-09 11:20:13

2016-10-31 19:41:29

Java垃圾回收
点赞
收藏

51CTO技术栈公众号