Spring-IoC容器

来源:互联网 发布:windows 95 iso 编辑:程序博客网 时间:2024/06/10 03:05

  • 导读
  • Ioc概述
    • 通过分配工作的实例来理解Ioc的概念
    • IoC类型
      • 构造函数注入
      • 属性注入
    • 通过容器完成依赖关系的注入
  • 涉及的Java知识-Java反射

导读

为了更好地理解Spring的IoC容器,在这里我们通过具体的日常工作中分配工作的示例来模拟IOC的概念。

同时,Spring实现依赖注入的Java底层技术是 Java反射,因此我们也会对Java反射进行介绍。


Ioc概述

Ioc (Inverse of Control 控制反转 )是 Spring容器的内核,AOP、声明式事务等功能都是以此为基础。


通过分配工作的实例来理解Ioc的概念

这里写图片描述

举个例子,日常工作(设计、开发、测试、集成等等)

小明直接处理开发工作:

================DoDistributedWork ==========================package com.xgj.master.ioc;import com.xgj.master.ioc.distributor.ProjectManager;import com.xgj.master.ioc.intf.Dealer;import com.xgj.master.ioc.specific.DealerImpl;import com.xgj.master.ioc.specific.XiaoMing;public class DoDistributedWork {    /**     *      * @Title: doDevelopWork     * @Description: 小明和具体的工作强耦合     * @return: void     */    public void doDevelopWork(){        //小明直接侵入开发工作        XiaoMing xiaoMing = new XiaoMing();        xiaoMing.doWork();    }    ......}=========================XiaoMing ==========================package com.xgj.master.ioc.specific;public class XiaoMing {    public void doWork() {        System.out.println(XiaoMing.class.getSimpleName() + " says that he will do the develop work");    }}

让我们来看下此时的类关系图

这里写图片描述

可以发现: 开发工作和小明强耦合.

明智的管理者,会从工作分配的角度出发,而不会让工作和具体的处理人员强耦合的 ,那如何让小明和开发工作解耦呢?

同样的开发工作,小强小刚等都可以胜任,而不是绑定到小明一个人身上? 那该如何处理呢?

通过上述分析,我们知道需要为处理人员定义一个接口,任何实现了该接口的实现类都可以处理开发工作。

package com.xgj.master.ioc.intf;public interface Dealer {    /**     *      * @Title: doDevelopWork     * @Description: 接口方法     * @return: void     */    public void doDevelopWork();}

接下来,只要继承该接口,就可以胜任开发工作

package com.xgj.master.ioc.specific;import com.xgj.master.ioc.intf.Dealer;public class DealerImpl   implements Dealer{    @Override    public void doDevelopWork() {        System.out.println(DealerImpl.class.getSimpleName() +" says that he will do the work");     }}

分配工作:

    /**     *      * @Title: doDevelopWork2     * @Description: 引入接口,只奥是使具体的执行者和开发工作解耦     * @return: void     *      */    public void doDevelopWork2(){        // 引入接口 Dealer        Dealer dealer = new DealerImpl();        // 通过接口处理对应的工作        dealer.doDevelopWork();    }

此时的UML:

这里写图片描述

此时我们发现:
DoDistrubuteWork 同时依赖 Dealer 和 DealerImpl,需要在DoDistrubuteWork 创建DealerImpl,并没有实现 工作只依赖Dealer的效果。

但是Dealer必须通过具体的实现类才能完成工作,如何让DealerImpl 和 DoDistrubuteWork 无关 同时又能完成Dealer 的具体动作呢?

我们引入 PM,UML关系图如下

这里写图片描述

/**     *      * @Title: pmDistributeWork     * @Description: 引入PM,使 工作和具体的执行者解耦     * @return: void     */    public void pmDistributeWork(){        // 引入PM        ProjectManager projectManager = new ProjectManager();        // PM分配工作        projectManager.distributeWork();    }

通过引入PM,使得 工作和 具体的处理人员解耦。PM就像一台装配器,安排具体人员处理具体的工作。

现在我们反过来理解IOC。字面意思:控制反转

结合上面的例子:
- 控制: 选择具体Dealer的控制权
- 反转:指的是这种控制权转移到PM手中。

对于软件来说,即某一接口具体实现类的选择控制权从调用类中移除,转交由第三方决定, 即由Spring容器借由Bean配置来进行控制。

关于IoC的另外一个叫法,Martin Fowler提出了DI(Dependecy Injection 依赖注入),即让调用类对你一个接口实现类的依赖关系由地方(容器或者协作类)注入,以移除调用类对某一个接口实现类的依赖。

很显然, 依赖注入比控制反转更加直接明了,易于理解。


IoC类型

从注入方法上看, IoC分为

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

Spring支持 构造函数注入和属性注入。

构造函数注入

在构造函数注入中,通过调用类的构造函数,将接口实现类通过构造函数变量传入

package com.xgj.master.ioc.consInj;import com.xgj.master.ioc.specific.DealerImpl;public class DoDistributedWork {    private DealerImpl dealerImpl ;    // 注入Dealer的实现类    public DoDistributedWork(DealerImpl dealerImpl){        this.dealerImpl = dealerImpl;    }    public void doSomething(){        dealerImpl.doDevelopWork();    }}

DoDistributedWork 的构造函数不关心由谁来处理工作,只要在构造函数中传入的处理者能够完成指定工作即可, 具体的处理者由PM来安排,如下

package com.xgj.master.ioc.consInj;import com.xgj.master.ioc.specific.DealerImpl;public class PM {    public void distribute() {        // 指定Dealer的具体人员        DealerImpl dealerImpl = new DealerImpl();        // 注入dealerImpl到工作中        DoDistributedWork distributedWork = new DoDistributedWork(dealerImpl);        distributedWork.doSomething();    }    public static void main(String[] args) {        PM pm = new PM();        pm.distribute();    }}

属性注入

有时候,并非每个场景都需要DealerImpl,在这种情况使用构造函数注入并不妥当 ,可以考虑使用属性注入。

package com.xgj.master.ioc.properInj;import com.xgj.master.ioc.intf.Dealer;public class DoDistributedWork {    private Dealer dealer ;    // 属性注入    public void setDealer(Dealer dealer) {        this.dealer = dealer;    }    public void doSomething(){        dealer.doDevelopWork();    }   }

为Dealer提供一个setter方法,以便PM在需要注入Dealer的具体实现类。

package com.xgj.master.ioc.properInj;import com.xgj.master.ioc.intf.Dealer;import com.xgj.master.ioc.specific.DealerImpl;public class PM {    public void distribute(){        Dealer dealer = new DealerImpl();        DoDistributedWork distributedWork = new DoDistributedWork();        //通过属性setter方法 注入        distributedWork.setDealer(dealer);        distributedWork.doSomething();    }    public static void main(String[] args) {        PM pm = new PM();        pm.distribute();    }}

通过容器完成依赖关系的注入

虽然实现了 DoDistributedWork 和 DealerImpl的解耦,但是这些代码仍然存在,只是转移到了PM中而已。

如何将PM这部分也不要呢? 假设有个管理部门,管理部分来选择PM、Dealer等等,那么 每个部分之间就都实现了解耦。我们可以更加专注于也位于逻辑的开发。

Spring就是这样的一个容器,通过配置文件或者注解描述类和类之间的依赖关系,自动完成类的初始化和依赖注入工作。

这里写图片描述

package com.xgj.master.ioc.springInj;import com.xgj.master.ioc.intf.Dealer;public class DealerImpl   implements Dealer{    @Override    public void doDevelopWork() {        System.out.println(DealerImpl.class.getSimpleName() +" says that he will do the work");     }}
package com.xgj.master.ioc.springInj;public class DoDistributedWork {    private DealerImpl dealerImpl ;    public void setDealerImpl(DealerImpl dealerImpl) {        this.dealerImpl = dealerImpl;    }    public void doSomething(){        dealerImpl.doDevelopWork();    }   }
<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans"    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"    xmlns:context="http://www.springframework.org/schema/context"    xsi:schemaLocation="http://www.springframework.org/schema/beans        http://www.springframework.org/schema/beans/spring-beans-4.3.xsd">    <!-- 实现类实例化 -->    <bean id="dealerImpl" class="com.xgj.master.ioc.springInj.DealerImpl" />    <bean id="doDistributedWork" class="com.xgj.master.ioc.springInj.DoDistributedWork"        p:dealerImpl-ref="dealerImpl" /> <!-- 通过 dealerImpl-ref 建立依赖关系--></beans>

测试类

package com.xgj.master.ioc.springInj;import org.springframework.context.ApplicationContext;import org.springframework.context.support.ClassPathXmlApplicationContext;public class SpringInjTest {    public static void main(String[] args) {        // TODO Auto-generated method stub        ApplicationContext context = new ClassPathXmlApplicationContext("Beans.xml");        DoDistributedWork doDistributedWork = (DoDistributedWork) context.getBean("doDistributedWork");        doDistributedWork.doSomething();    }}

这里写图片描述


涉及的Java知识-Java反射

Spring为什么会这么简洁,仅仅靠一个配置文件就可以实例化并装配好程序用到的Bean呢?

主要归功于Java类反射功能。

详见 Java-Java反射


原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 电脑帐号锁定了怎么办 云校家帐号被锁定怎么办 qq音乐停止运行怎么办 做事效率低怎么办教案 孩子做事效率低怎么办 百度搜不到答案怎么办 学乐云账号忘了怎么办 wps云空间不足怎么办 超星密码忘了怎么办 百度钱包忘记密码怎么办 宝宝吃了粉笔怎么办 粉笔灰进眼睛怎么办 讲公开课紧张怎么办 课堂派考勤旷课怎么办 2018qq音乐付费怎么办 不满一个月社保怎么办 试用期未买社保怎么办 小视频转发黑屏怎么办 听歌要钱的怎么办 手机歌曲要付费怎么办 安装包已损坏怎么办 方舟 安装包损坏怎么办 安装包已删除怎么办 超大附件过期了怎么办 邮箱被黑客盯上怎么办 云闪付安全问题忘记了怎么办 不知道网易账号怎么办 登录过程初始化失败怎么办 登录进程初始化失败怎么办 网易邮箱地址忘了怎么办 电脑电源短路了怎么办 电脑电源有问题怎么办 手机账号忘了怎么办 简历周五发了怎么办 网易邮箱被注销怎么办 foxmail接收密码忘记怎么办 招才猫企业邮箱认证没有怎么办 管理员账号被删除怎么办 我想办个信用卡怎么办 qq邮箱支付宝怎么办 12306忘记了邮箱怎么办