介绍

  这一节,我来介绍一下Spring三种基础配置方案中的最后一种配置,即Spring的Xml配置。xml配置是Spring的标配,是最早使用的方案,但是前面两节也说了,除非是比较特殊的要求,否则我们会选用前面两节的配置方案,但是,不得不说,xml也有很方便的时候,比如某些配置可能在程序部署过后需要改动,如数据库连接池属性的配置,包括连接地址,账户,密码,连接数等等,如果这些发生变化,可以不用修改程序重新打包,只需要修改xml文件,然后重新启动程序即可。
  Spring的xml配置方案有两种bean的注入方式,分别是构造函数注入和方法属性注入。其中,这两种注入方式分别有两种命名方法,如下:

  • 构造函数注入方式
    1、constructor-arg方法
    2、c-命名空间方法
  • 方法属性注入方式
    1、property方法
    2、p-命名空间方法

  下面我举个例子,说明这两种方法的使用,通过例子,我们就能够很好理解和使用Spring的Xml配置方案了。
  假设,我们有一个老师,这个老师很牛逼,能够同时教授语文和数学两门课程,现在,我们将创建一个老师类TeacherImpl,它实现了TeacherInter接口。为语文创建ChineseImpl类,它实现了Chinese接口,为数学创建MathImpl类,它实现了Math接口。下面我们以这个例子进行讲解。
  一、构造函数注入方式(constructor-arg)

  1、注入字面面
  什么是字面量,可以简单的理解为常量,代表的就是字面的意思。假设,我们老师现在教数学的算法,排序算法。那首先就需要为MathImpl创建bean,然后注入"排序"这个字面量,配置如下:

<bean id="math" class="lrf.spring.duty.MathImpl">
        <constructor-arg value="排序"/>
 </bean>

  从上面的配置可以知道,我们为MathImpl创建了一个id为math的bean,并通过构造函数方式的value属性,注入了"排序"这个字面量。于是类MathImpl就得到了这个字面量,下面是MathImpl部分代码(下文有本文例子的github地址哦):

private String algorithm;

    /**
     * 第一种方法:构造器注入字面量
     * @param algorithm
     */
    public MathImpl(String algorithm) {
        this.algorithm = algorithm;
    }
    
    @Override
    public void algorithm() {
        System.out.println("我现在教 "+algorithm+" 算法");
    }

  2、注入bean的引用
  第一步成功,接下来,我们将创建好的bean注入到我们的老师类TeacherImpl,这样,老师就能通过调用MathImpl的方法"教"数学了,xml配置如下:

<bean class="lrf.spring.handle.TeacherImpl">
        <constructor-arg ref="math"/>
  </bean>

  使用默认的bean id(即不直接写id名,因为没有其他地方引用,所以就不写了),我们为老师类TeacherImpl创建了一个bean,并注入了数学类的bean。这样,老师就能通过使用MathImpl的bean,调用MathImpl类的方法了,TeacherImpl类如下:

private MathImpl math;

    /**
     * 构造器注入bean
     * @param math
     */
    public TeacherImpl(MathImpl math) {
        this.math = math;
    }
    
    @Override
    public void teacher() {
        System.out.println("现在开始教数学");
        math.algorithm();
    }

  这样,我们就顺利的使用constructor-arg方法分别注入字面量和bean引用了,如果细心点,我们可以发现,其实这两种的唯一区别是,注入字面量使用"value"属性,注入bean引用使用"ref"引用,其它的没什么区别,就是这么简单。下面我们使用c-命名空间方法再举一下上面的例子。

  二、c-命名空间方法

  1、注入字面面
  废话就不多说了,我们直接看xml配置,如下:

<!--第一种,常用-->
  <bean id="math" class="lrf.spring.duty.MathImpl" c:algorithm="排序"/>
  <!--第二种-->
  <bean id="math" class="lrf.spring.duty.MathImpl" c:_0="排序" />
  <!--第三种,当构造函数参数只有一个的时候,可用这种,但是我用的spring版本不支持了。4.3.18.RELEASE-->
  <bean id="math" class="lrf.spring.duty.MathImpl" c:_="排序" />

  注意,使用c-命名空间方法方法需要加入c:命名空间xmlns:c=“http://www.springframework.org/schema/c”。c-命名空间有三种使用方法,配置中我也一一举例子了,使用的时候可以选用其中的一种即可,下面讲解一下:
  第一种: c:algorithm=“排序” algorithm是MathImpl构造函数的参数,意思是将字面量"排序"注入类中,以提供使用。
  第二种:c:_0=“排序” 这种方式看起来比较怪,但却是一种简便的方法。其中0是指构造函数参数的索引,从0开始,如果有多个参数,则按照索引值写就可以。前面的下划线,是因为xml配置的属性名第一个字符不能是数字。
  第三种:这种方法看起来更加诡异,连数字都没有,就一个下划线,这种情况的使用场景是构造函数只有一个参数,因此可以省略数字0,但是我用的版本不支持(我不太确定是否是版本不支持,我用的是Spring的4.3.18.RELEASE,我试了其它几个版本也不支持,知道的童鞋请不吝赐教)。
  这里的MathImpl的代码与上一节的 注入字面量 的代码一样,就不再贴出来了。

  2、注入bean的引用

  思路与第一节的一样,下面我们直接来看xml代码,如下:

<!--第一种,常用-->
  <bean class="lrf.spring.handle.TeacherImpl" c:math-ref="math"/>
  <!--第二种-->
  <bean class="lrf.spring.handle.TeacherImpl" c:_0-ref="math"/>
  <!--第三种,当构造函数参数只有一个的时候,可用这种,但是我用的spring版本不支持了。4.3.18.RELEAS-->
  <bean class="lrf.spring.handle.TeacherImpl" c:_-ref="math"/>

  注入bean的引用也有三种方法。通过对比上面的注入字面,其实我们很容易就能知道它的意思,不同的是(或者说,需要注意的是),属性名后面多了"-ref",这是引用这个单词的简写,其次,等号后面的值是一个bean的id名,而不是字面量,除了这两点区别之外,其它的都一样了。这里的TeacherImpl类的代码与上面的第一节的注入bean的引用一样,我就不贴出来了。在实际使用中,我们任选一种即可。怎么样,对比着学习,我们就能够进行快速的掌握,就能举一反三。

  注意 一般情况下,我建议使用c-命名空间的方法,理由就是代码写的少,方便。但是有一种情况下,我们必须使用constructor-arg方式,那就是构造函数的参数是一个集合类型时,要求我们注入集合类型,那我们就只能选择constructor-arg方式。比如构造参数为List类型。下面我们还是用本文的例子举例。
  假如我们老师现在要教语文了,教的是诗,并且不仅是一位诗人的诗,有李白,杜甫,苏轼的诗。那我们就可以为语文类ChineseImpl注入这几个字面量(或者bean),配置如下:

<bean id="chinese" class="lrf.spring.duty.ChineseImpl">
  <constructor-arg>
       <list>
            <value>李白</value>
            <value>杜甫</value>
            <value>苏轼</value>
       </list>
  </constructor-arg>

  通过上面的配置,我们就能够将字面量注入语文类ChineseImpl,ChineseImpl代码如下:

private List<String> poetry;

    /**
     * 第一种方法:构造器注入字面量
     * @param poetry
     */
    public ChineseImpl(List<String> poetry) {
        this.poetry = poetry;
    }

    @Override
    public void poetry() {
        for (String str: poetry) {
            System.out.println("我现在教 "+str+" 的诗");
        }
    }

  如果我们需要注入的是多个bean,那么可以下像下面这么做。

</bean><bean id="chinese" class="lrf.spring.duty.ChineseImpl">
    <constructor-arg>
        <list>
            <ref bean="bean"/>
            <ref bean="bean1"/>
            <ref bean="bean2"/>
        </list>
    </constructor-arg>

  以上不仅可以使用list,也可使用set,但是set的重复值都会被省略掉,顺序得不到保证,这两者都可以用来装配List,Set,甚至数组。

  三、方法属性注入方式(property)

  属性方法注入,是指,将字面量或者是bean通过类的方法参数注入类中。一般情况下,我们习惯使用setter方法,但是这只是一种习惯而已,方法名并不重要。下面我们来看看通过方法的参数如何进行注入。
  1、注入字面量
  上面说过,我们要学会类比学习,因此,我们这里可以类比第一节的一小结的注入字面量。下面是注入字面量的xml配置。

<bean id="math" class="lrf.spring.duty.MathImpl">
        <property name="algorithm" value="排序"/>
  </bean>

  将字面量"排序"注入到MathImpl的方法中,方法的参数为algorithm,下面是MathImpl中的方法。

/**
     * 第二种方法:属性注入字面量
     * @param algorithm
     */
    public void setAlgorithm(String algorithm) {
        this.algorithm = algorithm;
    }

  这样,参数algorithm就能够获得值"排序"。值准备好过后,我们就可以将这个math bean注入到老师类TeacherImpl中了。
  2、注入bean
  通过下面的xml,我们就能够将math bean注入了。

<!--创建一个bean,引用一个bean-->
    <bean class="lrf.spring.handle.TeacherImpl">
        <property name="math" ref="math"/>
    </bean>

  这样就顺利的将math bean注入到老师类TeacherImpl中了,方法的参数是math。代码如下:

private MathImpl math;
   
    public void setMath(MathImpl math) {
        this.math = math;
    }

  只要我们细心一点,就能发现,其实注入字面量与bean的区别进行是value和ref,value表示注入字面量,ref 表示注入bean引用。与第一节的类似。怎么样,很简单吧。下面,我们来看看p-命名方法的使用。

  三、方法属性注入方式(p-命名方法)

  2、注入字面量
  这里需要注意的是,因为一个方法参数只能有一个,因此不会像上面的有三种方法。

<bean id="math" class="lrf.spring.duty.MathImpl" p:algorithm="排序"/>

  其中,algorithm是MathImpl类中的参数。下面我们看看怎样将这个math bean注入到老师类TeacherImpl中。
  2、注入bean
  下面是xml配置。

<!--创建一个bean,引用一个bean-->
    <bean class="lrf.spring.handle.TeacherImpl"
          p:math-ref="math"
    />

  这样便达到了我们的目的,还是一样的,与注入字面量的区别仅仅是"-ref"后缀的区别。其它的都一样了。下面是老师类的代码。

private MathImpl math;
   
    public void setMath(MathImpl math) {
        this.math = math;
    }

  注意,这里一般情况也是推荐使用p-命名方式,但是它也存在当参数是集合类型的时候,它是无法做到了。只有property 才能做到,比如下面的配置。

<!--注入字面量-->
    <bean id="chinese" class="lrf.spring.duty.ChineseImpl">
        <property name="poetry">
            <list>
                <value>李白</value>
                <value>杜甫</value>
                <value>苏轼</value>
            </list>
        </property>
    </bean>

  同样的,这里的poetry也是参数的名称,上面是注入字面量,也可以注入bean,如下所示。

<!--注入bean-->
    <bean id="chinese" class="lrf.spring.duty.ChineseImpl">
        <property name="poetry">
            <list>
                <ref bean="bean"/>
                <ref bean="bean1"/>
                <ref bean="bean2"/>
            </list>
        </property>
    </bean>

  java类的代码我就不贴出来了,可以参考第一节的代码。到这里,我们已经将Spring的三种基础配置讲完,如果掌握,就算入门了,我们需要把基础打好,基础很重要,接下来,我们都会使用到它。大家可以参考Craig Walls这位大牛编著的Spring In Action(第四版),张卫滨翻译。笔者也是通过学习他的书入门的,感谢这两位大牛,这是所提供的网站,也可以在上面学习https://www.manning.com,本文的案例代码已上传至我的github,https://github.com/geeeeet/SpringXmlConfig.git 感兴趣的同胞可以一起学习,如发现疏漏错误的地方,请不吝赐教。