天天看点

spring Ioc 容器深入理解<一>

IoC 概述

    IOC是spring的内核,Aop、声明式事务都能功能都依赖于此功能,它涉及代码解耦,设计模式,代码优化的问题的考量。

ioc的初步理解

    ioc的概念重要但比较晦涩难懂,如下通过一个小例子来说明这个概念:     示例场景:电影: 无间道-》角色:刘建明-》演员:刘德华

spring Ioc 容器深入理解<一>

    刘德华饰演的刘建明和梁朝伟饰演的刘建明来到了天台之上,刘德华对梁朝伟说了一句经典台词:“我想做个好人”,我想用一个java类来为这天台对白的场景,进行编剧,并借此来理解ioc的概念

ioc的注入类型

    在传统的编程模式中,是剧本和演员来直接耦合的,我们会发现以上剧本,所以具体角色饰演的刘德华直接侵入到剧本当中,使剧本和演员直接耦合到了一起,那么一个明智的编剧,在剧情创作时,应该围绕故事的角色来进行,而不应该考虑角色的具体的饰演者,这样才能在剧本拍摄时,自由的选择演员,而并非绑定在刘德华一个人身上,那么通过以上的分析,我们知道需要为剧本主人公刘建明来定义一个接口。

spring Ioc 容器深入理解<一>

    如图,就是引入角色接口的示意图,那么我们引入了剧本角色刘建明,而剧本的情节通过 角色来展开,在拍摄时,角色由演员来饰演,就像这幅图一样,其中无间道,刘建明,和刘德华三者之间的关系图。

spring Ioc 容器深入理解<一>

     可以在这图当中,我们可以看到无间道同时依赖刘建明和刘德华,并没有达到我们所期望的,剧本仅依赖与角色的目的,但是角色必须最终具体的演员来完成,那么如果让刘德华和剧本无关,而能完成刘建明的具体动作呢,那么还是电影无间道这个场景,在这里我们引入了导演,在引入导演之后,剧本和饰演者就完全解耦了。首先,我们建立了一个导演类,接下来导演要选择一个剧本,同时,为剧本定一个角色,《刘建明》,让刘建明这个角色插入到无间道这个剧本当中去,最后让刘德华来饰演刘建明这个角色,你们通过引入导演之后,使剧本和具体的饰演者顺利的解耦,对应到软件当中,导演就是个装配器,它来安排演员,来饰演具体角色。

    反过来讲解IOC的概念,IOC从字面上的意思,就是控制和反转,它包含两个内容,第一是控制,第二是反转。它到底是什么东西的空值并反转呢,对应到前面 的例子。控制指的是选择刘建明的角色扮演者的控制权,而反转是指这种控制权,从无间道剧本中移除,转交到导演手中,对于软件来说,即是具一个接口的实现类的控制权,从调用类中来移除,转接到第三方来决定,那么IOC确实不够开门见山,一次业界进行了广泛的讨论,那么最终提出了DI ,就是依赖注入,用这个概念来替代ioc,即让调用类对一个接口实现类的依赖关系,由第三来注入,已移除调用类对于某一接口实现类的依赖,依赖注入这个词,显然比控制反转直接明了,易于理解。

ioc的注入方式

    从注入方法上看,主要划为三种类型:

1、构造函数的注入 2、属性的注入 3、接口的注入

    spring构造函数注入和属性注入。

三种注入的区别,

    1、构造函数的注入,在构造函数注入当中,我们通过调用类的构造函数,来讲接口实现类通过构造函数变量来注入

Public class WuJIanDao{
    private LiuJianMing ljm;
    // 1:注入刘建明的具体扮演者
    public WuJianDao(LiuJianMing ljm){
        this.ljm=ljm;   
    }

    public void tianTai(){
        ljm.declar("我想做个好人");
    }

}
           

    无间道的构造函数,不关心具体是谁来扮演刘建明这个角色,只要代码 1 处,去按照剧本的要求来完成相应的表演,那就可以了。那么角色的具体的扮演者,由谁来安排呢。

Public class Director{
    public void direct(){
        //2.指定角色的扮演者
        LiuJianMing ljm = new LiuDeHua();
        //3.注入具体扮演者到剧本中
        WuJianDao wjd - new WuJianDao(ljm);
        wjd.tianTai();
    }    

}
           

    在代码 2 处,导演安排刘德华来饰演刘建明这个角色,并在 代码 3 处,将刘德华注入到无间道这个剧本当中,然后开始天台对白的剧情的演出工作。那么有时候,导演就会发现虽然刘建明是影片无间道的第一主角,但并非每个场景都需要刘建明的出现,那么在这种情况下,通过构造函数来注入。并不是太妥当,那么这个时候可以考虑属性来注入。

    2、属性注入:通过Setter 方法来完成调用类所需依赖的注入,更加灵活方面和方便,

Public class WuJianDao{
    private LiuJianMing ljm;
    public void setLjm(LiuJianMing ljm){
        this.lim=ljm
    } 
    public void  tianTai(){
        ljm.cleclaer("我想做个好人");
    }

}
           
Public class Director{
    public void direct(){
        //2.指定角色的扮演者
        LiuJianMing ljm = new LiuDeHua();
        //3.注入具体扮演者到剧本中
        WuJianDao wjd - new WuJianDao(ljm);
        wjd.setLjm(ljm);
        wjd.tianTai();
    }    

}
           

    无间道当中,通过set方法来注入刘建明角色扮演者,无间道在 1 处,为刘建明属性提供另一个set方法,以便导演在需要使,来注入刘建明的具体扮演者,可以看代码 2 处,这里无间道调用属性set方法,来讲刘建明这个角色扮演者交由刘德华来进行表演。和通过构造函数注入 刘建明扮演者不同,在实例化无间道剧本时,并未指定任何扮演者,而在实例化无间道之后,在需要刘建明出场的时候,才调用set刘建明这个方法,来注入扮演者。按照类似的方式,我们还可以为剧本当中其他的角色来提供注入set 方法。这样导演就可以根据所拍场景不通,来注入相应的角色了。

    3、接口注入:将调用类所依赖注入的方法抽取到一个接口中,调用类通过实现该接口提供相应的注入方法。

    我们采取接口注入的方法,首先我们要声明一个接口,这里我们需要声明一个

Public interface ActorArrangable{
    void injectLjm(LiuJianMing ljm );    
}
           
Public class WuJianDao implements ActorArrangable{
    private LiuJianMing ljm;
    public void void injectLjm(LiuJianMing ljm ){
        this.ljm=ljm;
    }
    public void tianTai(){
        lm.clecare("我想做个好人");    
    }

}
           
Public class Director{
    public void direct(){
     
        LiuJianMing ljm = new LiuDeHua();
        
        WuJianDao wjd = new WuJianDao(ljm);
        wjd.injectLjm(ljm);
        wjd.tianTai();
    }    

}
           

    我们定义了一个injectLjm,在这里我们将刘建明这个角色注入到剧本当中,然后无间道实现了该接口的具体的实现,在这个类当中,它实现了接口中的方法。通过接口方法,来注入刘建明扮演者。 接下来我们通过导演来通过ActorArrangable 的 injectLjm 方法来完成扮演者的注入工作。

    那么由于通过接口注入,需要先声明一个接口,无疑增加了类的数量,而且效果和属性注入并没有本质上的却别,所以在spring ioc 中,并不提倡采用这种方式。

    虽然剧本无间道和演员刘德华实现了解耦,无间道无需关注角色实现类的实例化工作,但是这个工作在代码当中,依然是存在,只不过是转移到了导演类中而已,那么假设某一制片人,想改变这一局面,在选择某一剧本之后,希望通过一个海选,或第三方中介机构来选择导演、演员。然他们各司其职,在剧本、导演、演员都实现了解耦。那么所谓海选和第三方结构在程序中就是第三方的容器,它帮助完成类的初始化和装配工作。让开发者从这些底层的类的实例化,依赖关系装配中脱离出来,能够专注业务逻辑开发的工作,这无疑是一种令人向往的事情。spring就是这么一个容器,它通过配置文件,或注解来描述类和类的关系,自动完成类的初始化和依赖注入的工作。

配置文件片段   //1.实现类的实例化 <bean id = "ljm" class="LiuDeHua"/> // 2.通过ljm-ref 建立依赖关系  <bean id = "wjd" class="WuJianDao" p:ljm-ref="ljm"/>     在代码 1 处,实现了类的实例化,在 代码 2 处,我们通过ljm-ref 建立了依赖关系。

IoC 概述     IOC是spring的内核,Aop、声明式事务都能功能都依赖于此功能,它涉及代码解耦,设计模式,代码优化的问题的考量。

ioc的初步理解

    ioc的概念重要但比较晦涩难懂,如下通过一个小例子来说明这个概念:     示例场景:电影: 无间道-》角色:刘建明-》演员:刘德华

    刘德华饰演的刘建明和梁朝伟饰演的刘建明来到了天台之上,刘德华对梁朝伟说了一句经典台词:“我想做个好人”,我想用一个java类来为这天台对白的场景,进行编剧,并借此来理解ioc的概念

ioc的注入类型

    在传统的编程模式中,是剧本和演员来直接耦合的,我们会发现以上剧本,所以具体角色饰演的刘德华直接侵入到剧本当中,使剧本和演员直接耦合到了一起,那么一个明智的编剧,在剧情创作时,应该围绕故事的角色来进行,而不应该考虑角色的具体的饰演者,这样才能在剧本拍摄时,自由的选择演员,而并非绑定在刘德华一个人身上,那么通过以上的分析,我们知道需要为剧本主人公刘建明来定义一个接口。

    如图,就是引入角色接口的示意图,那么我们引入了剧本角色刘建明,而剧本的情节通过 角色来展开,在拍摄时,角色由演员来饰演,就像这幅图一样,其中无间道,刘建明,和刘德华三者之间的关系图。

     可以在这图当中,我们可以看到无间道同时依赖刘建明和刘德华,并没有达到我们所期望的,剧本仅依赖与角色的目的,但是角色必须最终具体的演员来完成,那么如果让刘德华和剧本无关,而能完成刘建明的具体动作呢,那么还是电影无间道这个场景,在这里我们引入了导演,在引入导演之后,剧本和饰演者就完全解耦了。首先,我们建立了一个导演类,接下来导演要选择一个剧本,同时,为剧本定一个角色,《刘建明》,让刘建明这个角色插入到无间道这个剧本当中去,最后让刘德华来饰演刘建明这个角色,你们通过引入导演之后,使剧本和具体的饰演者顺利的解耦,对应到软件当中,导演就是个装配器,它来安排演员,来饰演具体角色。

    反过来讲解IOC的概念,IOC从字面上的意思,就是控制和反转,它包含两个内容,第一是控制,第二是反转。它到底是什么东西的空值并反转呢,对应到前面 的例子。控制指的是选择刘建明的角色扮演者的控制权,而反转是指这种控制权,从无间道剧本中移除,转交到导演手中,对于软件来说,即是具一个接口的实现类的控制权,从调用类中来移除,转接到第三方来决定,那么IOC确实不够开门见山,一次业界进行了广泛的讨论,那么最终提出了DI ,就是依赖注入,用这个概念来替代ioc,即让调用类对一个接口实现类的依赖关系,由第三来注入,已移除调用类对于某一接口实现类的依赖,依赖注入这个词,显然比控制反转直接明了,易于理解。

ioc的注入方式

    从注入方法上看,主要划为三种类型:

1、构造函数的注入 2、属性的注入 3、接口的注入

    spring构造函数注入和属性注入。

三种注入的区别,

    构造函数的注入,在构造函数注入当中,我们通过调用类的构造函数,来讲接口实现类通过构造函数变量来注入

Public class WuJIanDao{     private LiuJianMing ljm;     // 1:注入刘建明的具体扮演者     public WuJianDao(LiuJianMing ljm){         this.ljm=ljm;        }

    public void tianTai(){         ljm.declar("我想做个好人");     }

}

    无间道的构造函数,不关心具体是谁来扮演刘建明这个角色,只要代码 1 处,去按照剧本的要求来完成相应的表演,那就可以了。那么角色的具体的扮演者,由谁来安排呢。

Public class Director{     public void direct(){         //2.指定角色的扮演者         LiuJianMing ljm = new LiuDeHua();         //3.注入具体扮演者到剧本中         WuJianDao wjd - new WuJianDao(ljm);         wjd.tianTai();     }    

}

    在代码 2 处,导演安排刘德华来饰演刘建明这个角色,并在 代码 3 处,将刘德华注入到无间道这个剧本当中,然后开始天台对白的剧情的演出工作。那么有时候,导演就会发现虽然刘建明是影片无间道的第一主角,但并非每个场景都需要刘建明的出现,那么在这种情况下,通过构造函数来注入。并不是太妥当,那么这个时候可以考虑属性来注入。

    属性注入:通过Setter 方法来完成调用类所需依赖的注入,更加灵活方面和方便,

Public class WuJianDao{     private LiuJianMing ljm;     public void setLjm(LiuJianMing ljm){         this.lim=ljm     }      public void  tianTai(){         ljm.cleclaer("我想做个好人");     }

}

Public class Director{     public void direct(){         //2.指定角色的扮演者         LiuJianMing ljm = new LiuDeHua();         //3.注入具体扮演者到剧本中         WuJianDao wjd - new WuJianDao(ljm);         wjd.setLjm(ljm);         wjd.tianTai();     }    

}

    无间道当中,通过set方法来注入刘建明角色扮演者,无间道在 1 处,为刘建明属性提供另一个set方法,以便导演在需要使,来注入刘建明的具体扮演者,可以看代码 2 处,这里无间道调用属性set方法,来讲刘建明这个角色扮演者交由刘德华来进行表演。和通过构造函数注入 刘建明扮演者不同,在实例化无间道剧本时,并未指定任何扮演者,而在实例化无间道之后,在需要刘建明出场的时候,才调用set刘建明这个方法,来注入扮演者。按照类似的方式,我们还可以为剧本当中其他的角色来提供注入set 方法。这样导演就可以根据所拍场景不通,来注入相应的角色了。

    接口注入:将调用类所依赖注入的方法抽取到一个接口中,调用类通过实现该接口提供相应的注入方法。

    我们采取接口注入的方法,首先我们要声明一个接口,这里我们需要声明一个

Public interface ActorArrangable{     void injectLjm(LiuJianMing ljm );     }

Public class WuJianDao implements ActorArrangable{     private LiuJianMing ljm;     public void void injectLjm(LiuJianMing ljm ){         this.ljm=ljm;     }     public void tianTai(){         lm.clecare("我想做个好人");         }

}

Public class Director{     public void direct(){               LiuJianMing ljm = new LiuDeHua();                  WuJianDao wjd = new WuJianDao(ljm);         wjd.injectLjm(ljm);         wjd.tianTai();     }    

}

    我们定义了一个injectLjm,在这里我们将刘建明这个角色注入到剧本当中,然后无间道实现了该接口的具体的实现,在这个类当中,它实现了接口中的方法。通过接口方法,来注入刘建明扮演者。 接下来我们通过导演来通过ActorArrangable 的 injectLjm 方法来完成扮演者的注入工作。

    那么由于通过接口注入,需要先声明一个接口,无疑增加了类的数量,而且效果和属性注入并没有本质上的却别,所以在spring ioc 中,并不提倡采用这种方式。

    虽然剧本无间道和演员刘德华实现了解耦,无间道无需关注角色实现类的实例化工作,但是这个工作在代码当中,依然是存在,只不过是转移到了导演类中而已,那么假设某一制片人,想改变这一局面,在选择某一剧本之后,希望通过一个海选,或第三方中介机构来选择导演、演员。然他们各司其职,在剧本、导演、演员都实现了解耦。那么所谓海选和第三方结构在程序中就是第三方的容器,它帮助完成类的初始化和装配工作。让开发者从这些底层的类的实例化,依赖关系装配中脱离出来,能够专注业务逻辑开发的工作,这无疑是一种令人向往的事情。spring就是这么一个容器,它通过配置文件,或注解来描述类和类的关系,自动完成类的初始化和依赖注入的工作。

配置文件片段   //1.实现类的实例化 <bean id = "ljm" class="LiuDeHua"/> // 2.通过ljm-ref 建立依赖关系  <bean id = "wjd" class="WuJianDao" p:ljm-ref="ljm"/>     在代码 1 处,实现了类的实例化,在 代码 2 处,我们通过ljm-ref 建立了依赖关系。