《Spring实战》--笔记 第二章 装配Bean

2.1 Spring 配置的可选方案

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

JavaConfig比XML更加强大且类型安全

2.2 自动化装配bean

自动装配的过程

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

使用java配置开启组件扫描

/**
@Configuration注解说明是一个配置类
@ComponentScan开启组件扫描(默认扫描当前配置类所在包)
*/
@Configuration
@ComponentScan
public class JavaDemoConfig{...}

使用@ContextConfiguration(classes=JavaDemoConfig)可以加载JavaDemoConfig配置

使用XML配组文件开启组件扫描

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

2.2.2 为组件扫描的Bean命名

@Component(“组件id”),如果没有声明组件id,那么Spring会通过自动为该组件注册一个id,将该类类名第一个字母变为小写。

也可以使用@Named(“组件id”)进行声明,不常见。

2.2.3 设置组件扫描的基础包

@ComponentScan默认扫描当前类所在的包。

@ComponentScan(basePackages="soundsystem")

指定扫描"soundsystem"包,当然如果需要扫描多个包,写成

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

上面这种方式是使用String类型表示包名,如果代码重构后包名发生了变化,就会出现错误。
@ComponentScan提供了另外一种方法,就是指定包中所包含的类或者接口:

@ComponentSacn(basePackageClasses={CDPlayer.class,DVDPlayer.class})

当在注解中声明了类之后,Spring会将该类所在的包作为扫描的对象。(可以手动添加一个空的接口专门为标记对象,避免引用实际需要的类,因为这些类以后代码重构可能不存在)

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

@Autowired可以使用在构造器、Setter方法甚至类的任何方法上。

/**
普通方法使用@Autowired
*/
@Autowired
public void setCompactDisc(CompactDisc cd){
this.cd = cd; 
}

当应用上下文创建的时候,Spring会去寻找对应的bean,如果没有找到对应的bean,那么会报错。可以将@Autowired的required属性设置为false。

/**
普通方法使用@Autowired
*/
@Autowired(required=false)
public void setCompactDisc(CompactDisc cd){
this.cd = cd; 
}

这样使用之后,当没有对应的bean时,Spring不会报错,但是这个bean可能会出现空指针异常。
@Autowired是Spring特有的注解。也可以替换成java依赖注入的规范@Inject,大部分情况下他们是可以互相替换。

2.3 通过Java代装配Bean

有时候自动装配行不通(比如你要将第三方的组件配置到你的代码中,不可能在它的类上加上@Autowired注解)时,就需要显式配置Bean
JavaConfig是配置代码,应当没有任何业务逻辑,可以将它放入单独的包里面,就像XML配置文件一样和业务分开。

2.3.1 创建配置类

@Configuration注解表明该Java类是一个配置类。
@ComponentScan开启组件扫描

2.3.2 声明简单的bean

在JavaConfig中创建一个方法,然后创建所需类型的实例,最后为这个方法添加@Bean注解。

@Bean
public CompactDisc sgtPeppers(){
   return new SgtPeppers();
}

默认情况下,bean的ID与@Bean注解的方法名是一样,上面例子的Bean的名字就会是sgtPeppers。如果想指定成其他的名字,在@Bean注解的name属性中声明。

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

可以玩一些更有意思的操作。

@Bean    
public CompactDisc randomBeatlesCD(){        
   int choice = (int)Math.floor(Math.random()*4);
   switch (choice){            
   case 0:return new SgtPeppers();            
   case 1:return new WhiteAlbum();            
   case 2:return new HardDaysNight();            
   case 3:return new Revolver();       
   }   
}

2.3.3 借助JavaConfig实现注入

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

上面这个例子中创建了一个Bean,名字叫做cdPlayer,在这个方法返回的Bean的实例中,在构造器中使用sgtPeppers()方法传入了一个CompactDisc的对象。

看上去CompactDisc是通过调用sgtPeppers()这样一个方法来得到的。实际上sgtPeppers()由于声明了@Bean注解,Spring将会拦截所有对该方法的调用,保证直接返回该方法创建的bean,并不是每次都对其进行了实际的调用。
因为Spring中的Bean都是单例的,所以Spring会拦截sgtPeppers()方法,然后返回同一个已经创建完成的SgtPeppers实例。

除了调用方法注入外,当然也可以这么写:

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

这里Spring会在cdPlayer创建的时候,将CompactDisc以自动装配的形式注入到cdPlayer的构造器中。这种方法通常较好,它不要求COmpactDisc和cdPlayer声明在同一个配置类中,甚至没有要求CompactDisc在JavaCon中声明(可以将配置分散到多个配置类、XML文件,或者通过自动扫描来装配)

2.4通过XML装配Bean

2.4.1创建XML配置规范

最简单的SpringXMl配置如图所示:
《Spring实战》--笔记 第二章 装配Bean
<beans></beans>是整个配置文件的根元素。
首先需要声明顶部的多个XML模式(XSD)文件,这些文件定义了配置文件中的XML元素。

2.4.2声明一个简单的<bean>

<bean>类似于JavaConfig中的@Bean注解,它声明了一个Bean。

<bean class="soundsystem.SgtPeppers"/>

也可以为它指定一个id

<bean id="sgtPeppers" class="soundsystem.SgtPeppers"/>

如果没有为它指定id,Spring会根据全限定类名来进行命名。如"soundsystem.SgtPeppers#0",当你又声明了一个SgtPeppers,并且没有指定id,那么Spring会为他自动创建一个id:“soundsystem.SgrPeppers#1”。
自动生成在引用时可能不太便利,建议主动为bean声明id。

XML配置和JavaConfig相差在哪里

  1. 在XML中,bean是由Spring调用该类的构造器自动生成的实例。但是在JavaConfig中你可以用任何方式返回一个实例
  2. 在XML中,bean的class属性是用字符串的形式表示的。(但是IDE的强大确保你能够检查到XML文件的合法性)
  3. (XSD文件的引入不小心就引入错误的,导致冲突)

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

有两种可选的构造器注入的方案:

  • <constructor-arg>元素
  • 使用Spring3.0所引入的c-命名空间

<constructor-arg>比c-命名空间更加冗长,但是有些事情<constructro-arg>可以做
到,但是c-命名空间做不到。

这里使用了<constructor-arg>为csPlayer这个Bean注入了另外一个Bean-compactDisc的引用。

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

如果使用c-命名空间:

<bean id="csPlayer" class="soundsystem.CDPlayer" c:cd-ref="compapctDisc">

c-命名空间的规则:
《Spring实战》--笔记 第二章 装配Bean
这里的构造器参数指明了cd,如果cd这个参数名称发生了变化,就会出现错误,所以可以将cd换成_0、_1这样指定构造器的顺序,如果只有一个参数,甚至可以只用一个下划线_来表示。(xml不允许直接数字开头,所以加下划线)

<bean id="csPlayer" class="soundsystem.CDPlayer" c:_-ref="compapctDisc">

前面都是诸如对象的引用,现在来试试装配字面量。
首先在一个类中有这样的构造方法。

public BlankDisc(String title,String artist){
    this.titile = title;
    this.artist = artist;
}

然后在XML中配置:

<bean id="compactDisc" class="soundsystem.BlankDisc">
    <constructor-arg value="Sgt.Peppers's Lonely Hearts Club Band"/>
    <constructor-arg value="The Beatles"/>
</bean>

如果换成使用c-命名空间:

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

装配集合
如果一个类的构造函数需要传入集合,假设他的构造函数如下:

public BlankDisc(String title,String artist,List<String> tracks){
    this.titile = title;
    this.artist = artist;
    this.tracks = tracks;
}

那么你可以在xml这么设置:

<bean id="compactDisc" class="soundsystem.BlankDisc">
    <constructor-arg value="Sgt.Peppers's Lonely Hearts Club Band"/>
    <constructor-arg value="The Beatles"/>
    <constructor-arg>
        <list>
            <value>...</value>
            <value>...</value>
            <value>...</value>
            <value>...</value>
            <!-- ... -->
        </list>
    </constructor-arg>
</bean>

c-命名空间目前还不能使用集合装配

2.4.4设置属性

使用进行属性设置。

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

同样的,Spring为属性设置提供了一个p-命名空间,所以也可以这么写

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

p-命名空间的规则
《Spring实战》--笔记 第二章 装配Bean

同样的p-也不支持注入集合。如果你不想在Bean中定义太长,你也可以使用Spring util-命名空间来简化Bean的定义

<util:list id="trackList">
    <value>...</value>
    <value>...</value>
    <value>...</value>
    <!-- ... -->
</util:list>

这时候你可以将这个list的id像其他bean一样用ref进行注入。

util-命名空间的元素

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

2.5 导入和混合配置

2.5.1 在JavaConfig中引入XML配置

假如现在有两个JavaConfig,如果将两个配置整合?

  1. 在一个JavaConfig上@Import(xxx.class)导入另外一个JavaConfig
  2. 创建一个更高级的JavaConfig,然后@Import({xxx.class,xxx.class})将他们整合

如果有一个是XML配置文件的话。
使用@ImportResource(“classpath:xxx.xml”)整合类路径下的XML配置文件。

2.5.2 在XML配置中引用JavaConfig

加入现在有两个XML配置文件,如何将两个配置整合?

使用XML的元素引用另外的文件,和@ImportResource注解一样同样是使用类路径。

如何整合XML和JavaConfig?

直接在XML文件中将JavaConfig声明成一个Bean

<bean class="soundsystem.CDConfig"/>
上一篇:webdriver得到cookies并应用保存


下一篇:Selenium——根据已有cookie打开网页