Spring Bean的装配

  在《Spring 基本使用》一节中,Spring Bean的装配方式是:组件扫描和@Autowired自动装配。有时候自动化配置方案行不通,需要明确配置Sring。比如你需要将第三方组件装配到你的应用中。在这种情况下,你是没有办法在它的类上加上@Component和@Autowired注解的,因此,在这种情况下,便不能使用自动装配了。
  在无法使用自动装配时,你只能使用显示的装配方案,可选的有两种Java配置和XML配置。
  在进行显示配置时,JavaConfig是更好的方案,因为它更加强大,类型安全,并且重构友好。因为它就是Java代码,和你应用中其他的Java代码一样。同时,JavaConfig又和其他的Java代码有所区别,在概念上,它与应用程序中的业务逻辑和领域代码是不同的。尽管它与其他组件一样都使用同一语言进行描述,但是JavaConfig是配置代码,这意味着它不应该包含任何的业务逻辑代码。JavaConfig也不应该侵入其他的业务逻辑代码中。尽管不是必要的,一般将JavaConfig放在放在一个单独的包中,使其与业务逻辑代码相分离。

1.通过JavaConfig来显示的配置Spring

(1)创建配置类
package com.hsun.spring.config;

import org.springframework.context.annotation.Configuration;
/**
 * 创建JavaConfig的关键在于为配置类加上@Configuration注解,
 * 该注解表明这个类是一个配置类,该类应该包含SPring如何创建bean的细节
 * @author hsun
 *
 */
@Configuration
public class MyConfig {

}

  在《Spring 基本使用》中,使用的都是组件扫描的方式来发现Spring应该创建的Bean。尽管我们可以同时使用组件扫描和显示配置,在此只关注显示配置,故而将注解@ComponentScan移除。

(2) 创建Bean

  @ComponentScan告诉Spring 哪个packages 的用注解标识的类 会被spring自动扫描并且装入bean容器。在此配置类中移除了此注解,组件扫描将不会发现那些我们希望被Spring发现并且创建的Bean。
  针对这样的情况我们可以在JavaConfig中显示配置一个bean,编写一个方法,这个方法负责创建我们所需要的bean的实例,并在该方法上加上@Bean注解。

   @Bean
    public CompactDisc setPeppers() {
        return new CompactDisc();
    }

  @Bean注解会告诉Spring注解这个方法将返回一个对象,该对象要注册成为Spring应用上下文的bean。方法体中包含了最终产生bean实例的逻辑。默认情况下这种方式创建的bean的ID与创建该bean的方法的方法名是一样的。在以上的示例代码中,创建产生的bean的id将会是setPeppers。如果需要为其设置一个其他的名字的话,那么可以修改方法的名称或者也可以通过name属性指定一个不同的名字:

    @Bean(name="lonelyHeartClubBand")
    public CompactDisc setPeppers() {
        return new CompactDisc();
    }

  当然使用JavaConfig创建Bean不仅仅只有这一点功能,使用JavaConfig创建bean仅仅与创建bean的方法体内的代码逻辑相关。那么如下,可以根据不同的情况来创建不同的bean:

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

(3)借助JavaConfig实现注入

  之前声明的CompactDisc Bean都是非常简单的Bean它自身没有其他的依赖,但是若土国声明CDPlayer Bean,并且该Bean依赖ComPactDisc。在JavaConfig中想要将其装配到一起,最简单的方法就是引用创建Bean的方法,如下是一种声明CDPlayer的可行的方案:

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

  当然除了以上的通过方法的引用来实现装配外,也可以通过参数传递的方式来实现装配:

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

  通过参数引用其他bean的方式通常是最佳的选择。因为他不要求将CompactDisc Bean声明到同一个配置类中。甚至你不需要将ComapctDisc声明到JavaConfig配置类中,实际上他可以通过组件扫描发现或者通过XML配置。你可以将这些配置分散到多个配置类或者配置文件以及自动扫描装配bean之中。只要功能完全健全即可。不管CompactDisc是通过什么方式创建的,Spring都会就将其传入配置方法中,并用其创建CDPlayer。
  另外,此处使用的是Bean的构造器实现了DI功能,但是我们完全可以采用其他风格的DI配置。比如说通过Setter来注入CompactDisc:

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

2.通过XML来装配bean

  在使用XML来装配Bean之前你需要创建一个Spring的XML配置规范,即创建一个Spring的配置文件,最简单的Spring XML配置如下所示:


(1)声明一个简单的<bean>

  要在基于Spring XML的配置中声明一个bean,需要使用spring-beans模式中两个元素<beans>、<bean>。<beans>元素包裹<bean>,声明一个简单的bean如下:



这里声明了一个简单的bean,创建这个bean的类是通过class属性指定的,并且要使用全限定类名。因为没有明确的指定ID,所以这个bean将会只用全限定类名来进行命名。bean的ID将会是

其中“#0”是一个计数形式,用来区分相同类型的其他bean实例。如果声明了另外一个SgtPeppers,并且没有明确进行你标识,那么自动得到的ID将会是

当然也可以通过id属性来为每一个创建的bean来指定一个你选择的名字:



在将这个bean装配到其他的bean中时你将会使用到这个名字。

(2)借助构造器初始化bean

a.简单的构造器初始化

  在Spring 的XML配置中只有一种声明Bean的方式,使用bean元素并指定class属性,Spring将从这里获取必要信息来创建bean。但是在XML中声明DI时,却有多中可选的配置方案和风格。具体到构造器注入有两种可选择的方案:

  • 使用<constructor-arg>元素


  • 使用Spring 3.0所引入的c-命名空间
      先在spring xml配置文件中声明 c-的命名空间:


  使用c-命名空间来声明构造器参数:


使用c-声明构造器参数的属性名构成:



或者将构造器参数替换成“0”,也就是将参数名替换成参数索引,因为XML文件不允许数字做为属性的第一个字符,因此必须要添加一个下划线作为前缀:


如果这有一个构造器参数,那么还可以写成这样:


b.将字面量注入到构造器中

  再次使用<constructor-arg>来进行构造器的参数注入,但是此时使用的是"value"而不是“ref”,通过“value”属性表明,给定值要通过字面量的形式注入到构造器中。

通过c-命名空间:



或者

当然如果只有一个构造器参数,那么你当然可以写成这样:
c.装配集合

类似的可以使用“ref”来替代”value“



当构造器参数是java.util.List时,使用<list>是合情合理的,尽管如此,我们同样可以按照同样的方式来使用<set>元素:



d.设置属性

使用p-命名空间:


引入p-命名空间和模式

使用p-命名空间设置属性

p-命名空间属性所遵循的命名约定

list属性设置+property、p-混合

使用spring-util-命名空间来声明list,配bean的属性注入:


引入命名空间

声明list

引用sring-util- 声明的list

3. 导入和混合配置

(2)JavaConfig引用


或者编写一个更加高级的配置类将两个配置类组合在一起:


(2)JavaConfig引用XML配置

(3)在XML配置中引用JavaConfig

配置文件组合:


©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,590评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 86,808评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,151评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,779评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,773评论 5 367
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,656评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,022评论 3 398
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,678评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 41,038评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,659评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,756评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,411评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,005评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,973评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,203评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,053评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,495评论 2 343

推荐阅读更多精彩内容