原文地址:http://blog.csdn.net/wangyang1354/article/details/50757098


我们经常会遇到这样一种情景,就是在我们开发项目的时候经常会在一个类中调用其他的类中的方法,来完成我们期望的任务,大部分的情况下往往会采用在当前需要的这个类里面new一个实例出来,然后调用他的方法,那么这样的话会有个问题,就是有一天我想改变下这个类,改为其他的名称,那么这时候必须要做的是同时去调用方的类文件中改变这个改变的类的名称。这样的情况是因为代码的耦合带来了后期维护成本的增加,那么spring的出现就可以很好的起到解耦的作用,而他的核心机制就是依赖注入。

依赖注入与控制反转


依赖注入:对于spring而言,将自己置身于spring的立场上去看,当调用方需要某一个类的时候我就为你提供这个类的实例,就是说spring负责将被依赖的这个对象赋值给调用方,那么就相当于我为调用方注入了这样的一个实例。从这方面来看是依赖注入。


控制反转:对于调用方来说,通常情况下是我主动的去创建的,也就是对于这个对象而言我是控制方,我有他产生与否的权力,但是,现在变了,现在变为spring来创建对象的实例,而我被动的接受,从这一点上看,是控制反转。


这两者的意思是一致的,就看你从谁的角度去看这个问题。不同的角度那么看到的问题可能是不一样的。



依赖注入两种方式


1.设值注入


设值注入:通过set的方式注入值.Ioc容器通过成员变量的setter方法来注入被依赖的对象,这种注入方式简单,直观,因而在spring中大量的使用。

下面我们采用实际的例子来体会一下:

假设这样的一个场景,我想打印消息,这样一件事情

首先定义一个MessageService的接口。

[java] view
plain
 copy

 

  1. package com.siti.spring20160227;
  2. public interface MessageService {
  3. /**
  4. * 消息打印
  5. */
  6. public void printMessage();
  7. }

然后实现这个接口,并实现这个方法。

[java] view
plain
 copy

 

  1. package com.siti.spring20160227;
  2. public class MessagePrinter implements MessageService {
  3. @Override
  4. public void printMessage() {
  5. System.out.println("输出消息!");
  6. }
  7. }

那么对于我而言,我也定义一个person的接口

[java] view
plain
 copy

 

  1. package com.siti.spring20160227;
  2. public interface Person {
  3. /**
  4. * 人发送消息
  5. */
  6. public void sendMessage();
  7. }

我来实现人这个接口

[java] view
plain
 copy

 

  1. package com.siti.spring20160227;
  2. public class WangYang implements Person{
  3. private MessageService service;
  4. public void setService(MessageService service) {
  5. this.service = service;
  6. }
  7. @Override
  8. public void sendMessage() {
  9. this.service.printMessage();
  10. }
  11. }

Spring的配置文件:

[java] view
plain
 copy

 

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <beans xmlns="http://www.springframework.org/schema/beans"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xsi:schemaLocation="
  5. http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
  6. <!-- bean definitions here -->
  7. <bean id = "messageService" class = "com.siti.spring20160227.MessagePrinter"></bean>
  8. <bean id = "wy" class = "com.siti.spring20160227.WangYang">
  9. <property name="service" ref="messageService"></property>
  10. </bean>
  11. </beans>

测试类如下:

[java] view
plain
 copy

 

  1. package com.siti.spring20160227;
  2. import org.springframework.context.ApplicationContext;
  3. import org.springframework.context.support.ClassPathXmlApplicationContext;
  4. public class MainTest {
  5. public static void main(String[] args) {
  6. ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
  7. Person person = context.getBean("wy", Person.class);
  8. person.sendMessage();
  9. }
  10. }


2.构造注入


通过构造函数的方式注入。spring以反射的方式执行带指定参数的构造器,当执行带参数的构造器时就可以通过构造器的参数赋值给成员变量,完成构造注入。


那么现在需求变了,我需要改一些东西,下面可以注意下我主要改动了哪里:

在WangYang这个类中添加有参数和无参数的构造函数:

[java] view
plain
 copy

 

  1. package com.siti.spring20160227;
  2. public class WangYang implements Person{
  3. private MessageService service;
  4. <span style="color:#33ff33;">public WangYang() {
  5. super();
  6. }
  7. public WangYang(MessageService service) {
  8. this.service = service;
  9. }
  10. </span>public void setService(MessageService service) {
  11. this.service = service;
  12. }
  13. @Override
  14. public void sendMessage() {
  15. this.service.printMessage();
  16. }
  17. }

在Spring配置文件中,稍微改动,即将原来的设值注入换为构造注入即可。

[java] view
plain
 copy

 

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <beans xmlns="http://www.springframework.org/schema/beans"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xsi:schemaLocation="
  5. http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
  6. <!-- bean definitions here -->
  7. <bean id = "messageService" class = "com.siti.spring20160227.MessagePrinter"></bean>
  8. <bean id = "wy" class = "com.siti.spring20160227.WangYang">
  9. <!-- <property name="service" ref="messageService"></property> -->
  10. <span style="color:#33ff33;"><constructor-arg ref="messageService"></constructor-arg></span>
  11. </bean>
  12. </beans>


这样再次运行MainTest类,程序正常运行。所以从这里也可以体会到,spring这种解耦的方便性和重要性。



设值注入和构造注入的对比


这两种方式,效果是一样的,注入的时机不同,设值注入是先调用无参的构造函数,创建出实例后然后调用set方法注入属性值。而构造输入是通过在调用构造函数初始化实例的同时完成了注入。


设值注入的优点


1. 通过set的方式设定依赖关系显得更加直观,自然,和javabean写法类似。

2. 复杂的依赖关系,采用构造注入会造成构造器过于臃肿,spring 实例化的时候同时实例化其依赖的全部实例,导致性能下降,set方式可以避免这些问题。

3. 在成员变量可选的情况下,构造注入不够灵活。


构造注入的优点


某些特定的情况下,构造注入比设值注入好一些。

1. 构造注入可以在构造器中决定依赖关系的注入顺序,优先依赖的优先注入,构造注入可以清楚的分清注入的顺序。

2. 组件的调用者无需知道组件内部的依赖关系,符合高内聚原则。

Spring进阶之路(1)-Spring核心机制:依赖注入/控制反转的更多相关文章

  1. Helloworld之Spring依赖注入/控制反转(DI/IoC)版

    Helloworld之Spring依赖注入/控制反转(DI/IoC)版 作者:雨水, 日期:2014-10-29 摘要:本文主要用于培训刚開始学习的人理解Spring中的依赖注入的基本概念. 先介绍依 ...

  2. Spring的核心机制依赖注入

    原文地址:http://developer.51cto.com/art/200610/33311.htm 本文主要讲解依赖注入(设值注入.构造注入),作用是可以使Spring将各层的对象以松耦合的方式 ...

  3. spring-第一篇之spring核心机制依赖注入(DI)/控制翻转(IoC)

    1.spring的核心机制:依赖注入(DI)/控制翻转(IoC) 什么是依赖:A对象需要调用B对象,所以A依赖于B. 什么是注入:A对象注入一个属性B对象. 什么是依赖注入(DI):A对象依赖于B对象 ...

  4. Spring的核心机制——依赖注入(Dependency Inject)

    Spring不仅提供对象,还提供对象的属性值,而不是由使用该对象的程序所提供的. Java应用是由一些相互协作的对象所组成的,在Spring中这种相互协作的关系就叫依赖关系. 如果A组件调用了B组件的 ...

  5. Spring的核心机制——依赖注入(Dependency Inject)

    Spring不仅提供对象,还提供对象的属性值,而不是由使用该对象的程序所提供的. Java应用是由一些相互协作的对象所组成的,在Spring中这种相互协作的关系就叫依赖关系. 如果A组件调用了B组件的 ...

  6. Spring 依赖注入控制反转实现,及编码解析(自制容器)

    定义: 在运行期,由外部容器动态的将依赖对象动态地注入到组件中. 两种方式: 手工装配 -set方式 -构造器 -注解方式 自动装配(不推荐) 1利用构造器 2set方法注入 dao: package ...

  7. Benefits of Using the Spring Framework Dependency Injection 依赖注入 控制反转

    小结: 1. Dependency Injection is merely one concrete example of Inversion of Control. 依赖注入是仅仅是控制反转的一个具 ...

  8. 【SSH进阶之路】Spring的AOP逐层深入——采用注解完成AOP(七)

    上篇博文[SSH进阶之路]Spring的AOP逐层深入——AOP的基本原理(六),我们介绍了AOP的基本原理,以及5种通知的类型, AOP的两种配置方式:XML配置和Aspectj注解方式. 这篇我们 ...

  9. 【SSH进阶之路】Spring的IOC逐层深入——为什么要使用IOC[实例讲解](二)

    上篇博客[SSH进阶之路]Spring简介,搭建Spring环境——轻量级容器框架(一),我们简单的介绍了Spring的基本概念,并且搭建了两个版本的Spring开发环境,但是我们剩下了Spring最 ...

随机推荐

  1. 67. Add Binary

    public class Solution { public String addBinary(String a, String b) { char[] aa=a.toCharArray(); cha ...

  2. scala言语基础学习九

    模式匹配 case _ =>不能放在函数的中间必须放在最后,否则scala会编译不通过 在case 里面使用if守卫 在模式匹配中获取输入的数据(在匹配不到的情况下) 对类型进行匹配 case ...

  3. UVALive-4329 Ping pong (树状数组)

    题目大意:有n个数排成一列,问从中能找出几个三元组(ai,aj,ak)满足i<j<k并且这三个数严格单调. 题目分析:枚举中间的数字aj,如果aj前面有c(j)个数a(j)小,后面有d(j ...

  4. poj3660 最短路/拓扑序

    题意:有n头牛,为了给牛排顺序,给出了牛之间的胜负关系,具有传递性,问给出的胜负关系是否可以给这些牛排出唯一的顺序. 其实是个拓扑排序问题,牛的胜负关系就是有向边,然后判断是否有唯一的拓扑序就行.当然 ...

  5. TinyXML2读取和创建XML文件 分类: C/C++ 2015-03-14 13:29 94人阅读 评论(0) 收藏

    TinyXML2是simple.small.efficient C++ XML文件解析库!方便易于使用,是对TinyXML的升级改写!源码见本人上传到CSDN的TinyXML2.rar资源:http: ...

  6. java的nio之:java的nio的服务器实现模型

    [nio服务端序列图]

  7. java多线程:并发包中ReentrantReadWriteLock读写锁的锁降级模板

    写锁降级为读锁,但读锁不可升级或降级为写锁. 锁降级是为了让当前线程感知到数据的变化. //读写锁 private ReentrantReadWriteLock lock=new ReentrantR ...

  8. NDK环境搭建

  9. 20150906VS小知识

    .sln :解决方案管理文件.caproj:项目管理文件.cs:程序源代码文件项目文件目录下有个bin文件夹,里面的debug文件夹,里面存放生成后的程序. //注释一行/* */ 注释一段 alt ...

  10. 007. 自定义ListBox的item的宽高, 字体居中

    /// <summary> /// 自定义ListBox的item的宽高, 字体居中 /// </summary> /// <param name="sende ...