装配Bean

spring提供了三种bean的装配机制

  • 一、在XML中进行显示配置;
  • 二、在Java中进行显示配置;
  • 三、隐式的bean发现机制和自动装配

 

一、自动化装配bean

CD播放器依赖于CD,只有将CD插入(注入)到CD播放器,CD播放器才能放出音乐。

1、spring从两个角度来实现自动化装配

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

2、@Component 注解表明该类会作为组件类,并告知spring要为这个类创建bean;组件扫描默认不启用,需组合@ComponentScan 注解使用。

3、@ComponentScan 启用组件扫描,如果没有其他配置,@ComponentScan默认会扫描与配置类相同的包。例,CDPlayerConfig类位于soundsystem包中,因此spring将会扫描这个包及这个包下的所有子包,查找带有@Compnent注解的类,这样就能发现CompactDisc,并且会在spring中自动为其创建一个bean;在xml中的使用:<context:componet-scan base-package="com.spring.soundsystem">。

4、为组件扫描的bean命名:spring应用上下文中所有的bean都会给定一个ID,@Component注解默认为ID为类名首字母小写,可自定义命名@Component("newName");也可以使用Java依赖注入规范中提供的@Named注解为bean设置ID,如:@Named("newName")。大多数场景中两者可相互替换,但推荐使用@Component,因为@Named注解语意不明。

5、设置组件扫描的基础包

@componetScan会以配置类所在的包作为基础包(base package)来扫描组件,如果我们将配置类放在单独的包中,使其与其他的代码区分开来,就需要在@Component的value属性中指明包的名称:

@Configuration
@ComponentScan("com.spring.soundsystem")
public class CDPlayConfig{
}

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

@Configuration
@ComponentScan(basePackages="com.spring.soundsystem")
//@ComponentScan(basePackages{"com.spring.soundsystem","com.spring.video"})
public class CDPlayConfig{
}

  以上方法基础包为String类型,这种方法是类型不安全的(not type-safe),@Componet还提供另外一种方法,那就是将其指定为包中所包含的类或者接口

@Configuration
@compnentScan(basePackageClasses={CDPlayer,class,Video.claass})
public class CDPlayerConfig{
}

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

  @autowired注解可用在类的任何方法上,不仅能够用在构造器上,还能用在属性的Setter方法上;如果没有匹配的bean,那么在应用上下文创建的时候,spring会抛出一个异常,为避免异常,可将@autowired的required属性设置为false,即:@autowired(required=false);将required属性设置为false时,spring会尝试执行自动装配,如果没有匹配的bean,sping将会让这个bean处于为装配的状态。同时,需要先在代码中进行null检查,否则会出现NullPointerException。如果有多个bean都能满足依赖关系,spring会抛出一个异常,表明没有明确指定选择哪个bean进行自动装配。可使用Java依赖注入规范的@Inject注解替换@Autowired。

 

二、通过Java代码装配bean(JavaConfig)

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

2、声明简单的bean

// @Bean注解会告诉spring这个方法返回一个对象,该对象要注册为spring应用上下文的bean
// 默认情况下,bean的id与带有@Bean注解的方法名是一样的
// 如果想设置一个不同的名字,可以重命名该方法,也可以通过name属性指定一个不同的名字,@Bean(name = "lonelyHeartsClubBand")
@Bean
public CompactDisc sgtPeppers(){
  return new SgtPeppers();    
}

3、借助JavaConfig实现注入

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

// 看起来CompactDisc是通过调用sgtPeppers()得到的,但情况并非完全如此。因为sgtPeppers()方法上添加了@Bean注解,spring将会拦截所有对它的调用,并确保直接返回该方法所创建的bean,而不是每次都对其进行实际的调用
@Bean
public CDPlayer cdPlayer(){
  return new CDPlayer(sgtPeppers()) ;
}
// 另一种理解起来更为简单的方式,CDPlayer的构造器实现DI
@Bean
pubic CDPlayer cdPlayer(CompactDisc compactDisc){
    return new CDPlayer(compactDisc);
}
// Setter方法注入
public CDPlayer cdPlayer(CompactDisc compactDisc){
    CDPlayer cdPlayer = new CDPlayer(compactDisc);
    cdPlayer.setCompactDisc(compactDisc);
    return cdPlayer;
}

 

三、通过XML装配Bean

1、创建一个XML文件,必须以<beans>元素为根,最为简单的Spring 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"
       xsi:schemaLocation="http://www.springframework.org/schema/beans 
      http://www.springframework.org/schema/beans/spring-beans.xsd
      http://www.springframework.org/schema/context">

</beans>

2、声明一个简单的<bean>

// 默认的ID"soundsystem.SgtPeppers#0","#0"是一个计数形式
<bean class="soundsystem.SgePeppers" />
// 为bena设置一个id
<bean id="compactDisc" class="soundsystem.SgePeppers" />

  当spring发现这个<bean>元素时,它将会调用SgtPeppers的默认构造器来创建bean。需要注意的是,在这个简单的<bean>声明中,我们将bean的类型以字符串的形式设置在了class属性中。谁能保证设置给class属性的值是真正的类呢?Spring的XML配置并不能从编译器的类型检查中受益。即便它所引用的是实际的类型,如果你重命名了类,会发生什么呢?

3、借助构造器注入初始化bean

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

· <constructor-arg>元素

· 使用spring 3.0所引用的c-命名空间

3.1、构造器注入bean引用


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

  当spring遇到<bean>元素时,他会创建一个CDPlayer实例。<constructor-arg>元素会告知spring要将一个ID为compactDisc的bean引用传递到CDPlayer的构造器中。

c-命名空间是在spring3.0中引入的,他是在XML中更为简洁第描述构造器参数的方式,要使用它必须要在XML的顶部声明其模式。

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

4、将字面变量注入到构造器中

假设要创建CompactDisc的一个新实现

  

<bean id="compactDIs" class="soundsystem.BlankDisc">
    <constructor-arg value="Sgt. Pepper's Loney Hearts Club Band" />
    <constructor-arg value="The Beatles" />
</bean>

  这里没有使用“ref”属性来引用其他的bean,而是使用了value属性,通过该属性表明给定的值要以字面量的形式注入待构造器中(“ref”,引用传递,“value”,值传递)。

5、设置属性

如何选择构造器注入还是属性注入?对于强依赖使用构造器注入,二队可选性的依赖使用属性注入。

  

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

  <property>元素为属性的Setter方法所提供的功能与<constructor-arg>元素为构造器所提供的功能是一样的。在本例中,它引用了ID为compactDisc的bean(通过ref属性),并将其注入到compactDisc属性中(通过setCompactDisc()方法)。

spring为<constructoer-arg>元素提供了c-命名空间作为替代方案,与之类似,sping提供了更加简洁的p-命名空间,作为<property>元素的替代方案。

使用p-命名空间需要进行声明:

  

我们可以使用p-命名空间,按照以下的方式装配compactDisc属性

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

  "p:"前缀表明我们设置的是一个属性,属性名称以“-ref”提示spring要进行装备的是引用而不是字面量。

将字面量注入到属性中

  

  

posted @ 2019-03-29 16:52  wintercloud  阅读(285)  评论(0编辑  收藏  举报