轻松理解Java Spring 核心功能之一: 控制反转容器(IoC Container)

控制反转容器(IoC Container)是Spring的一个重要基础功能,不喜欢新名词的同窗,姑且理解为组件装配容器.java

为何须要Spring容器 ?(Why Spring Container)

要理解Spring的设计精神,先来看看Spring的设计初衷.git

先看看没有Spring以前,咱们怎么作.
以一个现实的状况说明.你们应该都有过购买手机的经历.
收到手机后,打开包装, 给手机装上SIM卡,装上电池,开机 ... github

咱们用java面向对象的思想作设计:
手机,SIM卡,电池, 这是三个对象,也可称为实体,物体,组件,零件
名称不重要,反正这是三个东西,天然对应三个java 对象.
1, Battery.javaspring

package demo;

public class Battery{
    private String power;
    public Battery(String power){
        this.power = power;
    }
    public String getPower(){
        return this.power;
    }
}

2, Simcard.javawindows

package demo;

public class Simcard{
    private String number;
    public Simcard(String  number){
        this.number = number;
    }
    public String getNumber(){
        return this.number;
    }
}

3, Mobile.java数组

package demo;
public class Mobile{
    private String brand;
    private Battery battery;
    private Simcard simcard;

    public Mobile(String brand){
        this.brand = brand;
    }
    public void setBattery(Battery battery){
        this.battery =  battery;
    }
    public void setSimcard(Simcard simcard){
        this.simcard = simcard;
    }
    public void poweron(){
        System.out.println("Mobile: " +  this.brand + " powered on");
        System.out.println("Battery: " + this.battery.getPower() );
        System.out.println("Simcard: " + this.simcard.getNumber() );

    }
}

不使用Spring 容器

4, 运行程序 Main.javagradle

package demo;

public class Main{
     public static void main(String[] args) {
        //建立零件
         Mobile mobile = new Mobile("XiaoMI1");
         Battery battery =  new Battery("2000mA");
         Simcard simcard = new Simcard("13612345678");
        //组装零件
         mobile.setBattery(battery);
         mobile.setSimcard(simcard);
        //使用
         mobile.poweron();
     }
}

以上程序不使用Spring,运行良好.
由于这里只有三个零件,建立和组装都没有问题.
若有一个设备由1000个零件,建立和组装过程就很繁琐.
试想,咱们网购了一辆山地自行车,要把它装配起来,咱们首先会看货品清单和装配说明书.this

Spring 容器就是为建立和组装零件而设计的.设计

模拟简单容器

在介绍Spring 容器以前, 先介绍一下容器的概念,初学者会对容器概念感到陌生.
现实生活中,装有糖果的盒子就是容器,Java里的容器和现实生活相似,只不过装的是对象实例.
这里对 Main.java 作些修改以解释容器概念
4, 运行程序 Main.javacode

package demo;

public class Main{
     public static void main(String[] args) {
          //建立容器
          Object[] container = new Object[3];
          //建立和组装实例
          Mobile mob = new Mobile("XiaoMI1");
          Battery bat = new Battery("2000mA");
          Simcard sim = new Simcard("13612345678");
          mob.setBattery(bat);
          mob.setSimcard(sim);
          //放入容器
          container[0] = mob;
          container[1] = bat;
          container[2] = sim;
          //从容器中获取实例
          Mobile mobile = (Mobile) container[0];
          mobile.poweron();
     }
}

以上程序建立数组做为容器, 建立和组装实例后放入容器, 使用时,从容器中获取实例.
这个程序看起来有些画蛇添足,确体现了容器的主要特性.
这里,咱们手动完成了 建立容器->建立和组装实例->放入容器的工做.
使用Spring后,这些工做就能够由Spring来完成.
这里,咱们使用对象数组做为容器, 经过数字下标获取对象, Spring 使用ConcurrentHashMap 做为容器, 经过字符串ID获取对象. (事实上ConcurrentHashMap 内部也是把对象包装一下放到数组里)

这里,零件之间的装配关系经过人工完成,而Spring经过配置文件来描述零件之间的装配关系.
Spring的配置文件使用XML格式描述组件清单和装配关系,这个配置文件至关于现实生活中的货品清单和装配说明书.

使用Spring容器

使用Spring容器时,须要一个配置文件(货品清单) manifest.xml
5, manifest.xml

<?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-4.0.xsd">

    <bean id="battery1" class="demo.Battery">
            <constructor-arg name="power" value="3000mA" />
    </bean>
    <bean id="simcard1" class="demo.Simcard">
            <constructor-arg name="number" value="13512345678" />
    </bean>
    <bean id="mobile1" class="demo.Mobile">
            <constructor-arg name="brand" value="Xiaomi" />
             <property name="Simcard" ref="simcard1"/>
            <property name="Battery" ref="battery1"/>
    </bean>

</beans>

这里的bean 就是对象实例的意思,java里全部对象实例均可称为bean
这个配置文件,简单的说就是一个bean的列表. 每一个bean经过XML配置其建立初始值或是装配对象. id属性,是为了之后便于从容器中获取.
这个配置文件里battery1,simcard1 咱们设定的构造参数,而mobile1, 咱们设定了构造参数的同时还装配了具体的Battery和Simcard.

4, 运行程序 Main.java( 使用Spring)

package demo;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Main{
     public static void main(String[] args) {
          ApplicationContext context= new ClassPathXmlApplicationContext("manifest.xml");
          Mobile mobile = (Mobile) context.getBean("mobile1");
          System.out.println("************************");
          mobile.poweron();
    }
}

这里的context, 简单的理解就是对象容器, Spring 经过分析配置文件完成对象建立,装配的工做.
使用时,经过ID获取容器对象.

Spring容器经过配置文件来描述零件清单和装配关系,装配关系变更时,修改配置便可,不用从新编译代码.
对于简单的例子,看不出Spring容器的优点.
当对于零件不少,装配关系复杂多变的系统,就能体现Spring的优点.

Spring 容器除了使用xml来配置,还可使用注解(annotation)来配置. 注解配置,这里不在展开细说,总之,二者的功能是同样的,看我的喜爱使用.

运行源代码

git clone https://github.com/huanghq/SpringContainerExample.git
cd SpringContainerExample/
./gradlew run
(windows 用户:gradlew.bat run)

************************
Mobile: Xiaomi powered on
Battery: 3000mA
Simcard: 13512345678

运行源代码要求Java1.7 环境,支持跨平台.
使用gradle 下载依赖包,编译运行.不熟悉gradle的同窗不要紧.
只需专一上述java文件和配置文件,
第一次运行须要下载gradle和java依赖包,有些慢,耐心等待.

对控制反转(IOC)概念感兴趣的同窗,参看下文:
Java开发中的依赖注入(DI)和控制反转(IOC)

相关文章
相关标签/搜索