Java

一篇文章带你了解IoC

2020-03-02  本文已影响0人  JerrysCode

IoC是Spring的核心技术之一,中文名为控制反转,名字听起来比较抽象,什么是IoC?所谓“反转”到底反转了什么?为什么需要IoC?本篇文章将我的学习总结下来,供朋友们参考

什么是IoC

先介绍下概念术语

IoC的目的在于提供一种机制来管理对象的创新和销毁,以及对象之间的依赖关系。DI和DL是IoC的两种实现方式,三者的关系如下图所示


IoC.PNG

DI是IoC最常见的实现方式

通过容器把依赖的对象注入, 典型实现如Spring中的@Autowired

DL是IoC的另外一种实现

通过IoC容器提供的api查找依赖对象, 典型实现如Spring中的Context.getBean(MyBean.class)

为什么要使用IoC

应用程序通过多个类协同工作来实现业务逻辑,协作必然带来类之间的依赖。如何管理这种依赖关系呢?

如果不使用IoC,程序就需要自己实例化依赖的类。

举个例子:现实生活中每个汽车(Car)都有1个引擎(Engine),用下面的代码描述

public class Car {
    private Engine engine;
    
    public Car(){
        this.engine = new Engine();
    }
}

在这段代码中,Car依赖于Engine,Car类在构造方法中new了一个Engine实例。这种方法有几个缺点:

  1. 代码耦合:Car实例初始化必须依赖于Engine
  2. 无法适应变化:如果要更换一种新类型的Engine,必须修改Car代码
  3. 单元测试Car这个类,必须保证能够正确初始化Engine

使用IoC方式

为了解决上文提到的“耦合”问题,我们可以使用IoC来解耦。

public class Car {
    private Engine engine;

    public Car(Engine engine){
        this.engine = engine;
    }
}

这段代码中,Car不再通过new来获得Engine对象,而是 在运行时,由“第三方”程序创建Engine实例,并通过构造方法注入到Car类中,
这个“第三方”程序就是IoC容器。对Engine类进行实例化的"控制权"从Car类转移到了IoC容器中, 这区别于传统的new的方式,所以叫“反”转。

Spring如何实现IoC

通过前面的介绍,我们可以看到IoC是一种软件设计思想,并不是Spring特有的技术,Spring只是按自己的方式实现了这个思想。
Spring 的依赖注入由DI容器完成。

springBeanFactory.PNG
Spring提供xml和java annotation两种方式来声明Bean和描述Bean之间的关系

xml方式

  1. 通过xml声明Bean,指定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"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
    <!--声明Engine-->
    <bean id="engine" class="com.jerry.Engine"/>

    <!--声明Car,通过构造函数方式注入id为engine的Bean-->
    <bean id="car" class="com.jerry.Car">
        <constructor-arg ref="engine"/>
    </bean>
</beans>
  1. 通过ApplicationContext获取Bean
GenericXmlApplicationContext ctx = new GenericXmlApplicationContext();
ctx.load("classpath:my-spring-ctx.xml");
ctx.refresh();

Car car = ctx.getBean("car", Car.class);
car.start();

Java 配置方式

  1. 用一个配置类声明Bean,指定Bean之间的依赖关系
@Configuration  //@Configuration 表明这是一个配置类
public class CarCofig {
    @Bean
    public Car car(){
        return new Car(engine());
    }
    @Bean
    public Engine engine() {
        return new Engine();
    }
}
  1. 通过ApplicationContext获取Bean
AnnotationConfigApplicationContext context = new         
AnnotationConfigApplicationContext(CarCofig.class);

Car car = context.getBean(Car.class);
car.start();
上一篇下一篇

猜你喜欢

热点阅读