spring装配bean

693 阅读13分钟

spring装配bean

1. Spring配置的可选方案

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

    Spring的配置风格 是可以互相搭配的,所以你可以选择使用XML装配一些bean,使用Spring基于Java的配置(JavaConfig)来装配另一些bean,而将剩余的 bean让Spring去自动发现

2. 自动化装配bean

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

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

组件扫描和自动装配组合在一起就能发挥出强大的威力,它们能够将你的显式配置降低到最少。

2.1 创建可以被发现的bean

1.编写接口以及实现类

说明:@Component注解表明该类会作为组件类,并告知Spring要为这个类创建bean。没有必要显式配置SgtPeppersbean,因为这个类使用 了@Component注解,所以Spring会为你把事情处理妥当。

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

2.开启组件扫描

    CDPlayerConfig类使用了@ComponentScan注解,因此Spring将会扫描CDPlayerConfig类所在包以及这个包下的所有子包,查找有@Component注解的类,找到自动为其创建bean。

    备注:如果你更倾向于使用XML来启用组件扫描的话,那么可以使用Spring context命名空间的context:component-scan元素。

3.测试组件扫描
    为了测试组件扫描的功能,我们创建一个简单的JUnit测试,它会 创建Spring上下文,并判断CompactDisc是不是真的创建出来了


    CDPlayerTest使用了Spring的SpringJUnit4ClassRunner,以便在测试开始的时候自动创建Spring的应用上下文。注 解@ContextConfiguration会告诉它需要在CDPlayerConfig中加载配置。因为CDPlayerConfig类中包含了@ComponentScan, 因此最终的应用上下文中应该包含CompactDiscbean

2.2 为组件扫描的bean命名

  • 如果不指定bean的id,默认情况下spring会以类名首字母小写作为此bean的id
  • 如果想为这个bean设置不同的ID,你所要做的就是将期望的ID作为值传递给@Component注解。

  • 还有另外一种为bean命名的方式,这种方式不使用@Component注解,而是使用Java依赖注入规范(Java Dependency Injection)中所提供 的@Named注解来为bean设置ID:

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

2.3 设置组件扫描的基础包

  • 如果未为@ComponentScan设置任何属性。则按照默认规则,它会以配置类所在的包作为基础包(base package)
  • 为@ComponentScan设置基础包
    • @ComponentScan的value属性中指明包的名称:
      1.以string类型表示基础包

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


            设置多个基础包:

              2.以类或接口所在的包表示基础包
              除了将包设置为简单的String类型之外,@ComponentScan还提供了另外一种方法,那就是将其指定为包中所包含的类或接口:


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

2.4 通过为bean添加注解实现自动装配(@Autowired使用)

  • 构造器上添加了@Autowired注解
    这表明当Spring创建CDPlayerbean的时候,会通过 这个构造器来进行实例化并且会传入一个可设置给CompactDisc类型的bean。
  • 属性的setter方法上添加了@Autowired注解
    在Spring初始化bean之后,它会尽可能得去满足bean的依赖,在本例中,依赖是通过带有@Autowired注解的方法进行声明的,也就 是setCompactDisc()。
  • 在类的任何上添加了@Autowired注解

使用@Autowired注解进行自动装配时,能否匹配的情况

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


    将required属性设置为false时,Spring会尝试执行自动装配,但是如果没有匹配的bean的话,Spring将会让这个bean处于未装配的状态。 但是,把required属性设置为false时,你需要谨慎对待。如果在你的代码中没有进行null检查的话,这个处于未装配状态的属性有可能会 出现NullPointerException。

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

补充:@Autowired是Spring特有的注解。如果你不愿意在代码中到处使用Spring的特定注解来完成自动装配任务的话,那么你可以考虑将其替换 为@Inject:

@Inject注解来源于Java依赖注入规范,该规范同时还为我们定义了@Named注解。在自动装配中,Spring同时支 持@Inject和@Autowired。尽管@Inject和@Autowired之间有着一些细微的差别,但是在大多数场景下,它们都是可以互相替换的。

3. 通过Java代码装配bean

尽管在很多场景下可以使用组件扫描和自动装配来实现spring自动化配置,但是在有些场景下是行不通的。比如你想要将第三方库中的组件装配到你的应用中,在这种情况下,是没有办法在它的类上添 加@Component和@Autowired注解的,因此就不能使用自动化装配的方案了。

在这种情况下,你必须要采用显式装配的方式。在进行显式配置的时候,有两种可选方案:Java和XML

3.1 创建配置类

@Configuration注解所修饰的类就是配置类,该类中包含了应该在sprin应用上下文中如何创建bean的细节。
例如:

3.2 生命简单的bean

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


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

1)默认情况下,bean的ID与带有@Bean注解的方法名是一样的。
2)设置成一个不同的名字的话,那么可以重命名该方法,也可以通过name属性指定一个不同的名字

3.3 借助javaconfig实现注入

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

    上图在创建CDPlayer实例的时候构造器参数调用sgtPeppers()方法得到的,因为sgtPeppers()方法上添加了@Bea注解,Spring将会拦截所有对它的调用,并确保直接返回该方法所创建的bean,而不是每次都对其进行实际的调用
2)在javaConfig中装配的另一种方式

    在这里,cdPlayer()方法请求一个CompactDisc作为参数。当Spring调用cdPlayer()创建CDPlayerbean的时候,它会自动装配一个CompactDisc到配置方法之中。不用明确引用CompactDisc的@Bean方法。

    通过这种方式引用其他的bean通常是最佳的选择,因为它不会要求将CompactDisc声明到同一个配置类之中。在这里甚至没有要求CompactDisc必须要在JavaConfig中声明,实际上它可以通过组件扫描功能自动发现或者通过XML来进行配置。你可以将配置分散到多个配置类、XML文件以及自动扫描和装配bean之中,只要功能完整健全即可。不管CompactDisc是采用什么方式创建出来的,Spring都会将其 传入到配置方法中,并用来创建CDPlayer bean

4. 通过配置文件装配bean

4.1 创建xml配合规范

最为简单的spring.xml配置如下所示:

说明:1.顶部声明多个XML模式(XSD)文件定义了配置Spring的XML元素。2.用来装配bean的最基本的XML元素包含在spring-beans模式之中

4.2 在xml中声明bean

要在基于XML的Spring配置中声明一个bean,我们要使用spring-beans模式中的另外一个元素:。元素类似于JavaConfig 中的@Bean注解。


说明:1.创建一个bean的类是通过class属性指定的,要使用全限定名。 2、因为没有明确给定ID,所以这个bean将会根据全限定类名来进行命名;上述图中bean的id是“soundsystem.SgtPeppers#0”,其中“#0”是一个计数的形式,用来区分相同类型的其他bean。如果你声明了另外一个SgtPeppers,并且没有明确进行标识,那么它自动得到的ID将会是“soundsystem.SgtPeppers#1”。3、如果想为bean指定id,则通过id属性进行指定。

4.3 借助构造器初始化bean

构造器注入有两种方式: 1、<constructor-arg元素 2、使用Spring3.0所引入的c-命名空间

  1. 将bean的引用装配到构造器
    1)使用 <constructor-arg 元素


        2)使用Spring的c-命名空间
c-命名空间是在Spring 3.0中引入的,它是在XML中更为简洁地描述构造器参数的方式。 要使用它的话,必须要在XML的顶部声明其模式


    三种形式:
    1.
   上图,我们使用了c-命名空间来声明构造器参数,它作为元素的一个属性,属性名以“c:”开头,也就是命名空间的前缀。接下来就是要装配的构造器参数名,在此之后是“-ref”,这是一个命名的约定,它会告诉 Spring,正在装配的是一个bean的引用
    2.使用参数在整个参数列表中的位置信息

   “0”是参数的索引。因为在XML中不允许数字作为属性的第一个字符,因此必须要添加一个下画线作为前缀。

    3.如果构造器中只要一个参数,根本不用去标示参数

  1. 将字面量装配到构造器

  1)使用 <constructor-arg 元素

  2)使用Spring的c-命名空间
    三种形式:
    1.

   装配字面量与装配引用的区别在于属性名中去掉了“-ref”后缀

    2.通过参数索引装配相同的字面量值

    3.如果构造器中只要一个参数,根本不用去标示参数

  1. 装配集合
    在装配bean引用和字面量值方面,<constructor-arg和c-命名空间的功能是相同的。但是有一种情况“将集合装配到构造器参数中”是<constructor-arg能够实 现,c-命名空间却无法做到的
  • 集合元素是普通的字面量

补充:可以将集合值在注入期设置为null,但是在运行期间要注意空指针异常。

<null/元素将null值传递给构造器。

  • 集合元素是bean

使用<ref元素替代<value,实现bean引用列表的装配

补充:当构造器参数的类型是java.util.List时,不管集合类型是字面量还是bean,也可以按照同样的方式使用元素:

和元素的区别不大,其中最重要的不同在于当Spring创建要装配的集合时,所创建的是java.util.Set还 是java.util.List。如果是Set的话,所有重复的值都会被忽略掉,存放顺序也不会得以保证。不过无论在哪种情况 下,或都可以用来装配List、Set甚至数组。

4.4 设置属性

通过属性的setter方法实现依赖注入

4.4.1 设置属性(引入其他bean)

1.通过<property实现依赖注入

2.通过p-命名空间实现依赖注入
Spring为元素提供了c-命名空间作为替代方案,与之类似,Spring提供了更加简洁的p-命名空间,作 为元素的替代方案。为了启用p-命名空间,必须要在XML文件中与其他的命名空间一起对其进行声明:


使用p-命名空间:
p-命名空间中属性所遵循的命名约定与c-命名空间中的属性类似:

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

4.4.2 设置属性(字面量)


1.通过<property实现依赖注入

2.通过p-命名空间实现依赖注入


3.通过p-命名空间实现集合依赖注入
我们不能使用p-命名空间来装配集合,没有便利的方式使用p-命名空间来指定一个值(或bean引用)的列表。但是,我们可 以使用Spring util-命名空间中的一些功能来简化BlankDisc bean。
首先,需要在XML中声明util-命名空间及其模式:

util-命名空间所提供的功能之一就是util:list元素,它会创建一个列表的bean。借助util:list,我们可以将磁道列表转移 到BlankDisc bean之外,并将其声明到单独的bean之中,如下所示:

现在,我们能够像使用其他的bean那样,将磁道列表bean注入到BlankDisc bean的tracks属性中:

补充说明:util:list只是util-命名空间中的多个元素之一。下图列出了util-命名空间提供的所有元素。

5. 导入和混合配置

在Spring中,可以将JavaConfig的组件扫描和自动装配和/或XML配置混合在一起

混合配置,在自动装配时,它并不在意要装配的bean来自哪里。自动装配的时候会考虑到Spring容器中所有的bean,不管它是在JavaConfig或XML中声明的还是通过组件扫描获取到的。

你可能会想在显式配置时,比如在XML配置和Java配置中该如何引用bean呢

5.1 在JavaConfig中引用XML配置

  • 在一个javaconfig中引入另外一个javaconfig

使用@Import注解导入CDConfig

  • 创建一个更高级的SoundSystemConfig,在其中使用@Import将两个配置类组合在一起

  • 在一个javaconfig中引入XML来配置

5.2 在XML配置中引用JavaConfig

  • 在一个xml配置中引入另外一个xml配置

  • 在一个xml配置中引入一个javaConfig配置

    元素能在xml配置文件中导入javaConfig配置类

  • 创建一个更高层次的配置文件,这个文件不声明任何的bean,只是负责将两个或更多的配置组合起来