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小记(3):Spring的bean的装配(基础)_第1张图片
为被装配的组件命名

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

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

Spring小记(3):Spring的bean的装配(基础)_第2张图片
通过XML进行bean的装配

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

元素
使用Spring3.0所引入的c空间

使用的配置文件如下所示




       
       
              
       

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

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




       
       

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

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

    public BlankDisc(String title,String artist,List 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进行配置


              
              
              
                     
                            Sgt. Peper's Lonely Hearts Club Band
                            Fixing a Hole
                     
              
       

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


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

public class BlankDisc implements CompactDisc {
    private String title;
    private String artist;
    private List tracks;

//    public BlankDisc(String title,String artist,List 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 tracks){this.tracks = tracks;}


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

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


              
              
              
                     
                            Getting Better
                            Fixing a Hole
                     
              
       

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




       
       
       
              Getting Better
              Fixing a Hole
       
       

混合配置

在通常的使用中,我们不仅可以使用上面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);
    }
} 

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

Spring小记(3):Spring的bean的装配(基础)_第3张图片
XML中引用JavaConfig

我们先创建一个XML配置文件,里面包含了上面两种方式的配置



       
       

再编写测试文件,如下

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

运行并查看结果

Spring小记(3):Spring的bean的装配(基础)_第4张图片

你可能感兴趣的:(Spring小记(3):Spring的bean的装配(基础))