Spring小记(3):Spring的bean的装配(基础)

在spring中,对象无需自己查找或创建与其所关联的其他对象,容器负责把需要相互协作的对象引用赋予各个对象,容器的这种创建对象之间协作关系的行为被称为装配,也被成为依赖注入(DI),依赖注入有3种方案可供选用,如下

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

看下面一个实例
1、创建一个接口

public interface CompactDisc {
    void play();
}

2、添加这个接口的实现,注意我们在类的头部添加了@Component的注解,表明这个类是一个组件

@Component
public class SgtPeppers implements CompactDisc {
    private String title = "Sgt. Pepper's Lonely Hearts Club Band";
    private String artist = "The Beatles";


    @Override
    public void play() {
        System.out.println("Playing " + title + " by " + artist);
    }
}

3、添加对这个组件的配置,这个类里面什么东西都没有,只有类的头部有两个注解,分别为@Configuration和@ComponentScan,其中@ComponentScan注解表明会对这个包中的包含@Component的类进行扫描

@Configuration
@ComponentScan
public class CDPlayConfig {
}

4、编写一个简单的JUnit例子

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = CDPlayConfig.class)
public class CDPlayConfigTest {

    @Autowired
    private CompactDisc cd;

    @Test
    public void cdShouldNotBeNull(){
        assertNotNull(cd);
    }
} 

在上面的JUnit的例子中,类的头部包含了@RunWith注解和@ContextConfiguration注解,其中RunWith中的SpringJUnit4ClassRunner.class将会为我们创建Spring应用的上下文,ContextConfiguration中的classes = CDPlayConfig.class则表明我们将在CDPlayConfig中加载配置
运行,会发现JUnit的测试是通过的

为被装配的组件命名

Spring应用的上下文中的所有的bean都会有一个ID来标识自己,假如我们不强制指定,那么Spring会根据类名为其指定一个ID,一般会把类的第一个字母小写来作为ID,比如上面的SgtPeppers,那么这个bean的ID就是sgtPeppers,我们也可以自己指定ID,有两种方式,分别如下
第一种是在Component里面直接写上ID

@Component("lonelyHeartClub")
public class SgtPeppers implements CompactDisc {
    ...
}

第二种是使用DI的参数@Named注解,如下

@Named("lonelyHeartClub")
public class SgtPeppers implements CompactDisc {
    ...
}

不过推荐使用第一种

对于@ComponentScan的注解,假如我们不指定扫描的包,那么就会扫描配置类当前所在的包,我们也可以指定我们需要进行扫描的包,如下

@ComponentScan(basePackages = "com.fan.soundsystem")
public class CDPlayConfig {
}

不过也可以使用类所在包作为扫描的包,如下

@Configuration
@ComponentScan(basePackageClasses = CDPlayConfig.class)
public class CDPlayConfig {
}

@Autowired是自动装配注解,表明会在上下文中搜索bean并装配到参数之中,假如没有匹配的bean,那么就会抛出异常,为了避免异常的发生,我们可以设置@Autowired的required属性为false。我们同样可以使用@Inject来替代@Autowired,如下

@Inject
public void setCompactDisc(CompactDisc cd){
    this.cd = cd;
}
通过JavaConfig进行bean的装配

1、我们针对CompactDisc创建一个新的实现

@Component
public class Revolver implements CompactDisc {
    private String title = "Revolver";
    private String artist = "The Beatles";

    @Override
    public void play() {
        System.out.println("Playing " + title + " by " + artist);
    }
}

2、然后我们把CDPlayConfig 中的@ComponentScan注解移除,并添加我们自己写的注入,需要注意的是,假如我们有两个创建CompactDisc 的方法被增加了注解@bean,那么我们将得不到一个正确的结果,如下面注释的部分不能出现

@Configuration
public class CDPlayerConfig1 {
//    @Bean
//    public CompactDisc sgtCompactDisc(){
//        return new SgtPeppers();
//    }
    @Bean
    public CompactDisc randomBeatlesCD(){
        int choice = (int) Math.floor(Math.random() * 4);
        if(choice == 0){
            return new SgtPeppers();
        }else {
            return new Revolver();
        }
    }

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

3、对JUnit的实例做一下简单的修改

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = CDPlayerConfig1.class)
public class CDPlayConfigTest {
//    @Rule
//    public final StandardOutputStreamLog log = new

    @Autowired
    private CDPlayer cd;

    @Test
    public void cdShouldNotBeNull(){
        assertNotNull(cd.getCompactDisc());
    }

这样同样能够取得相同的效果

通过XML进行bean的装配

基于XML装配bean的方法配置风格有两种,分别为

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

使用<constructor-arg>的配置文件如下所示

<?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">

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

我们可以通过这种方式来获取bean

使用c命名空间的方式配置如下

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:c="http://www.springframework.org/schema/c"
       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">

       <bean id="compactDisc" class="com.fan.soundsystem.SgtPeppers"/>
       <bean id="cdPlayer" class="com.fan.soundsystem.CDPlayer" c:cd-ref="compactDisc"/>
</beans>

我们为上面的配置编写一个测试方法,如下

public class Main {
    public static void main(String[] args){
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("springConfig.xml");
        CDPlayer cd = context.getBean(CDPlayer.class);
        cd.getCompactDisc().play();
        context.close();
    }
}

c命名空间相比之下更加的灵活
我们有时候需要将字面量注入到bean之中,我们在这种情况下该怎么做呢?
如下,我们先创建一个类,并不设置任何注解

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;
    }


    @Override
    public void play() {
        System.out.println("Playing " + title + " by " + artist);
        for(String track : tracks)
            System.out.println("-Track:" + track);
    }
}

然后利用配置给这个bean进行配置

<bean id="blankDisc" class="com.fan.soundsystem.BlankDisc">
              <constructor-arg value="Sgt. Pepper's Lonely Hearts Clubs Band"/>
              <constructor-arg value="The Beatles"/>
              <constructor-arg>
                     <list>
                            <value>Sgt. Peper's Lonely Hearts Club Band</value>
                            <value>Fixing a Hole</value>
                     </list>
              </constructor-arg>
       </bean>

和引用注入一样,我们同样可以使用c命名空间进行注入,如下

<bean id="blankDisc" class="com.fan.soundsystem.BlankDisc"
               c:title="Sgt. Pepper's Hearts Club Band"
               c:artist="The Beatles"
               c:tracks-ref="trackList"/>

以上都是构造器注入的方法,有时候我们需要对属性进行注入,那么我们可以使用下面这种方式,首先我们需要改造一下BlankDisc的写法

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 setTitle(String title){this.title = title;}
    public void setArtist(String artist){this.artist = artist;}
    public void setTracks(List<String> tracks){this.tracks = tracks;}


    @Override
    public void play() {
        System.out.println("Playing " + title + " by " + artist);
        for(String track : tracks)
            System.out.println("-Track:" + track);
    }
}

注意其中的构造器必须注释掉,否则会出错,然后我们对配置文件进行编写

<bean id="blankDisc" class="com.fan.soundsystem.BlankDisc">
              <property name="title" value="Sgt. Pepper's Lonely Hearts Club Band"/>
              <property name="artist" value="The Beatles"/>
              <property name="tracks">
                     <list>
                            <value>Getting Better</value>
                            <value>Fixing a Hole</value>
                     </list>
              </property>
       </bean>

同样,我们还可以使用p空间进行配置,看下面

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:c="http://www.springframework.org/schema/c"
       xmlns:util="http://www.springframework.org/schema/util"
       xmlns:p="http://www.springframework.org/schema/p"
       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/util
                            http://www.springframework.org/schema/util/spring-util.xsd">

       <bean id="compactDisc" class="com.fan.soundsystem.SgtPeppers"/>
       
       <util:list id="trackList">
              <value>Getting Better</value>
              <value>Fixing a Hole</value>
       </util:list>
       <bean id="blankDisc" class="com.fan.soundsystem.BlankDisc"
             p:title="Sgt. Pepper's Lonely Hearts Club Band"
             p:artist="The Beatles"
             p:tracks-ref="trackList"/>
</beans>
混合配置

在通常的使用中,我们不仅可以使用上面3中方式的任何一种,而且我们还可以将各种方式进行组合使用,常见的做法是在JavaConfig中引用XML和在XML中引用JavaConfig,那么我们应该怎么做才能达到这一点呢

JavaConfig中引用XML

假如我们在一个测试单元中同事使用CDPlayer和BlankDisc,那么我们可以对CDPlayerConfig1 增加对BlankDisc的配置,如下所示

@Configuration
@ImportResource("classpath:springConfig.xml")
public class CDPlayerConfig1 {
//    @Bean
//    public CompactDisc sgtCompactDisc(){
//        return new SgtPeppers();
//    }
    @Bean
    public CompactDisc randomBeatlesCD(){
        int choice = (int) Math.floor(Math.random() * 4);
        if(choice == 0){
            return new SgtPeppers();
        }else {
            return new Revolver();
        }
    }

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

我们再修改一下测试单元的代码,如下

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = CDPlayerConfig1.class)
public class CDPlayConfigTest {
//    @Rule
//    public final StandardOutputStreamLog log = new

    @Autowired
    private CDPlayer cd;

    @Autowired
    private BlankDisc bd;

    @Test
    public void cdShouldNotBeNull(){
        assertNotNull(cd.getCompactDisc());
        assertNotNull(bd);
    }
} 

运行并查看运行的结果,如下所示

XML中引用JavaConfig

我们先创建一个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">
       <import resource="springConfig.xml"/>
       <bean class="com.fan.soundsystem.CDPlayerConfig1"/>
</beans>

再编写测试文件,如下

public static void main(String[] args){
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("TotalConfig.xml");
        AnnotationConfigApplicationContext context1 = new AnnotationConfigApplicationContext(CDPlayerConfig1.class);
        BlankDisc bd = context.getBean(BlankDisc.class);
        CDPlayer cdPlayer1 = context1.getBean(CDPlayer.class);
//        CDPlayer cdPlayer = context1.getBean(CDPlayer.class);
        cdPlayer1.play();
        bd.play();
        context.close();
    }

运行并查看结果

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

推荐阅读更多精彩内容