Spring基础知识

Spring之旅

Spring是一个开源框架,最早由Rod Johnson创建。是为了解决企业级开发的复杂性而创建的,但不仅仅局限与服务器端的开发,任何Java应用都能在简单性、可测试性和松耦合性方面从Spring获益。

为了降低Java开发的复杂性,Spring采用以下4种关键策略:

  • 基于POJO的轻量级和最小侵入性编程;
  • 通过依赖注入和面向接口实现松耦合;
  • 基于切面和惯例进行声明式编程;
  • 通过切面和模板减少样板式代码。

注:POJO(Plain Ordinary Java Object) , 简单的Java对象,实际就是普通的JavaBeans。是为了避免和EJB混淆所创造的简称。

Spring成功的关键在于依赖注入和AOP,它们也是Spring框架的核心部分。

DI是组装应用对象的一种方式,借助这种方式对象无需知道依赖来自何处或者依赖的实现方式。对象在运行期赋予它们所依赖的对象,依赖对象通常会通过接口了解所注入的对象,这样的话就能确保低耦合。

AOP可以帮助应用将散落在各处的逻辑汇集于一处—切面。当Spring装配bean时,这些切面能够在运行期编织起来,这样就能非常有效地赋予bean新的行为。

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

装配Bean

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

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

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

尽可能使用自动装配机制,显式配置越少越少。当不得不使用显式配置时,推荐使用类型安全且比XML更加强大的JavaConfig,但如果JavaConfig中没有实现时,可以使用XML。

自动化装配bean

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

  • 组件扫描:Spring会自动应用上下文所创建的bean。
  • 自动装配:Spring自动满足bean之间的依赖。

创建可被发现的bean

@Component注解表明某个类会作为组件类,告知Spring要为这个类创建bean。

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

可以用@ComponentScan注解在Spring中启用组件扫描。如果没有其它配置的话,会默认扫描该类所在的包及其这个包的子包,查找带有@Component 注解的类。

也可以通过XML来启用组件扫描:

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

为组件扫描的 bean 命名

Spring 应用上下文中所有的bean都会定一个ID。若没有明确的为某个bean设置ID,Spring会根据类名为其指定一个ID。具体来讲,是将类名的第一个字母变为小写。

也可以自定义ID,将ID作为值传递给@Component 注解。

如:

@Component("lonelyHeartsClub")

当然还可以使用Java依赖注入规范中提供的@Named 注解来为bean设置ID。

Spring支持@Named 作为 @Component 注解的替代方案,两者有些略微差异,但是在大多数场景中是可以相互替换的。

设置组件扫描基础包

前面提到过如果没有为@ComponentScan 设置任何属性,它会按照默认规则,会以配置类所在的包作为基础包来扫描组件。

可以通过basePackages来指定基础包,并可以用一个数组来设置多个基础包。

@ComponentScan(basePackages="soundsystem")

@ComponentScan(basePackages={"soundsystem","video"})

除了将包设置为简单的String类型外,@ComponentScan还可以将其指定为包中所包含的类或接口。

@ComponentScan(basePackageClasses="Player.class")

可以考虑创建一个用来进行扫描的空标记接口(marker interface),通过标记接口的的方式,依然能够保持对重构友好的接口引用,但是可以避免引用其它任何实际的应用程序代码。

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

自动装配就是让Spring自动满足bean依赖的一种方法,在满足依赖的过程中,会在Spring应用上下文中寻找匹配某个bean需求的其他bean。

为了声明要进行自动装配,我们可以借助Spring的@Autowired注解。

不管是构造器,setter方法还是其他的方法,Spring都会尝试满足方法参数上所声明的依赖。假如有且只有一个bean匹配依赖需求的话,那么这个bean会被装配进来。

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

将required 属性设置为false时,Spring会尝试执行自动装配,但如果没有匹配的bean的话,Spring会让这个bean处于未装配状态。

如果有多个bean都能满足依赖关系,Spring将会抛出一个异常,表明不确定要选择哪个bean进行自动装配。

@Autowired 是 Spring的特定的注解,可以替换为@Inject(源于Java依赖注入规范),两者有细微的却别,但在大部分的情况下,都可以替换。

通过Java代码装配bean

有时候自动化装配方案行不通,比如将第三方库中的组件装配到你的应用中,只能采用显式装配的方式,可选两种方案:Java和XML。

JavaConfig是更好的方案,因为它更强大、类型安全并且重构友好。它是Java代码,就像应用程序中的其他Java代码一样。但是与其他的Java代码又有区别,它与应用程序中的的业务逻辑和领域代码不同,它是配置代码;这意味着它不应该包含任何业务逻辑,JavaConfig也不应该侵入到哑无逻辑代码中。通常把JavaConfig放到单独的包中,使它与其他的应用程序逻辑分离开。

创建配置类

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

声明简单的bean

在JavaConfig中声明bean,要编写一个方法,这个方法会创建所需类型的实例,然后给这个方法添加@Bean注解,@Bean注解告诉Spring这个方法返回一个对象,该对象要注册为Spring应用上下文的bean。默认情况下,bean的ID与带有@Bean注解的命名方法是一样的,当然可以用name属性来指定一个不同的名字。

@Bean(name="lonelyHeartsClubBand")
public CompactDisc sgtPeppers() {
    return new SgtPeppers();
}

方法体返回了一个新的实例,这里使用Java进行描述,可以发挥Java提供的所有功能。

借助 JavaConfig 实现注入

1、最简单的方法

在JavaConfig中装配bean的最简单的方式就是引用创建bean的方法。

没有使用默认的构造器来创建实例,而是调用了需要传入对象的构造器来创建该实例。

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

sgtPeppers()方法添加了@Bean注解,Spring会拦截所有对它的调用,并确保直接返回该方法所创建的bean,而不是每次都其进行实际的调用。

在软件领域,完全可以将同一个SgtPeppers实例注入到任意数量的其它bean中。

2、一种更易理解的方法
@Bean
public CDPlayer(CompactDisc compactDisc){
    return new CDPlayer(compactDisc);
}

cdPlayer()方法请求一个CompactDisc作为参数,当Spring调用cdPlayer()创建CDPlayer bean时,它会自动装配一个CompactDisc到配置的方法中。这样,也可以将CompactDisc注入到CDPlayer构造器中,而且不用明确引用CompactDisc的 @Bean方法。

通过这种方式引用其他bean通常是最佳的选择,因为它不会要求将CompactDisc声明到同一个配置中,甚至它可以通过组件扫描自动发现或者通过XML进行配置。

也可以采用其他风格的DI配置。

比如通过setter方法来注入;

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

带有@Bean注解的方法可以采用任何必要的Java功能来产生bean实例。

通过XML装配bean

创建 XML 配置规范

在使用XML为Spring装配bean之前,要创建一个新的配置规范,即创建一个XML文件,并且要以<beans>元素为根。在使用XML时,要在配置文件顶部声明多个XML模式(XSD)文件,这些文件定义了配置Spring的XML元素。可借助Spring Tool Suite这个工具来创建和管理配置文件,并可以检查配置的合法性。

用来装配bean的最基本的XML元素包含在spring-beans模式中。

声明一个简单的

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

<bean class="soundsystem.SgtPeppers" />

创建这个bean类通过class属性来指定,并且要使用全限定的类名。

没有明确给定ID,这个bean将会“soundsystem.SgtPeppers#0”,其中,“#0”是一个计数的形式,用来区分相同类型的其他 bean,可以借助id属性,为每个bean设置名字。

借助构造器注入初始化bean

构造器注入bean引用
<bean id="cdPlayer" class="soundsystem.CDPlayer">
    <constructor-arg ref="compactDisc">
</bean>

告诉Spring要将一个ID为compactDisc的bean引用传递到CDPlayer的构造器中。

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

c: c-命名空间的前缀,接下来就是要装配的构造器的参数名。

-ref:命名的约定,它会告诉Spring,正在装配的是一个bean的引用,这个bean的名字是compactDisc,而不是字面量“compactDisc”。

也可以使用参数在整个参数列表中的位置信息,即参数索引。

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

如果只有一个构造器参数,根本不用去标示参数。直接用_ref即可。

将字面量注入到构造器中
<bean id="CDPlayer" class="soundsystem.CDPlayer">
    <constructor-arg value="Sgt. Pepper's Lonely Hearts Club Band" />
    <constructor-arg value="The Beatles" />
</bean>

使用value属性表明给定的值要以字面量的形式注入到构造器中。

也可以使用c-命名空间来表示

<bean id="CDPlayer" class="soundsystem.CDPlayer">
    <c:_title="Sgt. Pepper's Lonely Hearts Club Band" />
    <c:_artist="The Beatles" />
</bean>

或者用参数索引装配相同的字面量值

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

XML不允许某个元素的多个属性具有相同的名字。只有一个构造器参数,就可以简单地用下划线表示。

<bean id="CDPlayer" class="soundsystem.CDPlayer">
    <c:_="Sgt. Pepper's Lonely Hearts Club Band" />
</bean>
装配集合

可以用<list>元素处理列表:

<bean id="CDPlayer" class="soundsystem.CDPlayer">
    <constructor-arg value="Sgt. Pepper's Lonely Hearts Club Band" />
    <constructor-arg value="The Beatles" />
    <constructor-arg>
        <list>
            <value>A</value>
            <value>B</value>
            <value>C</value>
            <value>D</value>
            <value>E</value>
        </list>
    </constructor-arg>
</bean>

也可以用<ref>元素来代替<value>,实现bean引用列表的装配。

同理,可以按照同样的方式使用<set>元素,当是set时,所有重复的元素都会被忽略掉,存放顺序也不会得到保证。

无论哪种情况下,<set>或<list>都可以用来装配List、Set甚至数组。

设置属性

一般来说,对强依赖使用构造器注入,而对可选性依赖使用属性注入。

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

<property>在这里,它引用了ID为compactDisc的bean,并通过setCompactDisc()方法将其注入到compactDisc属性中。

Spring提供了p-命名空间来代替<property>。为了启用p-命名空间,要在XML中进行声明。

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

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

将字面量注入到属性中

借助元素的value来装配属性:

<bean id="CDPlayer" class="soundsystem.CDPlayer">
    <property name = "title" value="Sgt. Pepper's Lonely Hearts Club Band" />
    <property name = "artist" value="The Beatles" />
    <property name="tracks">
        <list>
            <value>A</value>
            <value>B</value>
            <value>C</value>
            <value>D</value>
            <value>E</value>
        </list>
    </property>
</bean>

还可以使用p-命名空间的属性来完成该功能,与c-命名空间一样,装配bean引用与装配字面量的唯一区别在于是否带有“-ref”后缀,如果没有,所装配的就是字面量。

我们不能用p-命名空间来装配集合,没有便利的方式使用p-命名空间来指定一个值(或bean引用)的列表,可以使用Spring的util-命名空间的一些功能来简化。

要使用必须先声明util-命名空间及其模式。

借助util-命名空间中<util:list>元素建立一个新的bean来实现上述功能

<util:list id="trackList">
    <value>A</value>
    <value>B</value>
    <value>C</value>
    <value>D</value>
    <value>E</value>
</util:list>

现在可以将上面的bean注入到BlankDisc的tracks属性中

<bean id="compactDisc"
    class="soundsystem.BlankDisc"
    p:title = "Sgt. Pepper's Lonely Hearts Club Band"
    p:artist = "The Beatles"
    p:tracks-ref="trackList" />
元素描述
<util:constant>引用某个类型的public static域,并将其暴露为bean
<util:list>创建一个java.util.List类型的bean,其中包含值和引用
<util:map>创建一个java.util.Map类型的bean,其中包含值和引用
<util:set>创建一个java.util.Set类型的bean,其中包含值和引用
<util:properties>创建一个java.util.Properties类型的bean
<util:property-path>引用一个bean的属性(或内嵌属性),其中包含值和引用

导入和混合配置

在Spring中,所有类型的配置方案都不是互斥的。所以可以将混合在一起使用。

在JavaConfig中引用XML配置

如果一个Config需要用到另一个Config,我们需要将这两个类组合起来,一种方式是使用@Import注解导入;另一个方式是创建一个更高级别 的Config,在这个类中使用@Import将两个配置组合在一起。

现在我们想通过XML来配置BlankDisc,那么该如何让Spring同时加载它和其他基于Java的配置呢?

可以用ImportResource注解,我们可以这样来配置

...

@Configuration
@Import(CDPlayerConfig.class)
@ImportResource("classpath:cd-config.xml")
public class SoundSystemConfig{
}
在XML配置中引用JavaConfig

在XML中,可以用<import>元素来拆分XML配置。即可以在XML配置文件中使用<import>元素来引用该文件(xml文件)。

但是我们想引入一个JavaConfig类呢?事实上并没有XML元素可以导入JavaConfig元素。但是为了将JavaConfig类导入到XML配置中,我们可以这样声明bean。

<beans ...>
    <bean class="soundsystem.CDConfig" />

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

</beans>

采用这种方式,两种配置——其中一个用XML描述,另一个使用JavaConfig描述被组合了起来。

类似的,可以创建一个更高层次的配置文件,只负责将两个或者更多个配置组合起来。

注意

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值