什么是装配

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

Spring配置的可选方案

Spring提供了3中主要的装配机制:

  ● 在XML中进行显式配置。

  ● 在Java中进行显式配置。

  ● 隐式的bean发现机制和自动装配。

选择哪种装配方取决于你的喜好,同时还可以选择多种配置风格混搭,即便如此还是建议尽可能的使用自动配置的机制,显式配置越少越好。当必须要显式配置bean时,建议使用类型安全且比XML更加强大的JavaConfig,最后当想使用便利的XML名称空间,且在JavaConfig中没有同样的实现时,才应该使用XML。

自动化装配bean

Spring通过两个角度来实现自动装配,以下两个功能结合在一起就能发挥出强大的威力,能将显式配置降低到最少

  ● 组件扫描(component scanning)Spring会自动发现应用上下文中所创建的bean。

  ● 自动装配(autwiring)Spring自动满足bean之间的依赖。

创建可自动装配的bean

如下例子,创建几个bean代表了音响系统中的组件,来看看Spring的自动装配

使用CD机作为例子,如果不将CD插入(注入)CD播放器事实上是没有用处的,可以说CD播放器依赖于CD。

//一个表示光盘的接口
public interface CompactDisc {
void play();
}

一个代表CD的接口

@Component    //@Component 表明会将此类作为一个组件类,并告知Spring需要为这个类创建bean
public class SgtPeppers implements CompactDisc {
private String title="百里守约";
private String artist="萧敬腾";
@Override
public void play() {
System.out.println("当前播放:"+title+" "+artist);
} }

一个CD接口的实现,其中@Component注解表示该类作为组件类,并告知Spring要为这个类创建bean,但是组件扫描默认是不启用的,还需要显式配置一下Spring,从而启用组件扫描。

@Configuration  //Spring配置类
@ComponentScan //表示启用的组件扫描
public class CDPlayerConfig { }

类CDPlayerConfig通过JAVA代码定义了Spring的装配规则,其使用了@ComponentScan组件扫描,如果没有其他配置,会默认扫描配置类相同包下的其他类,查找是否有@Component注解,如果有Spring就会为其自动创建一个bean。

(如果使用XML配置,可以使用Spring Context下的命名空间<context:component-scan>元素 如:<context:component-scan base-package="soundsystem"/>

import static org.junit.Assert.assertNotNull;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; @RunWith(SpringJUnit4ClassRunner.class) //这个是指定使用的单元测试执行类,这里就指定的是SpringJUnit4ClassRunner.class
@ContextConfiguration(classes=CDPlayerConfig.class) //从CDPlayerConfig配置类加载上下文,因为该配置类包含了@ComponentScan
public class CDPlayerTest { @Autowired //自动装配注解
private CompactDisc cd; @Test
public void cdShouldNotBeanNull(){
assertNotNull(cd); //断言是否为null
}
}

使用JUnit进行测试,执行结果为绿色,通过了测试,只要带有@Component注解的类都会被自动创建为bean,只要加上@ComponentScan就能自动创建无数个bean。

为组件扫描的bean命名

Spring应用上下文会为所有的bean指定一个id,在上面的例子虽然没有指定id,但Spring会根据类名指定一个id,默认是将类的第一个字母小写。

如果需要为bean指定不同的id,则可将期望的id作为值传递给@Component注解,如:@Component("lonelyHearts")

另外还有一种为bean命名的方式,使用Java依赖注入规范中提供的@Named注解,如:@Named("lonelyHearts")

设置组件扫描的基础包

如果没有为@ComponentScan注解设置任何属性,则会按照默认规则将配置类所在的包设为基础包来扫描组件,如果需要扫描不同的包或多个基础包,则可在@ComponentScan的value属性中指明包的名称:@Componentscan("soundsystem")

如果想更加清晰的表明你所设置的是基础包,则可以通过basePackages属性进行设置:@Componentscan(basePackages="soundsystem"),也可以设置多个基础包:@Componentscan(basePackages={"soundsystem","video"})

以上设置的基础包类型是String类型表示的,虽然可以达到目的,但是这种方式是类型不安全的,如果重构代码则可能出错,理想方法是使用注解的basePackageClasses属性,并将其value指定为所包含的类或接口:

@Componentscan(basePackages={CDPlayer.class,DVDPlayer.class})

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

如果应用程序中就像SgtPeppers类一样没有任何依赖,则仅仅需要组件扫描,但是很多程序都是对象相互协作依赖才能完成任务,这样则需要将组件扫描得到的bean和他们的依赖装配在一起,那这就是自动装配。

如接下来完成上述的例子,添加一个CD播放器类

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component; @Component
public class CDPlayer {
private CompactDisc cd; @Autowired //该注解表明Spring创建CDPlayer bean的时候,会通过这个构造器来进行实例化,并传入一个可设置给CompactDisc类型的bean
public CDPlayer(CompactDisc cd){
this.cd=cd;
}
public void play(){
cd.play();
}
}

@AutoWried不仅可以用在构造器上,也能用在属性的Setter方法上,比如CDPlayer有一个setCompactDisc()方法,则可以使用下面的形式进行自动装配

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

验证自动装配

上面已经为CDPlayer构造器添加了@AutoWried注解,Spring将分配一个CompactDisc类型的bean自动注入进来,修改之前的CDPlayerTest方法,使其能够借助CDPlayer bean播放cd。

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; @RunWith(SpringJUnit4ClassRunner.class) //这个是指定使用的单元测试执行类,这里就指定的是SpringJUnit4ClassRunner.class
@ContextConfiguration(classes=CDPlayerConfig.class) //从CDPlayerConfig配置类加载上下文,因为该配置类包含了@ComponentScan
public class CDPlayerTest { @Autowired //自动装配注解
private CompactDisc cd; @Autowired
private CDPlayer player; @Test
public void play(){
player.play();
}
}

输出结果:当前播放:百里守约  萧敬腾

通过Java代码装配bean

尽管很多情况下通过组件扫描和自动装配实现Spring的自动化配置是推荐的方式,但有时候自动化装配行不通,比如需要将第三方库中的组件装配到应用中,这种情况下没有办法添加@Component和@Autowried注解,只能使用显式装配的方式,进行显式配置时,有两种方案:

  ● XML配置文件

  ● JavaConfig

显式配置时JavaConfig是更好的方案,因为其是类型安全的,对重构更友好

通过JavaConfig显式配置

创建配置类

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

@Configuration  //Spring配置类
//@ComponentScan //表示启用的组件扫描 ,本例子将使用显式装配,不需要组件扫描,因此注释掉
public class CDPlayerConfig { }

声明简单的bean

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

@Bean //声明一个bean
public CompactDisc sgtPeppers(){
return new SgtPeppers();
}

@Bean注解会告诉Spring这个方法将返回一个对象,该对象要注册为Spring应用上下文中的bean,方法体包含最终产生bean实例的逻辑。默认情况下bean的id与带有@Bean注解的方法名是一样的。当然也可以使用@Bean(name="name")指定一个不同的名字。

借助JavaConfig实现注入

在CD的例子中,CDPlayer类依赖于CompactDisc,在JavaConfig中装配bean最简单的方式就是引用创建bean的方法,例如下面的方式,但是不推荐使用此方式。

@Bean //声明一个bean
public CDPlayer cdPlayer(){
return new CDPlayer (sgtPeppers()); //引用上面声明的创建bean的方法,sgtPeppers()
}

推荐以下方式,将其依赖CompactDisc通过参数传入,当Spring调用cdPlayer()创建CDPlayerbean的时候,会自动装配一个CompactDisc到配置方法中。通过此方式可以不需要讲CompactDisc声明在同一个配置类中,而是通过组建扫描自动发现或XML来配置,可以将配置分散到多个配置类,如XML、自动扫描和装配Bean中。

@Bean //声明一个bean
public CDPlayer cdPlayer(CompactDisc compactDisc){//请求一个CompactDisc作为参数,创建时Spring会自动装配一个CompactDisc到配置方法之中。
return new CDPlayer (compactDisc);
}

带有@Bean注解的方法可以采用任何必要的JAVA功能产生Bean实例,构造器和Setter方法只是@bean方法的两个简单样例。

通过XML装配bean

XML是比较悠久的Spring配置方法,但是现在一般都用自动装配和JavaConfig方式来代替XML方法,此方式只作为了解。

创建XML配置规范

创建JavaConfig配置类时,需要@Configuration注解,这是JavaConfig的规范,而创建XML配置文件时同样也要有规范,首先,不用说要一个XML文件,并且要以<beans>为根,还需要在头部声明多个XSD文件。

声明一个简单的bean

要在基于XML的Spring配置中声明一个bean,要使用<bean>元素,类似于JavaConfig中的@Bean注解

<bean class="soundSystem.SgtPeppers"/>

此处声明了一个简单的bean,bean的类由class属性指定,需要全限定类名,其id默认根据全限定类名来命名,如果想自己制定id,则可以使用id属性 id="SgtPeppers"

使用XML配置bean的一些特征说明:

  ● 不需要像JavaConfig一样自己负责创建SgtPeppers的实例,当Spring发现这个<bean>元素时,将会调用其默认狗制造函数来创建bean,这将会变的很被动,没有JavaConfig那样强大。

● 在bean生命中,将bean的类型以字符串的形式设置在class属性中,表示其实类型不安全的,不能在编译期进行检查。

借助构造器注入初始化bean

在XML声明DI时,有多重配置方案和风格,具体到构造注入有两种:

  ●  使用<constructor-arg>元素

  ● 使用Spring3.0所引入的c-命名空间

使用<constructor-arg>元素

当Spring遇到这个元素时,会创建一个cdPlayer实例,constructor-arg会告知Spring要将一个id为compactDisc的引用传递到CDPlayer构造器中。

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

使用Spring3.0所引入的c-命名空间

要使用它,必须在XML顶部声明模式,如:

在声明c-命名空间和模式声明后,就可以用它来声明构造函数,如:

其作为一个属性,以下是其组合描述,属性以命名空间的前缀c:开头,接下来就是要装配的构造器参数名称,之后是-ref,会告诉Spring正在装配的是一个bean引用。这个bean的名字是compactDisc(不是字面量compactDisc)

c-命名空间比<constructor-arg>元素简练,并且更易读。

将字面量注入到构造器

目前所做的DI通常都是“类型”的装配,也就是将对象引用装配到依赖于它们的其他对象中,有时候我们仅只需要一个字面量值来配置对象,如:

public class BlankDisc implements CompactDisc{
private String title;
private String artist; pulic BlankDisc(String title,String artist){
this.title=title;
this.artist=artist;
}
public void play(){
System.out.println("正在播放:"+title+" - "+artist);
}
}

上面例子中歌曲名称和艺术家的名字都是硬编码,但是它更加灵活,可以在配置类设置成任意想要的艺术家和歌曲名称。

XML方式

现在可以在XML配置类中将已有的SgtPeppers替换成这个类

<bean  id="compactDisc" class="soundsystem.BlankDisc">
<constructor-arg value="会痛的石头"/>
<constructor-arg value="萧敬腾"/>
</bean>

现在没有使用ref属性引用其他类,而是使用value属性直接赋予字面值,将字面值注入到构造器中。

C-命名空间方式

<bean id="compactDisc"
class="soundsystem.BlankDisc"
c:_0="会痛的石头"
c:_1="萧敬腾"/>

同样没有使用-ref属性,另外如果构造器只有一个参数,还可以这样

<bean id="compactDisc"
class="soundsystem.BlankDisc"
c:_="会痛的石头"/>

在装配bean引用和字面量值时,<constructor-arg>和c-命名空间功能是一样的,但是有一种<constructor-arg>能实现,但是c-命名空间却无法做到,比如装配集合到构造器参数中

装配集合

目前,CompactDisc定义时只包含歌曲名称和艺术家名字,但是如果一张CD有10个磁道,一个磁道包含一首歌曲,那么可以考虑使用集合。

修改BankDisc

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("当前播放:"+title+" - "+artist);
for(String track:tracks){
System.out.println("-磁道:"+track);
}
}
}

现在要声明bean的时候,必须提供一个磁道列表,有多种方案,首先可以使用<list>元素将其声明为一个列表,其实<constructor-arg>的子元素,会将包含值的列表传递到构造其中,value制定每个元素。

<bean  id="compactDisc" class="soundsystem.BlankDisc">
<constructor-arg value="会痛的石头"/>
<constructor-arg value="萧敬腾"/>
<constructor-arg>
<list>
<value>会痛的石头</value>
<value>父亲</value>
<value>好久不见</value>
<value>平凡之路</value>
</list>
</constructor>
</bean>

同时,也可以使用<ref>元素代替<value>,实现bean引用列表的装配,比如有一个代表歌曲目录的Discography类,其构造器如下:

public Discography(String artist,ListMConpactDisc> cds){
....
}

可采用下面的方式配置Discography bean:

<bean  id="compactDisc" class="soundsystem.BlankDisc">
<constructor-arg value="会痛的石头"/>
<constructor-arg value="萧敬腾"/>
<constructor-arg>
<list>
<ref bean="sgtPeppers"/>
<ref bean="whiteAlbum"/>
<ref bean="hardDaysNight"/>
<ref bean="revolver"/>
</list>
</constructor>
</bean>

设置属性

在CDPlayer和BlankDisc类完全是通过构造器注入,没有使用属性的Setter方法,接下来看如何使用SpringXML实现属性注入,假设CDPlayer类是下面这样:

public class CDPlayer {
private CompactDisc compactDisc;
@Autowried
public void setCompactDisc(CompactDisc compactDisc) {
this.compactDisc = compactDisc;
}
public void play(){
compactDisc.play();
}
}

在注入方式选择上,作为一个通用规则,更建议使用对强依赖使用构造器注入,可选性依赖使用属性注入,因此对于BlankDisc来说,歌曲名称、艺术家和磁道列表是强依赖(必须依赖),因此选择构造器注入,但是对于CDPlayer来讲CompactDisc即使没有装入,CDPlayer应该也有一些有限功能,在这里暂且认为是可选依赖。

现在CDPlayer除了默认构造器没有其他任何构造器,也没有任何强依赖,因此可以采用如下方式声明为Spring  bean:

<bean id="cdPlayer"  class="soundsystem.CDPlayer"/>

在创建时不会有问题,但是测试会出现空指针异常,可使用<peoperty.>元素来注入属性。

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

<property>元素为属性的Setter方法所提供功能和<construtor-arg>元素为构造器提供的功能一样,它引用了ID为compactDisc的bean,并且注入到cdPlayer的compactDisc属性中。

导入和混合配置

典型的Spring应用中,可能同时使用自动化和显式配置,可将JavaConfig的组建扫描和自动装配或XML混合在一起。混合配置中在自动装配时,它并不在意要装配的bean来自哪里,自动装配会考虑到Spring容器中所有的bean,不管是在JavaConfig或XML中声明还是通过组建扫描得到的。

在JavaConfig中引用XML配置

假设CDPlayerConfig已经变的很复杂,我们想将其拆分。

第一种方案:将BlankDisc从CDPlayerConfig拆分出来,定义在自己的CDConfig类中,如下所示:

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

compactDisc bean配置方法已经从CDPlayerConfig移除,但是我们还需要将这两个配置类组合在一起。

方法之一就是使用@Import注解导入CDConfig:

方法之二就是不在CDPlayerConfig中使用@Import,而是创建一个更高级别的SoundSystemConfig,在这个类使用@Import将两个配置类组合在一起:

在XML配置中引用JavaConfig

假设需要将XML配置文件进行拆分,可以使用import元素来拆分XML配置:

假设需要将CDPlayer配置在XML中,而BlankDisc配置在JavaConfig中,可以使用<bean>元素来操作,为了将JavaConfig导入到XML中,可以先这样声明bean:

小结

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

Spring 装配bean的三种方式:

  ● 自动化配置

  ● 基于Java的显式配置

  ● 基于XML的显式配置

尽可能的使用自动化配置,降低显示配置带来的维护成本,如果确实需要显式配置,应优先基于Java的配置,他比XML配置更强大,类型安全切易重构。

Spring学习笔记-装配Bean-02的更多相关文章

  1. Spring学习笔记—装配Bean

    在Spring中,对象无需自己负责查找或创建与其关联的其他对象.相反,容器负责把需要相互协作的对象引用赋予各个对象.创建应用对象之间协作关系的行为通常称为装配(wiring),这也是依赖注入的本质. ...

  2. #Spring实战第二章学习笔记————装配Bean

    Spring实战第二章学习笔记----装配Bean 创建应用对象之间协作关系的行为通常称为装配(wiring).这也是依赖注入(DI)的本质. Spring配置的可选方案 当描述bean如何被装配时, ...

  3. spring学习总结——装配Bean学习二(JavaConfig装配bean)

    通过Java代码装配bean 前言:上面梳理了通过注解来隐式的完成了组件的扫描和自动装配,下面来学习下如何通过显式的配置的装配bean: 使用场景:比如说,你想要将第三方库中的组件装配到你的应用中,在 ...

  4. spring学习总结——装配Bean学习三(xml装配bean)

    通过XML装配bean Spring现在有了强大的自动化配置和基于Java的配置,XML不应该再是你的第一选择了.不过,鉴于已经存在那么多基于XML的Spring配置,所以理解如何在Spring中使用 ...

  5. spring学习总结——装配Bean学习一(自动装配)

    一.Spring配置的可选方案 Spring容器负责创建应用程序中的bean并通过DI来协调这些对象之间的关系.但是,作为开发人员,你需要告诉Spring要创建哪些bean并且如何将其装配在一起.当描 ...

  6. Spring学习笔记--注入Bean属性

    这里通过一个MoonlightPoet类来演示了注入Bean属性property的效果. package com.moonlit.myspring; import java.util.List; im ...

  7. Spring学习(二)--装配Bean

    一.Spring装配机制 Spring提供了三种主要的装配机制: 1.在XML中进行显示配置 2.在Java中进行显示配置 3.隐式的bean发现机制和自动装配--自动化装配bean Spring可以 ...

  8. Spring学习笔记(3)——Bean的注入方式

    依赖注入 依赖注入支持属性注入.构造函数注入.工厂注入. 属性注入: 属性注入即通过setXxx()方法注入Bean的属性值或依赖对象 属性注入要求Bean提供一个默认的构造函数(无参构造函数),并为 ...

  9. spring学习总结——装配Bean学习四(导入和混合配置)

    情景:在典型的Spring应用中,我们可能会同时使用自动化和显式配置(JavaConfig)或者XML配置,幸好在Spring中,这些配置方案都不是互斥的.你尽可以将JavaConfig的组件扫描和自 ...

随机推荐

  1. Day3前端学习之路——CSS基本知识

    课程目标 初步了解什么是CSS,掌握基本的CSS概念,语法,针对选择器特殊性的计算处理,以及学习如何设置一些简单的样式 任务一:回答问题 1.什么是CSS,CSS是如何工作的? CSS 指层叠样式表 ...

  2. 关于ETH/BTC区块的监控

    此次我写的是一个小型的shell, 链接钉钉的机器人, 使用过的应该会比较娴熟的了,下面就简述一下把 主要的功能就是, 当发现本地数据库区块跟网络上的区块差距相差较大的时候就代表, 数据同步有问题, ...

  3. Java synchronized 关键字详解

    Java synchronized 关键字详解 前置技能点 进程和线程的概念 线程创建方式 线程的状态状态转换 线程安全的概念 synchronized 关键字的几种用法 修饰非静态成员方法 sync ...

  4. SDMask(iOS蒙层遮罩弹出引导)

    SDMask介绍 地址 针对iOS项目,大部分弹出视图三方都把弹出内容作为了项目的一部分,这种耦合局限性较大.该项目对此解耦,围绕我何时需要使用蒙层而展开设计.将弹出内容和动画和事件完全分离出去让co ...

  5. 字节、字符、位、bit、byte之间的关系

    字节.字符.位.bit.byte之间的关系 1. 概要 位(bit):是计算机 内部数据 储存的最小单位,表示二进制位,11001100是一个八位二进制数. 电脑记忆体中最小的单位,在二进位电脑系统中 ...

  6. cf938D

    题意简述:n个点m条边的无向图,有点权,有边权, 对于每一个点计算,d(i,j)表示点i到点j的最短路 题解:边权扩大二倍,建立源点,然后源点向每一个点x连接一条权值为a[x]的边,然后跑最短路即可 ...

  7. IIS WEB站点设置

    IIS安装 打开控制面板 -> 程序 -> 打开或关闭Windows功能 ,在弹出得对话框中选择“Internet信息服务”复选框.我这里是Windows server 2019 ,界面有 ...

  8. 清北学堂—2020.1提高储备营—Day 2 afternoon(线段树、树状数组)

    qbxt Day 2 afternoon --2020.1.18 济南 主讲:李佳实 目录一览 1.线段树 2.二叉搜索树(略过) 3.树状数组 总知识点:基础数据结构(本人初学感觉好难) 一.线段树 ...

  9. css flex弹性布局学习总结

    一.简要介绍 flex( flexible box:弹性布局盒模型),是2009年w3c提出的一种可以简洁.快速弹性布局的属性. 主要思想是给予容器控制内部元素高度和宽度的能力.目前已得到以下浏览器支 ...

  10. opencv —— 在 VS 中的配置

    添加一个新的 .cpp 文件到工程中 打开菜单栏视图中的属性管理器                                                      选择 Debug|x64 ...