美文网首页Java
一篇文章带你了解IoC

一篇文章带你了解IoC

作者: JerrysCode | 来源:发表于2020-03-02 22:46 被阅读0次

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

    什么是IoC

    先介绍下概念术语

    • IoC: Inversion of control, 中文翻译为控制反转。
    • DI: Dependency Injection,中文翻译为依赖注入
    • DL: Dependency Lookup,中文翻译为依赖查找

    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();
    

    相关文章

      网友评论

        本文标题:一篇文章带你了解IoC

        本文链接:https://www.haomeiwen.com/subject/gbjikhtx.html