美文网首页Java工程师的咖啡
Spring源码解读,认识Spring IOC容器

Spring源码解读,认识Spring IOC容器

作者: javap | 来源:发表于2020-02-20 12:20 被阅读0次

    知识要点:

    什么是Spring IoC容器

    什么是IoC

    什么是依赖倒置

    为什么需要Spring IoC

    什么是Spring IoC容器

    Spring Ioc容器的最主要作用就是:完成对象的创建管理和依赖注入等 。

    什么是IoC

    IoC(Inversion of Control,控制反转)是Spring的核心,贯穿始终。所谓IoC,对于spring框架来说,就是由Spring来负责控制对象的生命周期和对象之间的关系。
    既然提到了IoC,我们就不得不提及设计模式中的六大原则。因为原则之一的“依赖倒置”跟IoC有很大的关系。
    控制反转(IoC)是DIP(Dependence Inversion Principle,依赖倒置原则)的一种具体实现方式。 依赖注入(DI,Dependence Injection)是IoC的一种具体实现方式,用来实现依赖倒置。

    设计模式六大原则

    • 单一原则
      一个类或者一个方法只负责一个职责,各个职责的程序改动,不影响其它程序。
    • 里氏代换
      所有引用父类的地方必须能透明地使用其子类的对象,反过来则不成立。
    • 接口隔离
      建立单一接口,不要建立庞大臃肿的接口。一个接口只服务于一个子模块或业务逻辑。
    • 迪米特原则
      一个类对其他的类知道的越少越好,也就是对于被依赖的类的方法和属性尽量私有化。
    • 开闭原则
      对扩展开放,对修改关闭。
    • 依赖倒置
      面向接口编程是依赖倒置原则的核心,上层定义接口,下层实现这个接口, 从而使得下层依赖于上层,降低耦合度。
      让我们来看一段代码:
    class Laptop {
        public void start(){
            System.out.println("Laptop启动....");
        }
    
        public void run(){
            System.out.println("Laptop运行....");
        }
    }
    
    class Programmer {
        Laptop laptop = new Laptop();
    
        // 编写代码
        public void coding(){
            laptop.start();
            laptop.run();
        }
    }
    

    上面这段代码的问题在:如果某一天业务需求要改换成台式电脑(Desktop),这个修改工作肯定是避免不了的。而且工程越复杂修改量越大。怎么处理好呢?
    如果我们不进行解耦,它们的关系就会是这样:



    而且,在采用面向对象方法设计的软件系统中,底层实现都是由非常多的对象组成,所有的对象通过彼此的合作,最终实现系统的业务逻辑。 随着应用的规模越来越庞大,对象之间的依赖关系也越来越复杂,经常会出现对象之间的多重依赖性关系。这是致命的,不管对于开发还是维护来说。

    什么是依赖倒置

    如何降低系统之间、模块之间和对象之间的耦合度,是软件工程永远追求的目标之一。为了解决对象之间的耦合度过高的问题,我们使用IoC理论来实现对象之间的“解耦”。
    上面的代码,对象和对象之间的耦合太严重。那我们应该如何进行解耦呢?
    我们再来看一段代码:

    interface Computer {
        public void start();
        public void run();
    }
    
    class Laptop implements Computer{
        public void start(){
            System.out.println("Laptop启动....");
        }
    
        public void run(){
            System.out.println("Laptop运行....");
        }
    }
    
    class Desktop implements Computer{
        public void start(){
            System.out.println("Desktop启动....");
        }
    
        public void run(){
            System.out.println("Desktop运行....");
        }
    }
    
    class Programmer {
        Computer c;
        
        Programmer(Computer c){
            this.c = c;
        }
    
        public void coding(){
            c.start();
            c.run();
            c.stop();
        }
    
        // DI  解决依赖问题
        // IOC 解决实例化问题
        public static void main(String[] args){
            Computer c = new Desktop();
            Programmer p = new Programmer(p);
            p.coding();
        }
    }
    

    在这段代码里面,就体现了几个设计模式中的原则,当然也包括“依赖倒置”—— 高层模块不应该依赖低层模块,二者都应该依赖其抽象;抽象不应该依赖细节;细节应该依赖抽象。
    上面的第一段代码中的类是Programmer类依赖了具体Laptop类,如Programmer中的use方法drive,这样Programmer就对具体的Laptop产生了依赖,如果这个时候想要使用其它的工具如Desktop(桌面台式电脑),就需要修改Programmer类。因此我们需要抽象接口Computer,这样Programmer只需要依赖Computer即可,至于到底选择哪种电脑,就交给IOC容器,进行依赖注入即可。

    高层模块不应该依赖底层模块

    这句话是依赖倒置的核心。指的是概念的自包含,上层模块不应该去依赖具体的某个底层提供方。在设计系统时,常常会采用分层的方式:数据访问层,业务逻辑层,展示层等,而每一层会依赖下层的API,这样导致的问题就是难以替换下层的提供方。那应该如何做呢?业务逻辑层需要有自己的数据访问规范,也就是SPI,然后数据提供层去适配这个SPI,这样如果替换了下层的数据层之后对业务逻辑层也不会产生影响。

    抽象不应该依赖细节,细节应该依赖抽象

    有了上面的概念之后,自然也就有了依赖抽象而非细节,因为上层制定的是SPI(Service Provider Interface), 也就是一种通用的实现接口,由不同的实现方来提供实现。另外一般实现方也会提供自己的API接口供其他应用来使用,因此一般实现方会在自己的API上面封装一层SPI的适配层来提供给上层使用。
    依赖抽象而非细节也是依赖注入与IOC实现的基础。

    为什么需要Spring IoC

    IoC很好的体现了面向对象设计法则之一—— 好莱坞法则:“别找我们,我们找你”;即由IoC容器帮对象找相应的依赖对象并注入,而不是由对象主动去找。
    IOC理论提出的观点大体是这样的:借助于“第三方”实现具有依赖关系的对象之间的解耦,如下图:



    在Spring中通过IoC容器来创建这些对象,即由Ioc容器来控制对象的创建,控制外部资源获取(如:对象或资源文件等)。而控制反转在Spring中的体现就是:由容器来创建及注入依赖对象,对象只是被动的接受依赖对象,获取依赖对象的方式也被反转( 与反转相反的做法:通常由我们自己在对象中直接获取依赖对象 )。
    总结:IoC 不是一种技术,只是一种思想,一个重要的面向对象编程的法则,它能指导我们如何设计出松耦合、更优良的程序。传统应用程序都是由我们在类内部主动创建依赖对象,从而导致类与类之间高耦合,难于测试;有了IoC容器后,把创建和查找依赖对象的控制权交给了容器,由容器进行注入组合对象,所以对象与对象之间是 松散耦合,这样也方便测试,利于功能复用,更重要的是使得程序的整个体系结构变得非常灵活。

    相关文章

      网友评论

        本文标题:Spring源码解读,认识Spring IOC容器

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