美文网首页springJava技术文章我爱编程
轻松理解Java Spring 核心功能之一: 控制反转容器(I

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

作者: 黄洪清 | 来源:发表于2016-03-17 14:36 被阅读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)

    相关文章

      网友评论

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

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