springJava技术文章我爱编程

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

2016-03-17  本文已影响997人  黄洪清

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

为什么需要Spring容器 ?(Why Spring Container)

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

先看看没有Spring之前,我们怎么做.
以一个现实的情况说明.大家应该都有过购买手机的经历.
收到手机后,打开包装, 给手机装上SIM卡,装上电池,开机 ...

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

package demo;

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

2, Simcard.java

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.java

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个零件,创建和组装过程就很繁琐.
试想,我们网购了一辆山地自行车,要把它装配起来,我们首先会看货品清单和装配说明书.

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

模拟简单容器

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

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)

上一篇下一篇

猜你喜欢

热点阅读