《Spring实战》第四版读书笔记 第二章 装配Bean
博客专区 > 一万 的博客 > 博客详情
《Spring实战》第四版读书笔记 第二章 装配Bean
一万 发表于3个月前
《Spring实战》第四版读书笔记 第二章 装配Bean
  • 发表于 3个月前
  • 阅读 6
  • 收藏 0
  • 点赞 0
  • 评论 0

腾讯云 技术升级10大核心产品年终让利>>>   

在Spring中,对象无需自己查找或创建与其所关联的其他对象。相反,容器负责把需要相互协作的对象引用赋予各个对象。

创建应用对象之间协作关系的行为通常称为装配(wiring),这也是依赖注入的本质。

2.1 Spring配置的可选方案

Spring提供了三种主要的装配机制:

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

作者建议尽可能的使用自动装配的机制。显式配置越少越好,当必须要显式配置bean的时候(比如,有些源码不是由你来维护的,而当你需要为这些代码配置bean的时候),推荐使用类型安全并且比XML更加强大的JavaConfig。最后,只有当你想要使用便利的XML命名空间,并且在JavaConfig中没有同样的实现是才应该使用XML。

2.2 自动化装配bean

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

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

2.2.1 创建可被发现的bean

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

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

@Configuation
@ComponentScan
public class CDPlayerConfig {
}

如果没有其他配置,@ComponentScan默认会扫描与配置类相同的包。

如果想使用XML来启用组件扫描,可以使用Spring context命名空间的<context:component-scan>元素。

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

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

测试组件扫描代码:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes=CDPlayerConfig.class)
public class CDPlayerText {
    @Autowired
    private CompactDisc cd;
    
    @Test
    public void cdShouldNotBeNull() {
        assertNotNull(cd)
    }
}

CDPlayerTest使用了Spring的SpringJUnit4ClassRunner,以便在测试开始的时候自动创建Spring的应用上下文。注解@ContextConfiguration会告诉它需要在CDPlayerConfig中加载配置。

2.2.2 为组件扫描的bean命名

在组件扫描中如果没有明确的设置ID,Spring会根据类名为其指定一个ID。这个bean所给定的ID是首字母变为小写的类名。

如果想为这个bean设置不同的ID,需要将其作为值传递给@Component注解。

@Component("lonelyHeartsClub")
public class SgtPeppers implements CompactDisc {
}

另外一种bean命名方式使用Java依赖注入规范中提供的@Named注解:

@Named("lonelyHeartsClub")
public class SgtPeppers implements CompactDisc {
}

Spring支持将@Named作为@Component注解的替代方案。两者之间由一些细微的差异,但在大多数场景中可以互换。

本书的作者更喜欢@Component。

2.2.3 设置组件扫描的基础包

如果没有为@ComponentScan设置属性,按照默认规则,它会以配置类所在的包作为基础包来扫描逐渐。

如果想扫描不同的包,在@ComponentScan的value属性中指定包名即可。

@Configuraion
@ComponentScan("soundsystem")
public class CDPlayerConfig{
}

如果想更加清晰的表明所设置的是基础包,可以通过basePackages属性进行配置:

@Configuration
@ComponentScan(basePackages="soundsystem")
public class CDPlayerConfig{}

basePackages属性可以设置多个包,赋值一个数组即可:

@Configuration
@ComponentScan(basePackages={"soundsystem", "video"})
public class CDPlayerConfig { }

除了将包设置为简单的String类型外,@ComponentScan哈提供了另外一种方法,将其指定为包中所包含的类或接口:

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

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

可以在构造器、setter方法、任何方法上使用@Autowired注解,Spring会尝试满足方法参数上所声明的依赖。假如有且只有一个bean匹配依赖需求,那么这个bean将会被装配进来。

如果没有匹配的bean,那么在应用上下文创建的时候会抛出异常。可以将@Autowired的required属性设置为false,此时Spring会尝试自动装配,但是如果没有匹配的bean的话该属性将会为null。

如果有多个bean都满足依赖关系,Spring将会抛出异常。

@Autowired是Spring特有的注解。可以使用@Inject注解替代。

2.3 通过Java代码装配Bean

显式的装配方式有两种:Java和XML。

2.3.1 创建配置类

@Configuration注解表明这个类是一个配置类,该类应该包含在Spring应用上下文中如何创建bean的细节。

2.3.2 声明简单bean

要在JavaConfig中声明bean,需要编写一个方法,这个方法会创建所需类型的实例,然后给这个方法添加@Bean注解。

@Bean注解会告诉Spring这个方法将返回一个对象,该对象要注册为Spring应用上下文中的bean。方法体中包含了最终产生bean实例的逻辑。

默认情况下,bean的ID与方法名一致。如果想为其设置一个不同的名字,可以重命名该方法,也可以通过@Bean的name属性指定。

2.3.3 借助JavaConfig实现注入

在JavaConfig中装配bean的最简单方式就是引用创建bean的方法。在方法上添加了@Bean注解,Spring将会拦截所有对它的调用,并确保直接返回该方法所创建的bean,而不是每次都对其进行实际的调用。

通过调用方法引用bean的方式有点令人困惑。还有一种理解起来更简单的方式:

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

cdPlaye()方法请求一个CompactDisc作为参数,当Spring调用cdPlayer()创建CDPlayer bean的时候,它会自动装配一个CompactDisc到配置方法之中。

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

2.4 通过XML装配Bean

2.4.1 创建XML配置规范

在XML配置中,要创建一个XML文件,并且要以<beans>元素为根。

<?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.springframeword.org/schema/beans
            http://www.springframework.org/schema/beans/spring-beans.xsd
            http://www.springframework.org/schema/context">

        <!-- 配置详情 -->
</beans>

2.4.2 声明一个简单的<bean>

<bean>元素类似于JavaConfig中的@Bean注解。

如果没有给定ID,所以这个bean将会根据全限定类名来进行命名。例如“soundsystem.SgtPeppers#0“,其中“#0”是一个计数形式,用来区分相同类型的其他bean。

2.4.3 借助构造器注入初始化bean

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

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

构造器注入bean引用

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

c-命名空间的schema:

xmlns:c="http://www.springframework.org/schema/c"
<bean id="cdPlayer" class="soundsystem.CDPlayer" 
    c:cd-ref="compactDisc" />

属性以c:开头,也就是命名空间的前缀。接下来是要装配的构造器参数名,在此之后是-ref,这是一个命名约定,告诉Spring正在装配的是一个bean应用。

可以使用参数在整个参数列表中的位置来替代参数名:

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

因为在XML中不允许数字作为属性的第一个字符,因此必须要添加一个下划线作为前缀。

如果只有一个参数,不用标示参数:

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

将字面量注入到构造器中

<bean id="compactDisc"
    class="soundsystem.BlankDisc">
    <constructor-arg value="sgt. Pepper" />
</bean>

依然使用<constructor-arg>元素进行注入,但是使用了value属性。

<bean id="compactDisc"
    class="soundsystem.BlankDisc"
    c:_title="sgt. Pepper"/>

使用c-命名空间装配字面量与装配引用的区别在于属性名中去掉了-ref后缀。

装配集合

<constructor-arg>可以将集合装配到构造器参数重,而c-命名空间不能。

可以使用<null/>元素将null传递给构造器。

可以使用<list>元素声明一个列表:

<constructor-arg>
    <list>
        <value>.....</value>
        <value>......</value>
    </list>
</constructor-arg>

<list>元素是<constructor-arg>的子元素,这表明一个包含值的列表将会传递到构造器中。其中<value>元素用来指定列表中的每个元素。

与之类似,可以使用<ref>元素代替<value>,实现bean引用列表的装配。

可以用相同的方式使用<set>元素。<set>和<list>元素的区别不大,无论在哪种情况下,<set>或<list>都可以用来装配List、Set甚至是数组。

2.4.4 设置属性

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

Spring提供了p-命名空间作为<property>元素的替代方案。p-命名空间的schema:

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

util-命名空间所提供的功能之一是<util:list>元素,它会创建一个列表的bean。

xmlns:util="http://www.springframework.org/schema/util"
<util:list id="trackList">
    <value>......</value>
    <value>.....</value>
</util:list>

下表展示了Spring util-命名空间中的元素

元素描述
<util:constant>引用某个类型的public static域,并将其暴露为bean
<util:list>创建一个java.util.List类型的bean,其中包含值或引用
<util:map>创建一个java.util.Map类型的bean,其中包含值或引用
<util:properties>创建一个java.util.Propertie类型的bean
<util:property-path>引用一个bean的属性(或内嵌属性),并将其暴露为bean
<util:set>创建一个java.util.Set类型的bean,其中包含值或引用

2.5 导入和混合配置

2.5.1 在JavaConfig中引用XML配置

使用@Import注解引用其他JavaConfig配置,使用@ImportResource注解引入XML配置。

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

2.5.2 在XML配置中引用JavaConfig

在XML中可以使用<import>元素来引用其他XML配置。

将JavaConfig作为bean使用<bean>元素导入XML配置文件。

共有 人打赏支持
粉丝 28
博文 102
码字总数 173386
×
一万
如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!
* 金额(元)
¥1 ¥5 ¥10 ¥20 其他金额
打赏人
留言
* 支付类型
微信扫码支付
打赏金额:
已支付成功
打赏金额: