认识Spring

Spring框架有两个核心思想,一个是IoC控制反转,一个是AOP面向切面编程。

控制反转的意思就是,对象交给IoC container创建、管理,不再需要自己去new一个对象,如果这个对象依赖其他对象或资源,那么由IOC容器帮忙注入。DI依赖注入就是IoC思想的一种实现方式。原本是上层依赖下层,通过依赖注入的方式,将下层作为参数注入给上层,实现上层控制下层的功能。

举个例子,A类有个B类的成员变量,B类中有一个C类的成员变量,那么如果在C类增加了一个新的元素,导致的结果就是,A、B、C三个类的代码都要修改(构造方法上添加一个新的参数)。在使用上,构建一个A类的对象的时候,通过把新的参数传递给A,继而传给B,最后传给C,达到给C类对象的新参数赋值或者初始化的目的。
而控制反转以后,过程是初始化C类对象,把C类对象作为参数传给B类,B类再传给A类。这个过程中,A类接受的对象永远都是B类对象,B类对象接受的参数是C类对象,所以对C类对象内部的修改不影响B类和A类对C类的依赖。这样每次修改,只需要修改相应的对象就行,不需要改动原本那些依赖它的对象。

那么由谁来做控制反转这件事呢?答案是"IoC容器" 。IoC容器在这个过程中就是起到把下层传递给上层的作用,由它负责给你产生一个“控制反转过的对象”,也就是上述的 不需要自己去new一个对象。

IoC容器具体是什么? 粗略地说,它是一个工厂。在实现上,需要一个xml来配置这个容器,这个xml文件里需要把类注册成"bean",隐藏细节,这样在使用时就不需要关注细节了(比如上个例子,你只需要知道自己需要一个A对象,不用去了解生成一个A对象需要一个传入一个B和一个C,也不用知道去传入什么参数,这些在xml里面配置好了)。bean 就是那个被“控制反转”了的类。你调用它,它返回一个bean。

前面说到的注入,就是具体实现上层控制下层的方式,主要包含有两种方式:构造方法注入 和 setter方法注入。
而IoC容器,包含了 BeanFactory 和 ApplicationContext 两种。后者是前者的子类。

那么接下来在实践中看看以上概念到底是什么东西,——idea启动!

一、建立项目,手动或者用maven导入需要的包(core、context、expressions、beans和common-logging、log4j)

<dependency>
  <groupId>commons-logging</groupId>
  <artifactId>commons-logging</artifactId>
  <version>1.1.1</version>
</dependency>
<dependency>
  <groupId>log4j</groupId>
  <artifactId>log4j</artifactId>
</dependency>
<dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-core</artifactId>
  <version>5.0.8.RELEASE</version>
</dependency>
<dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-context</artifactId>
  <version>5.0.8.RELEASE</version>
</dependency>
<dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-beans</artifactId>
  <version>5.0.8.RELEASE</version>
</dependency>
<dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-expression</artifactId>
  <version>5.0.8.RELEASE</version>
</dependency>

二、建立类似结构

三、beans组成

1、Eyes 接口


package cn.ldy.beans;
public interface Eyes {
    void show();
}

2、BlueEyes 和 RedEyes 实现类


//BlueEyes.java
package cn.ldy.beans;
public class BlueEyes implements Eyes{
    @Override
    public void show() {
        System.out.println("Blue eyes!");
    }
}

//RedEyes.java
package cn.ldy.beans;
public class RedEyes implements Eyes {
    @Override
    public void show() {
        System.out.println("Red Eyes!");
    }
}

以及要注册的两个bean

3、BlueDragon 和 RedDragon


//BlueDragon.java
package cn.ldy.beans;
import java.util.List;
public class BlueDragon {
    private Eyes eyes;
    private int atk;
    private int def;
    private List<String> others;
    public BlueDragon(){
    }

    public BlueDragon(Eyes eyes, int atk, int def, List<String> others) {
        this.eyes = eyes;
        this.atk = atk;
        this.def = def;
        this.others = others;
    }

    public Eyes getEyes() {
        return eyes;
    }

    public void setEyes(Eyes eyes) {
        this.eyes = eyes;
    }

    public int getAtk() {
        return atk;
    }

    public void setAtk(int atk) {
        this.atk = atk;
    }

    public int getDef() {
        return def;
    }

    public void setDef(int def) {
        this.def = def;
    }

    public List<String> getOthers() {
        return others;
    }

    public void setOthers(List<String> others) {
        this.others = others;
    }

    public void summon(){
        System.out.println("Blue Dragon Summon!");
        eyes.show();
    }
}

//RedDragon.java
package cn.ldy.beans;
import java.util.List;
public class RedDragon {
    private Eyes eyes;
    private int atk;
    private int def;
    private List<String> others;

    public RedDragon(Eyes eyes, int atk, int def, List<String> others) {
        this.eyes = eyes;
        this.atk = atk;
        this.def = def;
        this.others = others;
    }

    public RedDragon() {
    }

    public Eyes getEyes() {
        return eyes;
    }

    public void setEyes(Eyes eyes) {
        this.eyes = eyes;
    }

    public int getAtk() {
        return atk;
    }

    public void setAtk(int atk) {
        this.atk = atk;
    }

    public int getDef() {
        return def;
    }

    public void setDef(int def) {
        this.def = def;
    }

    public List<String> getOthers() {
        return others;
    }

    public void setOthers(List<String> others) {
        this.others = others;
    }

    public void summon(){
        System.out.println("Red Dragon Summon!");
        eyes.show();
    }
}

接下来,就是把bean注册到配置文件里。

四、在beans.xml配置文件中注册bean

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

<bean name="blueeyes" class="cn.ldy.beans.BlueEyes"></bean>
<bean name="redeyes" class="cn.ldy.beans.RedEyes"></bean>

<bean name="bluedragon" class="cn.ldy.beans.BlueDragon">
    <property name="atk" value="3000"></property>
    <property name="def" value="2500"></property>
    <property name="eyes" ref="blueeyes"></property>
    <property name="others">
        <list>
            <value>8 stars</value>
            <value>dragon race</value>
        </list>
    </property>
</bean>
<bean name="reddragon" class="cn.ldy.beans.RedDragon">
    <constructor-arg name="atk" value="2400"></constructor-arg>
    <constructor-arg name="def" value="2000"></constructor-arg>
    <constructor-arg name="eyes" ref="redeyes"></constructor-arg>
    <constructor-arg name="others">
        <list>
        <value>7 stars</value>
        <value>dragon race</value>
        </list>
    </constructor-arg>
</bean>
</beans>

如上,在 beans 标签里的 bean就是注册的类。在此例中,我们把cn.ldy.beans.RedDragon(class属性中的值)这个类注册成bean,并且这个bean的name属性,也就是用来标识它的属性命名为reddragon(其他也是类似)。

最简单的,对于BlueEyes和RedEyes两个接口实现类来说,注册了一下,填了name和class就好了。
对于RedDragon和BlueDragon这两个bean来说,它们分别使用到了文章开头所说的constructor和set注入方式。

观察一下可以发现,bluedragon使用的set注入,就是利用property标签来设置bean中的属性的值。对比一下,可以看到,对于eyes属性,使用是的ref,也就是引用,从而给它注入了配置文件里的blueeyes这个bean;而对于基本类型,直接用value标签传递值即可。另外举了一个list的例子可以参看一下,这是细节上的问题,不再多说(数组、set等都是类似的形式)

reddragon使用的则是constructor注入,构造器注入,跟前者不一样的是,这个是在构造bean对象时就初始化,而set注入是构造一个默认bean对象,再用set方法注入。所以set方法需要默认构造器和set方法,而构造器注入需要完整的构造方法。注入的形式二者类似,亦不多说。

接下来,测试一下。

五、运行


//Test.java
package cn.ldy.test;
import cn.ldy.beans.BlueDragon;
import cn.ldy.beans.RedDragon;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Test {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
        BlueDragon blueDragon = (BlueDragon) context.getBean("bluedragon");
        blueDragon.summon();
        RedDragon redDragon = (RedDragon) context.getBean("reddragon");
        redDragon.summon();
    }

}

在这里,我们得到BlueDragon和RedDragon的对象的方式就不再是new一个出来了,而是利用一个IoC容器也就是ApplicationContext对象来替我们生成,具体需要一个什么对象,就是靠配置里的name属性来识别。它的生成过程就满足我们一开始讨论的,上层控制下层。现在就可以理解了,一个Dragon对象,它不需要自己在初始化的时候,给自己的Eyes赋值;而是反过来,在生成一个Dragon的过程中,我们是给Dragon传递了一个Eyes对象,这个Eyes你后续如何更改都无所谓,因为Dragon只管你是不是一个Eyes。而这反过来的这个生成过程,由我们配置在xml文件里,从而让IoC容器替我们生成对象。

看看结果:

posted @ 2018-08-17 15:18  木子李太宗  阅读(184)  评论(0编辑  收藏  举报