Spring - 2. Bean 注入

Bean 注入

Spring4 中有如下注入方式

  1. 显式在 XML 文件中配置
  2. 显式在 Java 代码中配置 (比 XML 更加安全)
  3. 隐式地通过 Bean 发现和自动装配

推荐的方式: 

  1. 尽量依赖 自动装配
  2. 当需要显式配置的时候, 优先使用 JavaConfig
  3. 若1和2不能满足, 使用 XML.

自动装配

自动装配主要有两个角度:

  1. Component scanning, Spring 扫描并 自动发现 在容器中需要创建的 bean.
  2. Autowiring, Spring 自动填充 bean 的依赖

两者协同工作.

如何自动装配

  1. 使用如下注解, 标识这些类可以被 spring 发现并创建

@Component @Configuration @Service 的实例

  1. 打开自动扫面开关, 通过如下开关:

若使用注解, 使用:

@ComponentScan, 只能添加在被 @Configuration 标注的类上(当是 @Configuration 也可以独自使用, 比如 Java Config 方式)

默认 spring 会扫描与 configuration 类同级 package (包括 subpackage)中的 component/configuration/service.

若使用 xml, 则采用:

<context:component-scan base-package="packageName"/>

如何写 spring 测试类

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes=CDPlayerConfig.class)
public class CDPlayerTest {
    @Rule
    public final StandardOutputStreamLog log = new StandardOutputStreamLog();

    @Autowired
    private CompactDisc cd;
    @Test
    public void cdShouldNotBeNull() {
        assertNotNull(cd);
    }
}

@Rule, 可以获取 console 上的内容@RunWith(SpringJUnit4ClassRunner.class), 标明一个 applicationContext 会在测试开始的时候被创建@ContextConfiguration(classes=CDPlayerConfig.class), 标明其 bean 配置信息来自 CDPlayerConfig

Bean 的命名

  1. 通过 Spring 注解 (推荐)

@Component("abc")

  1. 通过 JSR-330 注解

@Named("abc")

配置 component 扫描范围

@ComponentScan("basePackageName")

或多个扫描路径

@ComponentScan(basePackages={"soundSystem", "video"}): 会扫描soundsystem 和 video 这两个包, 但是这种方式用了 string 类型不安全.

@ComponentScan(basePackageClasses={CDPlayer.class, DVDPlayer.class}): 会扫描 CDPlayer.class 和 DVDPlayer.class 这两个类所在的包, 这两个类可以没有任何标注.

自动注入依赖

Spring 注解 @Autowired

@Autowired 支持三种注入方式:

  1. 构造函数

    @Autowired
    public CDPlayer(CompactDisc cd) {
        this.cd = cd;
    }
  2. setter 方法

    @Autowired
    public void setCompactDisc(CompactDisc cd) {
        this.cd = cd;
    }
  3. 普通方法

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

若 @Autowire 没有找到合适的 Bean 来注入, 会抛出异常. 为了避免异常, 可以在 将 @Autowire 的 required 属性设置为 false.

使用 JSR-330 注解 @Inject

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

使用 Java Config 配置 Bean

Step 1: 创建 Java Config 类

只需要类名前加上 @Configuration

@Configuration
public class CDPlayerConfig {

}

若 @Configuration 和 @ComponentScan 连用, 则是 自动装配. 若不使用自动装配, 那么, 需要将 自动装配中的 Component/Service 这些 bean 手动声明出来.

Step 2: 声明可以注入的 bean

@Bean 表明这个方法可以提供一个 bean 的实例, 并注册到 application context 中.

  1. 使用默认名字(方法名), sgtPeppers. 

    @Bean
    public CompactDisc sgtPeppers() {
        return new SgtPeppers();
    }
  2. 可以指定名字.

    @Bean(name="lonelyHeartsClubBand")
    public CompactDisc sgtPeppers() {
        return new SgtPeppers();
    }
  3. 条件注入

    @Bean
    public CompactDisc randomBeatlesCD() {
        int choice = (int) Math.floor(Math.random() * 4);
        if (choice == 0) {
            return new SgtPeppers();
        } else if (choice == 1) {
            return new WhiteAlbum();
        } else if (choice == 2) {
            return new HardDaysNight();
        } else {
            return new Revolver();
        }
    }

Step 3: 注入 Bean

  1. Bean 的注入默认是单例的. Spring 会拦截被调用的提供 bean 的方法, 保证其只被调用一次. 所以, 容器中的 bean 都是单例的. 

    @Bean
    public CDPlayer cdPlayer() {
        return new CDPlayer(sgtPeppers());
    }
    @Bean
    public CDPlayer anotherCDPlayer() {
        return new CDPlayer(sgtPeppers());
    }

实际注入的是同一个 sgtPeppers.

  1. 当发生跨 Config 文件注入的时候, 注意 Bean 的作用域.

下面这种方式, 要求 sgtPeppers() 在同一个 configuration 文件中

    @Bean
    public CDPlayer cdPlayer() {
        return new CDPlayer(sgtPeppers());
    }

而下面这种方式则可以跨 configuraton 文件

    @Bean
    public CDPlayer cdPlayer(CompactDisc compactDisc) {
        return new CDPlayer(compactDisc);
    }

使用 XML 文件配置 Bean

Step 1: 创建 XML 配置文件

最简单的 spring XML 配置文件:

Step 2: 声明可以注入的 bean

创建 Bean

  1. 默认下一句会创建以 "packageName.className#number" 为 ID 的 bean.

    <bean class="soundsystem.SgtPeppers" />
  2. 可以指名 ID

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

用构造函数注入初始化 Bean

  1. 使用 <constructor-arg> 元素

    • 注入引用, 按参数的次序

      <bean id="compactDisc" class="soundsystem.SgtPeppers" />
      <bean id="cdPlayer" class="soundsystem.CDPlayer">
          <constructor-arg ref="compactDisc" />
      </bean>
    • 注入字面值, 按参数的次序

      <bean id="compactDisc" class="soundsystem.BlankDisc">
          <constructor-arg value="Sgt. Pepper's Lonely Hearts Club Band" />
          <constructor-arg value="The Beatles" />
      </bean>
    • list 的注入, 次序有关

      <bean id="compactDisc" class="soundsystem.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>
                  <!-- ...other tracks omitted for brevity... -->
              </list>
          </constructor-arg>
      </bean>
      
      <bean id="beatlesDiscography class="soundsystem.Discography">
          <constructor-arg value="The Beatles" />
          <constructor-arg>
              <list>
                  <ref bean="sgtPeppers" />
                  <ref bean="whiteAlbum" />
                  <ref bean="hardDaysNight" />
                  <ref bean="revolver" />
                  ...
              </list>
          </constructor-arg>
      </bean>
    • Set 的注入, 次序无关, 并排重

      <bean id="compactDisc" class="soundsystem.BlankDisc">
          <constructor-arg value="Sgt. Pepper's Lonely Hearts Club Band" />
          <constructor-arg value="The Beatles" />
          <constructor-arg>
              <set>
                  <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... -->
              </set>
          </constructor-arg>
      </bean>
  2. 使用 Spring 3.0 中定义的 c-namespace

    • 通过 参数名 注入引用, 格式为 c:参数名-ref="Bean ID", 需要在编译时保存 debug symbols, 以使参数名保留.

      <bean id="compactDisc" class="soundsystem.SgtPeppers" />
      <bean id="cdPlayer" class="soundsystem.CDPlayer" c:cd-ref="compactDisc" />
    • 通过 参数次序 注入引用, 格式为 c:_位置-ref="Bean ID", 前面加 _ 是因为 XML 不允许数字开头

       

    • 通过 参数名字 注入字面值, 格式为 c:参数名="Sgt. Pepper's Lonely Hearts Club Band"

      <bean id="compactDisc" class="soundsystem.BlankDisc"
            c:title="Sgt. Pepper's Lonely Hearts Club Band"
            c:artist="The Beatles" />
    • 通过 参数次序 注入字面值, 格式为 c:_位置="Sgt. Pepper's Lonely Hearts Club Band"

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

用属性注入初始化 Bean

  1. 使用 <constructor-arg> 元素

    • 注入引用

      <bean id="cdPlayer" class="soundsystem.CDPlayer">
          <property name="compactDisc" ref="compactDisc" />
      </bean>
    • 注入字面值

      <bean id="compactDisc" class="soundsystem.BlankDisc">
          <property name="title" value="Sgt. Pepper's Lonely Hearts Club Band" />
          <property name="artist" value="The Beatles" />
      </bean>
    • 注入集合

       <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>
              <!-- ...other tracks omitted for brevity... -->
          </list>
      </property>
  2. 使用 Spring 3.0 中定义的 p-namespace

    • 通过 属性名 注入引用, 格式为 p:属性名-ref="Bean ID".

      <bean id="cdPlayer" class="soundsystem.CDPlayer" p:compactDisc-ref="compactDisc" />
    • 通过 属性名 注入字面值, 格式为 p:属性名="Bean ID".

      <bean id="compactDisc" class="soundsystem.BlankDisc"
          p:title="Sgt. Pepper's Lonely Hearts Club Band"
          p:artist="The Beatles">
      </bean>
    • p-namespace 无法直接初始化集合类型, 但是可以借助 util-namespace 来指定.

      <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>
          <!-- ...other tracks omitted for brevity... -->
      </util:list>
      <bean id="compactDisc"
          class="soundsystem.BlankDisc"
          p:title="Sgt. Pepper's Lonely Hearts Club Band"
          p:artist="The Beatles"
          p:tracks-ref="trackList" />

构造函数注入 or 属性注入 ?

构造函数来注入必须依赖, 属性注入可选依赖.

util-namespace

<util:constant>: 指向静态变量, 并暴露出来<util:list>: 构造 java.util.List <util:map>: 构建 java.util.Map <util:properties>: 构建 java.util.Properties <util:property-path>: 引用 bean 的属性, 并暴露出来 <util:set>: 构建 java.util.Set

配置的导入和混用

Java Config 中引入其他 Java Config

  1. 引入单个:

    @Configuration
    @Import(CDConfig.class)
    public class CDPlayerConfig {
    }
  2. 引入多个:

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

JavaConfig 中引入 XML

  1. 引入一个

    @Configuration
    @Import(CDPlayerConfig.class)
    @ImportResource("classpath:cd-config.xml")
    public class SoundSystemConfig {
    }
  2. 引入多个

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

XML 文件中引用另外一个 XML 配置

<import resource="cdplayer-config.xml" />

XML 文件中引用 Java Config

其实就是创建一个 Bean 啦:

<bean class="soundsystem.CDConfig" />

posted @ 2017-02-02 00:13  still_water  阅读(195)  评论(0编辑  收藏  举报