第02章-装配Bean

1. Spring配置的可选方案

  • 在XML中进行显式配置;
  • 在Java中进行显式配置;
  • 隐式的bean发现机制和自动装配。

2. 自动化装配bean

Spring从两个角度来实现自动化装配:

组件扫描(component scanning):Spring会自动发现应用上下文中所创建的bean。
自动装配(autowiring):Spring自动满足bean之间的依赖。

2.1 创建可被发现的bean

使用了@Component注解。这个简单的注解表明该类会作为组件类,并告知Spring要为这个类创建bean。

组件扫描默认是不启用的。我们还需要显式配置一下Spring,从而命令它去寻找带有@Component注解的类,并为其创建bean。

启用组件扫描

  • 基于Java @ComponentScan注解启用了组件扫描
@Configuration
@ComponentScan(basePackages="soundsystem","video")
public class CDPlayerConfig { 
}

如果没有其他配置的话,@ComponentScan默认会扫描与配置类相同的包。(通过一个空标记接口(remark interface)来这这个工作,是一个很好的实践。)

2.2 设置组件扫描的基础包

上面的例子中,所设置的基础包是以String类型表示的。我认为这是可以的,但这种方法是类型不安全(not type-safe)的。除了将包设置为简单的String类型之外,@ComponentScan还提供了另外一种方法,那就是将其指定为包中所包含的类或接口:

@Configuration
@ComponentScan(basePackageClasses = {CDPlayer.class})
public class CDPlayerConfig { 
}

basePackages属性被替换成了basePackageClasses。同时,我们不是再使用String类型的名称来指定包,为basePackageClasses属性所设置的数组中包含了类。这些类所在的包将会作为组件扫描的基础包。

  • 通过XML启用组件扫描
<context:component-scan base-package="soundsystem" />

2.3 通过为bean添加注解实现自动装配

为了声明要进行自动装配,我们可以借助Spring的@Autowired注解.
@Autowired注解不仅能够用在构造器上,还能用在属性的Setter方法上。

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

如果没有匹配的bean,那么在应用上下文创建的时候,Spring会抛出一个异常。为了避免异常的出现,你可以将@Autowired的required属
性设置为false:

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

3. 通过Java代码装配bean

你想要将第三方库中的组件装配到你的应用中,在这种情况下,是没有办法在它的类上添加@Component和@Autowired注解的,因此就不能使用自动化装配的方案了。 在这种情况下,你必须要采用显式装配的方式。在进行显式配置的时候,有两种可选方案:Java和XML。

JavaConfig是配置代码。这意味着它不应该包含任何业务逻辑,JavaConfig也不应该侵入到业务逻辑代码之中。尽管不是必须的,但通常会将JavaConfig放到单独的包中,使它与其他的应用程序逻辑分离开来,这样对于它的意图就不会产生困惑了。

  • 声明简单的bean
@Bean
public CompactDisc sgtPeppers() {
  return new SgtPeppers();
}
  • 借助JavaConfig实现注入
@Bean
public CDPlayer cdPlayer(CompactDisc compactDisc) {
  return new CDPlayer(compactDisc);
}

通过这种方式引用其他的bean通常是最佳的选择,因为它不会要求将CompactDisc声明到同一个配置类之中。在这里甚至没有要求CompactDisc必须要在JavaConfig中声明,实际上它可以通过组件扫描功能自动发现或者通过XML来进行配置。

  • 使用方法替代构造器的注入
    需要提醒的是,我们在这里使用CDPlayer的构造器实现了DI功能,但是我们完全可以采用其他风格的DI配置。比如说,如果你想通过Setter方法注入CompactDisc的话,那么代码看起来应该是这样的:
@Bean
public CDPlayer cdPlayer(CompactDisc compactDisc) {
  CDPlayer cdPlayer = new CDPlayer(compactDisc);
  cdPlayer.setCompactDisc(compactDisc);
  return cdPlayer;
}

4. 通过XML装配bean

  • 声明一个简单的<bean>
<bean class="soundsystem.SgtPeppers"/>
  • 借助构造器注入初始化bean
<bean id="cdPlayer" class="soundsystem.CDPlayer">
        <constructor-arg ref="compactDisc"/>
</bean>
  • 使用方法替代构造器的注入
<bean id="cdPlayer"  class="soundsystem.CDPlayer">
        <property name="compactDisc" ref="compactDisc"/>
</bean>

<property>元素为属性的Setter方法所提供的功能与<constructor-arg>元素为构造器所提供的功能是一样的。

  • 将字面量注入到属性中
    有Java对象如下:
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;
  }

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

}

可用以下xml将字面值(StringList<String>)注入到属性中:

<bean id="compactDisc"
      class="soundsystem.properties.BlankDisc">
  <property name="title" value="Sgt. Pepper's Lonely Hearts Club Band" />
  <property name="artist" value="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>

5. 导入和混合配置

5.1 在JavaConfig中引用XML配置

  • Java配置
@Configuration
public class CDPlayerConfig {

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

}
  • XML配置
<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>

以上xml配置中使用了c命名空间,这里_0,_1相当与第一个参数和第二个参数。

  • 在Java配置中引入XML配置
    两个bean——配置在JavaConfig中的CDPlayer以及配置在XML中BlankDisc——都会被加载到Spring容器之中。代码如下:
@Configuration
@Import(CDPlayerConfig.class)
@ImportResource("classpath:cd-config.xml")
public class SoundSystemConfig {

}

@Import将两个配置类组合在一起;
@ImportResource可在JavaConfig中引入XML配置;
以上代码是利用一个新的Java配置类,引入了已有的Java配置类以及XML配置文件。当然也可以在已有的Java配置类中直接引入XML配置文件。

5.2 在XML配置中引用JavaConfig

  • Java配置
@Configuration
public class CDConfig {
  @Bean
  public CompactDisc compactDisc() {
    return new SgtPeppers();
  }
}
  • XML配置
<bean id="cdPlayer"
      class="soundsystem.CDPlayer"
      c:cd-ref="compactDisc" />
  • 在XML配置中引入Java配置
<bean class="soundsystem.CDConfig" />

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

以上代码是在已有的XML配置文件中引入Java配置类,当然可以建立一个新的XML引入已有的XML配置文件和已有的Java配置类,如:

<bean class="soundsystem.CDConfig"/>
<import resource="cdplayer-config.xml"/>

XML配置文件应用已有XML配置文件使用<import resource>标签。

注意

不管使用JavaConfig还是使用XML进行装配,我通常都会创建一个根配置(root configuration),也就是这里展现的这样,这个配置会将两个或更多的装配类和/或XML文件组合起来。我也会在根配置中启用组件扫描(通过<context:component-scan>或@ComponentScan)。

Spring 3的一些内容

1、装配wiring,即创建应用对象之间的协作关系的行为,者也是依赖注入的本质。
2、创建Spring配置
从Sring3.0开始,Spring容器提供了两种配置Bean的方式:

XML文件配置方式
基于Java注解的配置方式

3、典型的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:p="http://www.springframework.org/schema/p"
   xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
</beans>

beans命名空间不是唯一的Spring命名空间,Spring核心框架自带了10个命名空间配置,如下:

4、当Spring容器加载Bean时,Spring使用反射来创建Bean。

5、覆盖Spring默认的单例配置:Spring Bean默认都是单例,但有时我们每次都需要获得唯一的Bean实例,比如每个人的门票要唯一:
我们只需要配置Bean的scope属性为prototype即可:
1

6、初始化和销毁Bean
Auditorium(舞台)要保证做的最先和最后两件事情:
开灯,关灯。

需要在Bean中使用init-method和destory-method属性:

当有很多上下文定义的Bean有相同名字的初始化方法和销毁方法时,可以直接在上层beans元素中声明default-init-method和default-destory-method属性,从而避免每一个都要设置一遍的问题。

最小化Spring XML配置——
Bean的自动装配(autowiring);
Bean的自动检测(autodiscovery);

一、自动装配Bean属性
1、 4种类型的自动装配
byName——把与Bean的属性具有相同名字(或ID)的其他Bean自动装配到Bean的对应属性中,名字不匹配则不装配;
byType——把与Bean的属性具有相同类型的其他Bean自动装配到Bean的对应属性中,类型不匹配则不装配;
constructor——把与Bean的构造器入参具有相同类型的其他Bean自动装配到Bean构造器的对应入参中;
autodetect——首先尝试使用constructor自动装配,若失败,再尝试使用byType进行自动装配。

2、byName
原来的装配是这样的:


当bean的id属性和property属性的name一致时,通过配置autowire属性皆可以自动装配instrument了,修改后的文件如下:

3、byType自动装配
byType自动装配的工作方式类似于byName,只不过不再是匹配属性的名字而是检查属性的类型。
若Instrument类型有多个Bean,Spring就会抛出异常,为解决这个为,需要标识首选的Bean或者取消某个Bean的自动装配候选资格:

首选Bean
设置Bean的primary属性为true。但是不幸的是所有的bean的默认primary都是true,因此只能将非首选的Bean的primary属性设置为false:

取消Bean候选资格
排除某些Bean是,可设置这些Bean的autowire-candidate属性为false:

4、constructor自动装配
通过构造器注入来配置Bean,我们可以移除

5、最佳自动装配

首选constructor自动装配,若没有发现与构造器相匹配的Bean时,Spring将尝试使用byType自动装配。

6、默认自动装配
当需要为上下文中的每一个Bean配置相同的上述自动装配autowire属性,可以在根目录

二、使用注解装配
注解方式允许更细粒度的自动装配,可以选择性地标注某一个属性来对其应用自动装配。
Spring容器默认禁止注解装配,最简单的启用方式是使用Spring的context命名空间配置中的

没有bean
当属性是可选的,而bean不存在时,可以使用required属性:
@Autowired(required=false)
多个bean【限定歧义性的依赖】
为帮助@Autowired鉴别哪一个Bean才是我们想要的,可配合使用Spring的@Qualifier注解,该注解可以包含一个字符串作为Bean的标识(标识不一定是id)。
如将一个id为guitar的乐器装配到instrument属性中:

注意,上述的guitar可以在xml中对


2、借助@Inject实现基于标准的自动装配
JCP(Java Community Process)发布Java依赖注入规范——JSR-330,@Inject注解是JSR-330的核心部件。
》note: JDK中并没有JSR-330的实现,需要下载响应的jar依赖包http://mvnrepository.com/artifact/javax.inject/javax.inject

@Inject
和@Autowired一样,@Inject可以自动装配属性、方法和构造器,但是没有required属性,即@Inject注解所标注的依赖关系必须存在,否则会报出异常。
与@Autowired对应的@Qualifier类似,@Inject对应@Name注解。
@Inject本身也有@Qualifier注解,但是不推荐使用,而是推荐自定义限定器注解。

3、在注解中使用表达式
String类型以及基本类型的属性,可以直接通过@Value的方式填入值。但是这相当于硬编码,与直接写在代码中没多大区别,因此不推荐使用,如一首歌名Eruption:

但是@Value可以使用SpEL表达式,获取系统属性,功能强大:

三、自动检测Bean

2、过滤组件扫描
通过为


四、使用Spring基于Java的配置
1、创建基于Java的配置
Spring的Java配置可以不用XML就可以编写大多数的Spring配置,但是还是需要极少量的XML来启动Java配置。就是说,XML总要有的。

Spring在base-package指定的包内查找使用@Configuration注解所标注的所有类。

2、定义一个配置类
使用@Configuration注解的Java类,就等价于XML配置中的

源码

自动配置:https://github.com/myitroad/spring-in-action-4/tree/master/Chapter_02/stereo-autoconfig
Java配置:https://github.com/myitroad/spring-in-action-4/tree/master/Chapter_02/stereo-javaconfig
XML配置:https://github.com/myitroad/spring-in-action-4/tree/master/Chapter_02/stereo-xmlconfig
混合配置:https://github.com/myitroad/spring-in-action-4/tree/master/Chapter_02/stereo-mixedconfig

猜你喜欢

转载自www.cnblogs.com/myitroad/p/9297771.html