Spring学习之==>IOC【控制反转】

一、概述

Spring的三大核心思想:IoC(控制反转),DI(依赖注入),AOP(面向切面编程)。本问讲着重介绍一下控制反转。

何谓控制反转:Spring 通过一种称作控制反转(IoC)的技术促进了松耦合。当应用了IoC,一个对象依赖的其它对象会通过被动的方式传递进来,而不是这个对象自己创建或者查找依赖对象。你可以认为IoC与JNDI相反——不是对象从容器中查找依赖,而是容器在对象初始化时不等对象请求就主动将依赖传递给它。

通俗的讲,控制权由代码中转到了外部容器,控制权的转移,就是所谓反转。也就是说,正常我们都是 new 一个新对象,才可以调用对象。有了控制反转就不需要了,交给容器来管理,我们只需要通过一些配置来完成把实体类交给容器这么个过程。这样可以减少代码量,简化开发的复杂度和耦合度。

二、面向接口编程

在一个面向对象的系统中,系统的各种功能是由许许多多的不同对象协作完成的。在这种情况下,各个对象内部是如何实现自己的,对系统设计人员来讲就不那么重要了;而各个对象之间的协作关系则成为系统设计的关键。小到不同类之间的通信,大到各模块之间的交互,在系统设计之初都是要着重考虑的,这也是系统设计的主要工作内容。面向接口编程就是指按照这种思想来编程。

面向接口编程,具体到某一个接口,对于调用者来说,我们不关心该接口是由哪个实现类来实现的,也不关心具体是怎么实现的,你只需把该接口提供给调用者就可以了。

三、编码实现IoC

下面,我们使用IoC思想来实现一个简单的面向接口编程。

首先定义两个接口 IAccountService 和 IOrderService,如下:

public interface IAccountService {

  int insertAccount(String msg);

}

IAccountService 接口

public interface IOrderService {

  void insert(String msg);

}

IOrderService 接口

然后,定义这两个接口的实现类

public class AccountBigServiceImpl implements IAccountService {

  @Override
  public int insertAccount(String msg) {

    System.out.println("===== AccountBigServiceImpl ====" + msg);

    return 0;
  }
}

AccountBigServiceImpl

public class AccountSamllServiceImpl implements IAccountService {

  @Override
  public int insertAccount(String msg) {

    System.out.println("smallService");

    return 0;
  }
}

AccountSamllServiceImpl

public class OrderServiceImpl implements IOrderService {

  @Override
  public void insert(String msg) {

    System.out.println("===== OrderServiceImpl ====" + msg);
  }
}

OrderServiceImpl

正常我们使用下面这段代码来调用这两个接口

public class Controller {
  public static void main(String[] args) {
    IAccountService accountService = new AccountBigServiceImpl();
    accountService.insertAccount("Hello!!");

    IOrderService orderService = new OrderServiceImpl();
    orderService.insert("World!!");
  }
}

我们在 Controller 这个类中直接 new 了 IAccountService 和 IOrderService 这两个接口的子类:AccountBigServiceImpl 和 OrderServiceImpl。这样就违背上面提到的面向接口编程的思想,我既要处理 Controller 这个类中的业务逻辑,还要关心 IAccountService 和 IOrderService 这两个接口具体的实现类是谁,上面是使用 AccountBigServiceImpl 这个类来实现接口 IAccountService,如果我要使用 AccountSamllServiceImpl这个实现类来实现这个接口,那我还得修改 Controller 中的代码,显然这样做的维护成本就太高了,而且也很容易出错,那么,我们可以想其他的办法。

首先,我们使用一个配置文件来定义这两个接口指向的实现类

IAccountService=com.jack.course.spring.factory.impl.AccountBigServiceImpl
IOrderService=com.jack.course.spring.factory.impl.OrderServiceImpl

conf.properties

然后,我们再定义一个工厂类

public class ServiceFactory {

  private static final String CONF_FILE_NAME = "factory/conf.properties";

  private static Properties prop;

  private static Map<String, Object> beanContainer;

  /**
   * 静态代码块,程序执行时只会被加载一次
   */
  static {

    try {
      beanContainer = Maps.newHashMap();
      //1.从配置文件中找出关系
      prop = new Properties();
      prop.load(ServiceFactory.class.getClassLoader().getResourceAsStream(CONF_FILE_NAME));
    } catch (IOException e) {
      throw new IllegalArgumentException(e);
    }
  }

  public static <T> T getService(Class<T> clazz){

    if (beanContainer.containsKey(clazz.getSimpleName())){
      return (T) beanContainer.get(clazz.getSimpleName());
    }

    try {
      //2.根据关系,将具体的实现类返回
      Object obj = instanceObj(clazz);
      beanContainer.put(clazz.getSimpleName(),obj);
      return (T) obj;
    } catch (Exception e) {
      throw new IllegalArgumentException(e);
    }
  }

  private static <T> Object instanceObj(Class<T> clazz) throws Exception {
    String className = prop.getProperty(clazz.getSimpleName());
    Class<?> instance = Class.forName(className);
    return instance.newInstance();
  }
}

注意:以上代码做了两处优化。第一,把读取配置文件的操作单独抽出来放入静态代码块,只会执行一次不会重复读取。第二,定义了一个 Map 作为 bean容器存放实例化后的对象,如果容器中已经存在实例化后的对象就可以直接返回,不用在重现通过 instanceObj() 方法来实例化对象了,通过这两处优化,能够大大提高性能。

这个工厂类实现的功能是:通过读取配置文件 conf.properties 得到接口的具体实现类,然后通过反射来生成一个对象传给 Controller,这样 Controller 类当中就可以不关心接口的实现类是谁,怎么实现也不用关心。

那我们 Controller 中就可以这么实现

public class Controller {
  public static void main(String[] args) {

    IAccountService accountService = ServiceFactory.getService(IAccountService.class);
    accountService.insertAccount("Hello!");

    IOrderService orderService1 = ServiceFactory.getService(IOrderService.class);
    IOrderService orderService2 = ServiceFactory.getService(IOrderService.class);
    orderService1.insert("One");
    orderService2.insert("Two");
  }
}

这样,我们如果想修改实现类的话,只需要修改配置文件就行了,不用修改代码。

运行结果如下:

以上,我们就通过 IoC 的思想实现了面向接口编程。但是,我们这样的实现就完全没有问题吗?

我们稍微修改一下 AccountBigServiceImpl 实现类,增加一个有参数的构造方法来覆盖默认的构造方法

public class AccountBigServiceImpl implements IAccountService {

  private AccountBigServiceImpl(String msg) {
    System.out.println(msg);
  }

  @Override
  public int insertAccount(String msg) {

    System.out.println("===== AccountBigServiceImpl ====" + msg);

    return 0;
  }
}

然后再执行 Controller,就会报错了。原因是因为我们使用 newInstance 实例化对象时使用的是默认的无参构造方法。

那么,我们通过修改工厂类,也可以实现该功能。但是,可能慢慢还会发现有其他问题,那么我们是不是要全部自己来实现呢,我们可以直接来使用 Spring 框架即可。Spring 框架把我们能想到的和想不到的功能都给实现了,我们只需直接使用就可以了。

四、使用XML文件配置IoC

五、使用注解+XML文件配置IoC

六、使用全注解配置IoC

原文地址:https://www.cnblogs.com/L-Test/p/11593641.html

时间: 2024-10-13 12:41:30

Spring学习之==>IOC【控制反转】的相关文章

Spring学习之Ioc控制反转(1)

开始之前: 1. 本博文为原创,转载请注明出处 2. 作者非计算机科班出身,如有错误,请多指正 ---------------------------------------------------------------------------开始啦啦啦啦啦------------------------------------------------------------------------------- 从开始接触spring起,听到最多的就是Ioc(控制反转)和AOP(面向切面编程

Spring学习之Ioc控制反转(2)

开始之前: 1. 本博文为原创,转载请注明出处 2. 作者非计算机科班出身,如有错误,请多指正 ---------------------------------------------------------------------------开始啦啦啦啦啦------------------------------------------------------------------------------- 上一篇博文简单的演示了如何用Spring框架创建bean,注入bean,并使用到

Spring框架中IoC(控制反转)的原理

一.IoC的基础知识以及原理: 1.IoC理论的背景:在采用面向对象方法设计的软件系统中,底层实现都是由N个对象组成的,所有的对象通过彼此的合作,最终实现系统的业务逻辑.即软件系统中对象之间的耦合,对象A和对象B之间有关联,对象B又和对象C有依赖关系,这样对象和对象之间有着复杂的依赖关系,所以才有了控制反转这个理论. 2.什么是控制反转(IoC): (1).IoC是Inversion of Control的缩写,有的翻译成"控制反转",还有翻译成为"控制反向"或者&

Spring中的Ioc控制反转与DI注入

Spring的控制反转 1.spring的介绍 spring是一款很受欢迎的java开源框架,核心全程围绕着BeanFactory展开,构成如下图. 2.IOC控制反转 2.1定义:把对象创建交给spring管理,不用new的方法,也不用工厂模式 2.2原理:1.xml配置文件,2.dom4j解析xml,3.工厂设计模式,4.反射 2.3使用:1.配置文件方式,2.注解方式 3.IOC注入bean管理  3.1.1 xml配置方式 1.就是xml配置文件中的spring创建对象的方式,也就是be

Spring基础、IOC(控制反转)、AOP(面向切面编程)、Log4j、注解配置

学习示例代码,包含本篇介绍的Spring常用操作示例和所有所需jar文件下载地址:http://download.csdn.net/detail/daijin888888/9556697 1.什么是Spring,有什么作用 --Spring框架属于一个解决方案框架,可以对其他技术和框架进行整合应用. --*好处是:将程序中的各个组件和框架技术进行解耦,便于日后系统维护,升级和扩展操作. --在SSH中,会将Action,DAO组件都交给Spring框架管理,由Spring框架创建这些对象,建立这

Spring中的IoC(控制反转)具体是什么东西

IOC:inverse of Control: 控制反转. 意思是程序中的之间的关系,不用代码控制,而完全是由容器来控制.在运行阶段,容器会根据配置信息直接把他们的关系注入到组件中.同样,这也是 依赖注入的含义.依赖注入和控制反转其实是一个概念.只不过强调的不同而已,依赖注入强调关系的注入是由容器在运行时完成,而控制反转强调关系是由容器控制.其实本质是一样的. 贴一段代码 /** * 学校类 */ public class School { private String name; public

spring学习总结一----控制反转与依赖注入

spring作为java EE中使用最为广泛的框架,它的设计体现了很多设计模式中经典的原则和思想,所以,该框架的各种实现方法非常值得我们去研究,下面先对spring中最为重要的思想之一----控制反转(依赖注入)进行简单的总结. 一.控制反转与依赖注入的概念 在学习spring框架的时候,我们习惯性地将控制反转和依赖注入放在一起,其实,两者体现的思想原则都是差不多的,只不过控制反转是一种更广泛的程序操作理念,而依赖注入是一种更为具体的实现方法,总的来说,控制反转可以依靠依赖注入来实现. 1.控制

Spring 学习 2- IOC原理 控制反转/依赖注入

控制反转/依赖注入 最近,买了本spring入门书:spring In Action .大致浏览了下感觉还不错.就是入门了点.Manning的书还是不错的,我虽然不像哪些只看Manning书的人那样专注于Manning,但怀着崇敬的心情和激情通览了一遍.又一次接受了IOC .DI.AOP等Spring核心概念. 先就IOC和DI谈一点我的看法. IOC(DI):其实这个Spring架构核心的概念没有这么复杂,更不像有些书上描述的那样晦涩.Java程序员都知道:java程序中的每个业务逻辑至少需要

Spring核心(ioc控制反转)

 IoC,Inversion Of Control 即控制反转,由容器来管理业务对象之间的依赖关系,而非传统方式中的由代码来管理. 其本质,即将控制权由应用程序代码转到了外部容器,控制权的转移就是所谓的反转,其带来的最大的好处是降低了业务对象之间的依赖程度,即实现了解耦. Spring的IoC容器主要使用DI(Dependency Injection,依赖注入)方式实现的.不需要主动查找,对象的查找.定位和创建全部由容器管理,容器会将符合依赖关系的对象通过属性(setter等)或者构造函数传