实战Spring通过XML装配bean

在装配bean的时候,还有一种可选方案。官方可能认为这种方式不好,因为非 java 代码配置,但是每个人的看法和喜好不同,也不是说不能选择的。

目录

 

创建XML配置规范

声明一个简单的

如果不加 id

声明简单bean的一些特征

借助构造器注入初始化bean

构造器注入bean引用

Spring的c-命名空间

将字面量注入到构造器中

装配集合(list)

设置属性

将字面量注入到属性中

导入和混合配置

在JavaConfig中引用XML配置

在XML配置中引用JavaConfig

小结


创建XML配置规范

在使用JavaConfig的时候,这意味着要创建一个带 有@Configuration注解的类,而在XML配置中,这意味着要创建一个XML文件,并且要以<beans>元素为根。

最为简单的Spring 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"
  xmlns:context="http://www.springframework.org/schema/context"
  xsi:schemaLocation="http://www.springframework.org/schema/beans 
    http://www.springframework.org/schema/beans/spring-beans.xsd
	http://www.springframework.org/schema/context 
    http://www.springframework.org/schema/context/spring-context.xsd">
</beans>

这个基本的XML配置已经比同等功能的JavaConfig类复杂得多了。作为起步,在JavaConfig中所需要的只是@Configuration,但在使用XML时,需要在配置文件的顶部声明多个XML模式(XSD)文件,这些文件定义了配置Spring的XML元素。

当然在 idea 中,你只需要选择 file 然后新建,然后 如图:

他会创建一个最最最基础的 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.xsd">

</beans>

为了做测试,让我们重新在走一遍CD样例,这次使用XML配置,而不是前几篇文章 使用JavaConfig和自动化装配。

声明一个简单的<bean>

要在基于XML的Spring配置中声明一个bean,我们要使用spring-beans模式中的另外一个元素:<bean>

<bean>元素类似于JavaConfig中的@Bean注解。我们可以按照如下的方式声明CompactDisc bean:

  <bean id="compactDisc" class="soundsystem.SgtPeppers" />

这是最最基本的 声明 bean 的方式,当然 id 可有可无,创建这个bean的类通过class属性来指定的,并且要使用绝对路径,全路径。

如果不加 id

没有明确给定ID,所以这个bean将会根据全类名来进行命名。

在本例中,bean的ID将会是“soundsystem.SgtPeppers#0”。其中,“#0”是一个计数的形式(计数就是为了区分),用来区分相同类型的其他bean。

如果你声明了另外一个SgtPeppers(另外一个的前提是不在同一个包下),并且没有明确进行标识,那么它自动得到 的ID将会是“soundsystem.SgtPeppers#1”。

不过,通常来讲更好的办法是借助id属性,为每个bean设置一个你自己选择的名字,以便于日后引用可以直接使用。

声明简单bean的一些特征

  1. 无需负责创建SgtPeppers的实例,也就是初始化;

  2. 将bean的类型以字符串的形式设置在了class属性中,但是并不安全;

  3. 借助IDE检查XML的合法性;

借助构造器注入初始化bean

在Spring XML配置中,只有一种声明bean的方式:

使用<bean>元素并指定class属性

Spring会从这里获取必要的信息来创建bean。 但是,在XML中声明DI时,会有多种可选的配置方案和风格。

具体到构造器注入,有两种基本的配置方案可供选择:

  • <constructor-arg>元素
  • 使用Spring 3.0所引入的c-命名空间

两者的区别在很大程度就是是否冗长烦琐。可以看到,<constructor-arg>元素比使用c-命名空间会更加冗长,从而导致XML更加难以读懂。另外,有些事情<constructor-arg>可以做到,但是使用c-命名空间却无法实现。

构造器注入bean引用

在XML中声明CDPlayer并通过ID引用SgtPeppers:

  <bean id="compactDisc" class="soundsystem.SgtPeppers" />
        
  <bean id="cdPlayer" class="soundsystem.CDPlayer">
    <constructor-arg ref="compactDisc" />
  </bean>

字面意思就是 名为 cdPlayer 的这个类,引用了 名为 compactDisc 这个类,当Spring遇到这个<bean>元素时,它会创建一个CDPlayer实例。

Spring的c-命名空间

c-命名空间是在Spring 3.0中引入的,它是在XML中更为简洁地描述构造器参数的方式。 要使用它的话,必须要在XML的顶部声明其模式,如下所示,在 beans 根目录下 新增:

xmlns:c="http://www.springframework.org/schema/c"

在c-命名空间和模式声明之后,我们就可以使用它来声明构造器参数了,如下所示:

<bean id="compactDisc" class="soundsystem.SgtPeppers" />
        
<bean id="cdPlayer" class="soundsystem.CDPlayer" c:cd-ref="compactDisc" />

c:写法更加简洁,当做 bean 的一个子属性来处理。

c:cd-ref命名来源

属性名以“c:”开头,也就是命名空间的前缀。

接下来就是要装配的构造器参数名,也就是 cd,这个cd 是 构造方法的传参 参数值:

@Autowired
public CDPlayer(CompactDisc cd) {
  this.cd = cd;
}

在此之后是“-ref”,这是一个命名的约定,它会告诉Spring,正在装配的是一个bean的引用,这个bean的名字是compactDisc。

c-命名空间属性能够更加有助于使代码的长度简洁明了。

注意事项

它直接引用了构造器参数的名称。引用参数的名称看起来有些怪异, 因为这需要在编译代码的时候,将调试标志(debug symbol)保存在类代码中。如果你优化构建过程,将调试标志移除掉,那么这种方式可能 就无法正常执行了。

替代的方案

我们使用参数在整个参数列表中的位置信息:

 <bean id="cdPlayer" class="soundsystem.CDPlayer" c:_0-ref="compactDisc"/>

这种写法就更蛋疼了,c:cd 还好理解,cd 就是构造函数的传值参数,而这个需要 将参数的名称替换成了“0”,也就是参数的索引。因为在XML中不允许数字作为属性 的第一个字符,因此必须要添加一个下画线作为前缀。看上去非常古怪,不如上面的号,毕竟见名知意。但是缺点就是,参数名改了,你这边也要 改。而使用索引,则无需考虑。

如果有多个构造 器参数的话,这当然是很有用处的。在这里因为只有一个构造器参数,所以我们还有另外一个方案——根本不用去标示参数:

需要注意的是,我在自己测试的时候,这样写 idea 会检测认为报错,可能是编辑器问题。

<bean id="cdPlayer" class="soundsystem.CDPlayer" c:_-ref="compactDisc"/>

将字面量注入到构造器中

迄今为止,我们所做的DI通常指的都是类型的装配——也就是将对象的引用装配到依赖于它们的其他对象之中——而有时候,我们需要做的只 是用一个字面量值来配置对象。

之前写的 cd 类, 在SgtPeppers中,唱片名称和艺术家的名字都是硬编码的。 很不符合 java 面向接口的思想,更违背了 多态的 核心。

接下来的做法,使他更加灵活,像现实中的空磁盘一样, 它可以设置成任意你想要的艺术家和唱片名。

package soundsystem;

/**
 * 像现实中的空磁盘一样, 它可以设置成任意你想要的艺术家和唱片名
 *
 * @author imenger
 */
public class BlankDisc implements CompactDisc {

    private String title;
    private String artist;

    public BlankDisc(String title, String artist) {
        this.title = title;
        this.artist = artist;
    }

    @Override
    public void play() {
        System.out.println("Playing " + title + " by " + artist);
    }

}

我们再次使用<constructor-arg>元素进行构造器参数的注入。但是这一次我们没有使用“ref”属性来引用其他的bean,而是使用 了value属性,通过该属性表明给定的值要以字面量的形式注入到构造器之中。

  <bean id="compactDisc"
        class="soundsystem.BlankDisc">
    <constructor-arg value="Sgt. Pepper's Lonely Hearts Club Band" />
    <constructor-arg value="The Beatles" />
  </bean>

等同于 c-命名空间(c:_title 这种方式不再赘述):

    <bean id="compactDisc" class="soundsystem.BlankDisc"
          c:_0="Sgt. Pepper's Lonely Hearts Club Band"
          c:_1="The Beatles"/>

假设BlankDisc只有一个构造器参数,这个参数接受唱片的名 称。在这种情况下,我们可以在Spring中这样声明它:

<bean id="compactDisc" class="soundsystem.BlankDisc"
          c:_="Sgt. Pepper's Lonely Hearts Club Band"/>

装配集合(list)

到现在为止,我们假设CompactDisc在定义时只包含了唱片名称和艺术家的名字。也就是一个光盘一首歌,显然 现在技术 已经远远超过这个样子了,CD之所以值得购买是因为它上面所承载的音乐。大多数的CD都会包含十多个磁道,每个磁道上包含一首歌。

如果使用CompactDisc为真正的CD光盘的话,那么它也应该有磁道列表的概念。请考虑下面这个新的BlankDisc:

package soundsystem.collections;

import java.util.List;

import soundsystem.CompactDisc;

/**
 * 空白 cd
 *
 * @author imenger
 * @date 2021/2/25 6:33 下午
 */
public class BlankDisc implements CompactDisc {

    private String title;
    private String artist;
    private List<String> tracks;

    public BlankDisc(String title, String artist, List<String> tracks) {
        this.title = title;
        this.artist = artist;
        this.tracks = tracks;
    }

    @Override
    public void play() {
        System.out.println("Playing " + title + " by " + artist);
        for (String track : tracks) {
            System.out.println("-Track: " + track);
        }
    }

}

此时的 tracks是一个列表,如果直接调用 play 方法,会报NullPointerException。所以需要先给 tracks 赋值;

使用<list>标签来声明 list

<?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 id="compactDisc" class="soundsystem.collections.BlankDisc">
    <constructor-arg value="Sgt. Pepper's Lonely Hearts Club Band" />
    <constructor-arg value="The Beatles" />
    <constructor-arg>
      <list>
        <value>Sgt. Pepper's Lonely Hearts Club Band</value>
        <value>With a Little Help from My Friends</value>
        <value>Lucy in the Sky with Diamonds</value>
        <value>Getting Better</value>
        <value>Fixing a Hole</value>
        <value>She's Leaving Home</value>
        <value>Being for the Benefit of Mr. Kite!</value>
        <value>Within You Without You</value>
        <value>When I'm Sixty-Four</value>
        <value>Lovely Rita</value>
        <value>Good Morning Good Morning</value>
        <value>Sgt. Pepper's Lonely Hearts Club Band (Reprise)</value>
        <value>A Day in the Life</value>
      </list>
    </constructor-arg>
  </bean>
        
  <bean id="cdPlayer" class="soundsystem.CDPlayer">
    <constructor-arg ref="compactDisc" />
  </bean>

</beans>

使用<ref>元素替代<value>

按照同样的方式使用<set>元素

<set>和<list>元素的区别不大,其中最重要的不同在于当Spring创建要装配的集合时,所创建的是java.util.Set还 是java.util.List。如果是Set的话,所有重复的值都会被忽略掉,存放顺序也不会得以保证。不过无论在哪种情况 下,<set>或<list>都可以用来装配List、Set甚至数组。

设置属性

接下来,我们就看一下如何使用Spring XML实现属性注入。假设属性注入的CDPlayer如下所示:

package soundsystem.properties;
import org.springframework.beans.factory.annotation.Autowired;

import soundsystem.CompactDisc;
import soundsystem.MediaPlayer;

public class CDPlayer implements MediaPlayer {
  private CompactDisc compactDisc;

  @Autowired
  public void setCompactDisc(CompactDisc compactDisc) {
    this.compactDisc = compactDisc;
  }

  @Override
  public void play() {
    compactDisc.play();
  }

}

对强依赖使用构造器注入,对可选性的依赖使用属性注入。

目前而言,CDPlayer 是没有强依赖的,所以可以采用属性注入

<bean id="cdPlayer" class="soundsystem.properties.CDPlayer">
  <property name="compactDisc" ref="compactDisc" />
</bean>

在本例中,它引用了ID 为compactDisc的bean(通过ref属性),并将其注入到compactDisc属性中(通过setCompactDisc()方法)。

同样可以支持p-命名空间

比如:

<bean id="cdPlayer" class="soundsystem.properties.CDPlayer"
      p:compactDisc-ref="compactDisc" />

p-命名空间中属性所遵循的命名约定与c-命名空间中的属性类似。图2.2阐述了p-命名空间属性是如何组成的。

首先,属性的名字使用了“p:”前缀,表明我们所设置的是一个属性。接下来就是要注入的属性名。最后,属性的名称以“-ref”结尾,这会提示Spring要进行装配的是引用。

将字面量注入到属性中

与前面那个相比,本次通过属性注入进行配置。代码如下:

package soundsystem.properties;

import java.util.List;

import soundsystem.CompactDisc;

public class BlankDisc implements CompactDisc {

  private String title;
  private String artist;
  private List<String> tracks;

  public void setTitle(String title) {
    this.title = title;
  }

  public void setArtist(String artist) {
    this.artist = artist;
  }

  public void setTracks(List<String> tracks) {
    this.tracks = tracks;
  }

  @Override
  public void play() {
    System.out.println("Playing " + title + " by " + artist);
    for (String track : tracks) {
      System.out.println("-Track: " + track);
    }
  }

}

然后在给他们赋值:

可以借 助<property>元素的value属性实现该功能

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xmlns:p="http://www.springframework.org/schema/p"
  xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

  <bean id="compactDisc"
        class="soundsystem.properties.BlankDisc"
        p:title="Sgt. Pepper's Lonely Hearts Club Band"
        p:artist="The Beatles">
    <property name="tracks">
      <list>
        <value>Sgt. Pepper's Lonely Hearts Club Band</value>
        <value>With a Little Help from My Friends</value>
        <value>Lucy in the Sky with Diamonds</value>
        <value>Getting Better</value>
        <value>Fixing a Hole</value>
        <value>She's Leaving Home</value>
        <value>Being for the Benefit of Mr. Kite!</value>
        <value>Within You Without You</value>
        <value>When I'm Sixty-Four</value>
        <value>Lovely Rita</value>
        <value>Good Morning Good Morning</value>
        <value>Sgt. Pepper's Lonely Hearts Club Band (Reprise)</value>
        <value>A Day in the Life</value>
      </list>
    </property>
  </bean>
        
  <bean id="cdPlayer"
        class="soundsystem.properties.CDPlayer"
        p:compactDisc-ref="compactDisc" />

</beans>

也可以使用Spring util-命名空间中的一些功能来简化BlankDiscbean:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xmlns:p="http://www.springframework.org/schema/p"
  xmlns:util="http://www.springframework.org/schema/util"
  xsi:schemaLocation="http://www.springframework.org/schema/beans 
    http://www.springframework.org/schema/beans/spring-beans.xsd
    http://www.springframework.org/schema/util 
    http://www.springframework.org/schema/util/spring-util.xsd">

  <bean id="compactDisc"
        class="soundsystem.properties.BlankDisc"
        p:title="Sgt. Pepper's Lonely Hearts Club Band"
        p:artist="The Beatles"
        p:tracks-ref="trackList" />

  <util:list id="trackList">  
    <value>Sgt. Pepper's Lonely Hearts Club Band</value>
    <value>With a Little Help from My Friends</value>
    <value>Lucy in the Sky with Diamonds</value>
    <value>Getting Better</value>
    <value>Fixing a Hole</value>
    <value>She's Leaving Home</value>
    <value>Being for the Benefit of Mr. Kite!</value>
    <value>Within You Without You</value>
    <value>When I'm Sixty-Four</value>
    <value>Lovely Rita</value>
    <value>Good Morning Good Morning</value>
    <value>Sgt. Pepper's Lonely Hearts Club Band (Reprise)</value>
    <value>A Day in the Life</value>
  </util:list>

  <bean id="cdPlayer"
        class="soundsystem.properties.CDPlayer"
        p:compactDisc-ref="compactDisc" />

</beans>

spring 帮我们 :list 创建一个列表,然后 我们将这个 list 对象注入给 tracks 里。

      p:tracks-ref="trackList" />

<util:list id="trackList">  

<util:list>只是util-命名空间中的多个元素之一。表2.1列出了util-命名空间提供的所有元素。

导入和混合配置

在典型的Spring应用中,我们可能会同时使用自动化和显式配置。 

在JavaConfig中引用XML配置

定义一个新的CDConfig 类:

@Configuration
public class CDConfig {
  @Bean
  public CompactDisc compactDisc() {
    return new SgtPeppers();
  }
}

compactDisc()方法已经从CDPlayerConfig中移除掉了,我们需要有一种方式将这两个类组合在一起。一种方法就是 在CDPlayerConfig中使用@Import注解导入CDConfig:

@Configuration
@Import((CDConfig.class))
public class CDPlayerConfig {
  
  @Bean
  public CDPlayer cdPlayer(CompactDisc compactDisc) {
    return new CDPlayer(compactDisc);
  }

}

或者采用一个更好的办法,也就是不在CDPlayerConfig中使用@Import,而是创建一个更高级别的SoundSystemConfig,在这个类中 使用@Import将两个配置类组合在一起:

@Configuration
@Import({CDPlayerConfig.class,CDConfig.class})
public class SoundSystemConfig {

}

不管采用哪种方式,我们都将CDPlayer的配置与BlankDisc的配置分开了。

现在,我们假设(基于某些原因)希望通过XML来配 置BlankDisc,如下所示:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xmlns:c="http://www.springframework.org/schema/c"
  xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

  <bean id="compactDisc"
        class="soundsystem.BlankDisc"
        c:_0="Sgt. Pepper's Lonely Hearts Club Band"
        c:_1="The Beatles">
    <constructor-arg>
      <list>
        <value>Sgt. Pepper's Lonely Hearts Club Band</value>
        <value>With a Little Help from My Friends</value>
        <value>Lucy in the Sky with Diamonds</value>
        <value>Getting Better</value>
        <value>Fixing a Hole</value>
        <!-- ...other tracks omitted for brevity... -->
      </list>
    </constructor-arg>
  </bean>

</beans>

让Spring同时加载它和其他基于Java的配置,

假设BlankDisc定义在名为cd-config.xml的文件中,该文件位于根类路径下,那么可以修

改SoundSystemConfig,让它使用@ImportResource注解,如下所示:

@Configuration
@Import(CDPlayerConfig.class)
@ImportResource("classpath:cd-config.xml")
public class SoundSystemConfig {

}

两个bean——配置在JavaConfig中的CDPlayer以及配置在XML中BlankDisc——都会被加载到Spring容器之中。

在XML配置中引用JavaConfig

假设希望将BlankDisc bean拆分到自己的配置文件中,该文件名为cdplayer-config.xml,这与我们之前使用@ImportResource是一样的。

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xmlns:c="http://www.springframework.org/schema/c"
  xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

  <bean class="soundsystem.CDConfig" />

  <bean id="cdPlayer"
        class="soundsystem.CDPlayer"
        c:cd-ref="compactDisc" />

</beans>

小结

Spring框架的核心是Spring容器。容器负责管理应用中组件的生命周期,它会创建这些组件并保证它们的依赖能够得到满足,这样的话,组件

才能完成预定的任务。 在本章中,我们看到了在Spring中装配bean的三种主要方式:自动化配置、基于Java的显式配置以及基于XML的显式配置。不管你采用什么方式,这些技术都描述了Spring应用中的组件以及这些组件之间的关系。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值