1、依赖和依赖注入

  传统应用程序设计中所说的依赖一般指的是“类与类之间的关系”,那么首先让我们复习一下类之间的关系:

  泛化:表示类与类之间的继承关系,表示接口与接口之间的继承关系;

  

  实现:表示类对接口的实现;

  

  依赖:当类与类之间有使用关系时就属于依赖关系,不同于关联关系,依赖不具有“拥有关系”,而是一种相识关系,只在某个特定的地方才有关系。

  

  关联:表示接口与接口或类与类之间的依赖关系,表现为“拥有关系”;具体代码可以用实例变量来表示。

  

  组合:属于关联的特殊情况,体现了部分整体的关系,是一种“强拥有关系”;整体与部分拥有相同的生命周期,是一种强关联;

  

  聚合:属于关联的特殊情况,也体现了部分整体的关系,是一种“弱拥有关系”;整体和部分可以有不一样的生命周期。是一种弱关联;

  

  它们关系的强弱顺序:泛化= 实现> 组合> 聚合> 关联> 依赖

  spring IoC容器依赖有两层含义:bean依赖容器容器注入bean的依赖资源

  • bean依赖容器:这里的依赖是指容器负责创建bean,并管理bean的生命周期,正式由于容器来控制创建bean并注入依赖,也就是控制值被反转了,这也正式IoC名字的由来,此处的依赖指的是bean和容器之间的依赖关系。
  • 容器注入bean的依赖资源:依赖资源可以是bean、外部文件、常量数据等,在Java中都反应为对象,并且有容器负责组装bean之间的依赖关系,此处的依赖指的是bean之间的关系可以认为是传统类与类之间的关联、组合、聚合关系。

2、为什么要依赖注入

  • 动态替换bean依赖对象,程序更灵活:替换bean对象无需更改源文件,直接修改配置文件即可。
  • 更好实践面向接口编程,代码更清晰:在bean中只需指定依赖对象的接口,接口定义依赖对象完成的功能,通过容器注入依赖实现。
  • 更好实践优先使用组合,而不是继承:因为IoC容器采用注入依赖,也就是组合对象,从而更好的实现对象的组合。 
  • 增加bean的复用性:依赖于对象组合,bean可复用且复用更简单
  • 降低bean之间的耦合:由于我们完全面向接口编程,在代码中没有直接引用bean依赖实现,全部引用接口,而且不会显示创建依赖对象代码。
  • 代码结构更清晰:要应用依赖注入,代码结构要按照规约方式进行书写,从而更好的应用一些最佳实践,因此代码结构更清晰。

  如何设计好类结构才是关键,依赖注入只是装配对象的一种手段。上一篇我们已经了解了bean依赖容器,spring IoC容器注入依赖资源主要有以下三种形式:

  构造器注入:就是容器实例化bean时注入那些依赖,通过在bean定义中指定构造器参数注入依赖,包括实例工厂方法参数注入依赖。

  setter注入:通过setter方法注入依赖。

  方法注入:通过配置方式替换掉bean方法,也就是通过配置改变bean方法功能。

3、依赖注入具体配置

  3.1 构造器注入:

    3.1.1 使用构造器注入通过配置构造器参数实现,构造器参数就是依赖。除了构造器方式还有实例工厂,静态工厂可以进行构造器注入。

    

    构造器注入可以根据参数的索引注入,参数的类型注入或参数名注入(参数名注入有限制:编译程序时打开调试模式或在构造器上使用@ConstructorProperties注解指定参数名)

 1 public class HelloImpl3 implements HelloApi {
 2    private String message;
 3    private int index;
 4    //@java.beans.ConstructorProperties({"message", "index"})
 5    public HelloImpl3(String message, int index) {
 6      this.message = message;
 7      this.index = index;
 8    }
 9    @Override
10    public void sayHello() {
11    System.out.println(index + ":" + message);
12  }

 1 <!-- 通过构造器参数索引方式依赖注入 -->
 2 <bean id="byIndex" class="cn.javass.spring.chapter3.HelloImpl3">
 3   <constructor-arg index="0" value="Hello World!"/>
 4    <constructor-arg index="1" value="1"/>
 5 </bean>
 6 <!-- 通过构造器参数类型方式依赖注入 -->
 7 <bean id="byType" class="cn.javass.spring.chapter3.HelloImpl3">
 8    <constructor-arg type="java.lang.String" value="Hello World!"/>
 9    <constructor-arg type="int" value="2"/>
10 </bean>
11 <!-- 通过构造器参数名称方式依赖注入 -->
12 <bean id="byName" class="cn.javass.spring.chapter3.HelloImpl3">
13    <constructor-arg name="message" value="Hello World!"/>
14    <constructor-arg name="index" value="3"/>
15 </bean>

 1 @Test
 2 public void testConstructorDependencyInjectTest() {
 3   BeanFactory beanFactory = new ClassPathXmlApplicationContext("chapter3/constructorDependencyInject.xml");
 4   //获取根据参数索引依赖注入的Bean
 5   HelloApi byIndex = beanFactory.getBean("byIndex", HelloApi.class);
 6   byIndex.sayHello();
 7   //获取根据参数类型依赖注入的Bean
 8   HelloApi byType = beanFactory.getBean("byType", HelloApi.class);
 9   byType.sayHello();
10   //获取根据参数名字依赖注入的Bean
11   HelloApi byName = beanFactory.getBean("byName", HelloApi.class);
12   byName.sayHello();
13 }

    3.1.2 静态工厂方法注入和实例工厂方法注入

 1 <!--静态工厂方法-->
 2 <bean id="byIndex" class="cn.javass.spring.chapter3.DependencyInjectByStaticFactory" factory-method="newInstance">
 3   <constructor-arg index="0" value="Hello World!"/>
 4   <constructor-arg index="1" value="1"/>
 5 </bean>
 6 <bean id="byType" class="cn.javass.spring.chapter3.DependencyInjectByStaticFactory" factory-method="newInstance">
 7   <constructor-arg type="java.lang.String" value="Hello World!"/>
 8   <constructor-arg type="int" value="2"/>
 9 </bean>
10 <bean id="byName" class="cn.javass.spring.chapter3.DependencyInjectByStaticFactory" factory-method="newInstance">
11   <constructor-arg name="message" value="Hello World!"/>
12   <constructor-arg name="index" value="3"/>
13 </bean>
24 <!--实例工厂方法-->
25 <bean id="instanceFactory" class="cn.javass.spring.chapter3.DependencyInjectByInstanceFactory"/>
26 <bean id="byIndex" factory-bean="instanceFactory" factory-method="newInstance">
27    <constructor-arg index="0" value="Hello World!"/>
28   <constructor-arg index="1" value="1"/>
29 </bean>
30 <bean id="byType" factory-bean="instanceFactory" factory-method="newInstance">
31   <constructor-arg type="java.lang.String" value="Hello World!"/>
32   <constructor-arg type="int" value="2"/>
33 </bean>
34 <bean id="byName" factory-bean="instanceFactory" factory-method="newInstance">
35   <constructor-arg name="message" value="Hello World!"/>
36   <constructor-arg name="index" value="3"/>
37 </bean> 

 1 //静态工厂类
 2 package cn.javass.spring.chapter3;
 3 import cn.javass.spring.chapter2.helloworld.HelloApi;
 4 public class DependencyInjectByStaticFactory {
 5   public static HelloApi newInstance(String message, int index) {
 6   return new HelloImpl3(message, index);
 7   }
 8 }
 9 //实例工厂类
10 package cn.javass.spring.chapter3;
11 import cn.javass.spring.chapter2.helloworld.HelloApi;
12 public class DependencyInjectByInstanceFactory {
13    public HelloApi newInstance(String message, int index) {
14    return new HelloImpl3(message, index);
15    }
16 }

  因为参数名需做额外配置,因此不建议使用根据参数名进行构造器注入

  3.2 setter注入

  setter注入,是通过构造器、静态工厂、实例工厂实例化好bean中,再调用bean类的setter方法注入依赖。

  

1 <!-- 通过setter方式进行依赖注入 -->
2  <bean id="bean" class="cn.javass.spring.chapter3.HelloImpl4">
3    <property name="message" value="Hello World!"/>
4      <property name="index">
5      <value>1</value>
6    </property>
7  </bean>

 1 package cn.javass.spring.chapter3;
 2 import cn.javass.spring.chapter2.helloworld.HelloApi;
 3 public class HelloImpl4 implements HelloApi {
 4    private String message;
 5    private int index;
 6   //setter方法
 7    public void setMessage(String message) {
 8    this.message = message;
 9    }
10    public void setIndex(int index) {
11    this.index = index;
12    }
13    @Override
14    public void sayHello() {
15    System.out.println(index + ":" + message);
16    }
17 }
18
19 @Test
20 public void testSetterDependencyInject() {
21    BeanFactory beanFactory = new ClassPathXmlApplicationContext("chapter3/setterDependencyInject.xml");
22    HelloApi bean = beanFactory.getBean("bean", HelloApi.class);
23    bean.sayHello();
24 }

  JavaBean本质就是一个pojo,具体有如下限制:

    该类必须有公共的无惨构造器

    属性为private访问级别

    属性必要时通过一组setter和getter方法来访问

  3.3 常量注入

    注入常量是依赖注入中最简单的,配置方式如下:

1 <property name="message" value="Hello World!"/>
2 或
3 <property name="index"><value>1</value></property>

    以上两种方式都可以,从配置来看第一种更简洁,此处的value中指定的全是字符串,由spring容器将此字符串转换成属性所需的类型,如果转换出错则抛出相应的异常。spring容器目前能对各种基本类型把配置的字符串参数转换为所需的类型。

 1 //测试类
 2 public class BooleanTestBean {
 3    private boolean success;
 4    public void setSuccess(boolean success) {
 5    this.success = success;
 6    }
 7    public boolean isSuccess() {
 8    return success;
 9    }
10 }

 1 <!-- boolean参数值可以用on/off -->
 2 <bean id="bean2" class="cn.javass.spring.chapter3.bean.BooleanTestBean">
 3  <property name="success" value="on"/>
 4 </bean>
 5 <!-- boolean参数值可以用yes/no -->
 6 <bean id="bean3" class="cn.javass.spring.chapter3.bean.BooleanTestBean">
 7  <property name="success" value="yes"/>
 8 </bean>
 9 <!-- boolean参数值可以用1/0 -->
10 <bean id="bean4" class="cn.javass.spring.chapter3.bean.BooleanTestBean">
11  <property name="success" value="1"/>
12 </bean>

  3.4 注入集合、数组和字典

    spring IoC容器不仅能注入简单的数据类型,还能注入集合(Collection、Set、List)类型、数组类型、字典数据类型、Properties类型。

    3.4.1 注入集合类型:

  • List类型:需要使用list标签注入,其具体配置如下:

  

1 <bean id="listBean" class="cn.javass.spring.chapter3.bean.ListTestBean">
2  <property name="values">
3    <list>
4      <value>1</value>
5      <value>2</value>
6      <value>3</value>
7    </list>
8  </property>
9 </bean>

 1 package cn.javass.spring.chapter3.bean;
 2 import java.util.List;
 3 public class ListTestBean {
 4    private List<String> values;
 5    public List<String> getValues() {
 6      return values;
 7    }
 8    public void setValues(List<String> values) {
 9      this.values = values;
10    }
11 }
12 @Test
13 public void testListInject() {
14  BeanFactory beanFactory = new ClassPathXmlApplicationContext("chapter3/listInject.xml");
15   ListTestBean listBean = beanFactory.getBean("listBean", ListTestBean.class);
16   System.out.println(listBean.getValues().size());
17   Assert.assertEquals(3, listBean.getValues().size());
18 }

  • set类型:需要使用set标签来配置注入,其配置参数含义与list相同
1 <bean id="setBean" class="cn.javass.spring.chapter3.bean.SetTestBean">
2   <property name="values">
3     <set>
4       <value>1</value>
5       <value>2</value>
6       <value>3</value>
7     </set>
8   </property>
9 </bean>

 1 package cn.javass.spring.chapter3.bean;
 2 import java.util.Set;
 3 public class SetTestBean {
 4    private Set<String> values;
 5    public void setValues(Set<String> values) {
 6      this.values = values;
 7    }
 8    public Set<String> getValues() {
 9      return values;
10    }
11 }

  • Collection类型:由于Collection类型是List和Set类型的基类型,所以使用list和set标签都可以进行注入,配置方式和以上配置方式相同。

    3.4.2 注入数组类型

      需要使用array标签来配置注入,其中标签属性“value-type”和“merge”与list标签含义完全相同。具体配置如下:

      

    3.4.3 注入字典类型:

      字典类型是包含键值对数据的数据结构,需要使用map、entry标签来配置注入,其属性key-type和value-type分别指定键值数据类型,其含义同list标签相同。使用key、value字标签分别指定键值数据。具体配置如下:

      

    3.4.4 Properties注入:

      spring能注入java.util.Properties类型数据,需要使用props标签来配置注入,键值类型必须是String,不能变。字标签<prop key=“键”>值<prop>来指定键值对,具体配置如下:

      

    

 

转载于:https://www.cnblogs.com/ouhouki/p/9692701.html

srping基础——DI(三)相关推荐

  1. 2013秋东北计算机在线作业,2013秋奥鹏东北师范大学计算机应用基础第三次在线作业及答案.doc...

    2013秋奥鹏东北师范大学计算机应用基础第三次在线作业及答案,奥鹏东北师范大学,东北师范大学奥鹏教育,福建师范大学奥鹏,华中师范大学奥鹏,福建师范大学奥鹏教育,奥鹏大工15春在线作业,奥鹏作业答案,2 ...

  2. Servlet基础(三) Servlet的多线程同步问题

    Servlet基础(三) Servlet的多线程同步问题 Servlet/JSP技术和ASP.PHP等相比,由于其多线程运行而具有很高的执行效率. 由于Servlet/JSP默认是以多线程模式执行的, ...

  3. 这回真的是挤时间了-PHP基础(三)

    hi 刚看了唐人街探案,5星好评啊亲.由于是早就约好的,也不好推辞(虽然是和男的..),但该写的还是得挤时间写.明天早上老师的项目结题,虽然和我关系不大,但不要添乱就好!! 1.PHP  一.PHP基 ...

  4. 计算机多媒体应用软件有超媒体特点吗,计算机应用基础第三套试卷98分

    计算机应用基础第三套试卷 总分:100考试时间:100分钟 一.单项选择题 1.下列文件扩展名中,________不是常用的图像文件格式.(答题答案:A) A.WAV B.TIF C.JPG D.GI ...

  5. MySQL基础总结(三)

    MySQL基础总结(三) 文章目录 MySQL基础总结(三) 七.锁机制 1.锁的分类 从对数据操作的类型分类: 从对数据操作的粒度分类: 2.MyISAM 表锁 3.InnoDB 行锁 4.加锁机制 ...

  6. (六)JS基础知识三(走进作用域和闭包)【三座大山之二,不会闭包,基本不会通过】

    JS基础知识三(作用域和闭包) 提问 作用域 自由变量 闭包 this 提问 this的不同应用场景,如何取值 手写bind函数 实际开发中闭包的应用场景,举例说明 创建10个a标签,点击的时候弹出对 ...

  7. C#基础第三天-作业-集合-冒泡排序-模拟名片

    1.名片:用两种集合(ArrayList/List<>)去输出余下信息. 身份证号码,电话号码,性别,姓名,身高,年龄,体重. 需求:根据 姓名 去查询某一行数据.如果集合中不存在提示(& ...

  8. 深度学习(7)TensorFlow基础操作三: 索引与切片

    深度学习(7)TensorFlow基础操作三: 索引与切片 一. 基础索引 1. Basic indexing 2. Numpy-style indexing 3. start : end 4. 切片 ...

  9. Python基础(三)--序列

    Python基础(三)--序列 1 序列相关的概念 1.1 什么是序列 序列是一种可迭代对象,可以存储多个数据,并提供数据的访问. 序列中的数据称为元素,Python内置的序列类型有:列表(list) ...

最新文章

  1. java 服务端客户端数据传输出现乱码
  2. WGAN的提出背景以及解决方案
  3. Android基础——项目的文件结构(三)
  4. 鸿蒙os2.0电脑版,鸿蒙系统2.0PC版
  5. itextpdf paragraph使用
  6. 广联达报错access_广联达土建算量软件错误提示大全及解决方法(持续更新至20170418)...
  7. vb.net 教程 3-1 窗体编程基础 1
  8. 为新开的餐厅设计网站html,18个以餐饮美食为主题的优秀网页设计
  9. 微信小程序 富文本编辑器 editor
  10. 通俗易懂区块链系列——双重支付/双花支付
  11. 豆腐的做法与编辑的文风
  12. 中国象棋c语言源代码csdn,中国象棋源代码-C语言小程序
  13. LTE学习笔记4之物理层信道与信号
  14. Python3 计算空气质量指数AQI
  15. 支撑压力(刀哥指标)
  16. 美国国家学术出版社所有PDF图书开放免费下载
  17. 自动驾驶仿真实验流程--以PanoSim仿真软件为例
  18. [多图试用]WPS Office for Mac 轻装上阵与诚意而来
  19. 无限级分销,无限级分销,五级三阶制,五级三晋制,传销,分销
  20. JS提取字符串的手机号或固话

热门文章

  1. rabbitmq php 学习
  2. 记帐数据只记部分后如何处理
  3. JavaScript设置对象的不可拓展
  4. Windows 10使用PowerShell创建系统还原点的技巧
  5. 15条走红网络的手机摄影技巧
  6. easyui accordion全部是关闭状态
  7. 手机的次世代竞争年代
  8. 使用Python解析nginx日志文件
  9. 在golang编程中总结的基础语法及常见的问题
  10. mongodb中分页显示数据集的学习