美文网首页
Spring装配bean的三种方式

Spring装配bean的三种方式

作者: 我是予不真 | 来源:发表于2018-07-12 01:10 被阅读0次

所有内容参考《spring 实战》,作为学习笔记使用。

spring装配bean主要有三种方式,(1) 自动装配 (2) java代码显式装配 (3) xml显式装配

1. 自动化装配

spring的自动化装配主要通过两个机制来实现,组件扫描、自动装配
组件扫描:Spring会自动发信应用上下文中所创建的bean
自动装配:Spring自动满足bean之间的依赖
下面通过代码来讲解,主要涉及4个java文件,两个接口,两个实现类。分别是
SgtPeppers实现CompactDisc,CDPlayer实现MediaPlayer

package soundsystem;
public interface CompactDisc {
    void play();
}
package soundsystem;

import org.springframework.stereotype.Component;

@Component("sgtPeppers")  //设置生成的bean的ID
//Component表示该类会作为组件类,并且告诉spring为该类创建bean,在spring中,组件扫描默认不启用,需要显示配置一下,配置完之后,spring会去扫描带有@Component的组件,并生成bean
//显示配置在CDPlayerConfig.java中配置了
public class SgtPeppers implements CompactDisc {

    private String title = "Sgt. Pepper's Lonely Hearts";
    private String author = "The Beatles";

    @Override
    public void play() {
        System.out.println("playing " + title + " by " + author);
    }
    public static void main(String[] args){

    }
}
package soundsystem;

public interface MediaPlayer {
    void play();
}
package soundsystem;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
public class CDPlayer implements MediaPlayer {
    private CompactDisc cd;
    /*
    * @Autowired实现依赖的注入。
    * */
    @Autowired  //spring会努力寻找一个可以设置为CompactDisc类型的bean传递给构造函数,如果spring找不到这样的bean,会抛异常,同时,如果找到多个这样的bean
    //也会抛异常
    public CDPlayer(CompactDisc cd) {
        this.cd = cd;
    }

    public CDPlayer(){

    }
    public void setCd(CompactDisc cd){
        this.cd = cd;
    }
    public void play() {
        cd.play();
    }
}

在SgtPeppers和CDPlayer类上都加了@Component注解,这个注解表示这个类会作为组件类,并告知Spring要为这个类创建Bean。所以,没必要显示的配置SgtPeppers的bean,Spring知道如何处理。
其实,写完了上边的代码还差一步,就是要告诉Spring要扫描哪个位置的组件。这里需要写一个配置类,这个类可以启用组件扫描。

package soundsystem;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
/*
* 这个类定义了spring的装配规则。
* 在没有其他配置的时候,@ComponentScan注解默认扫描与配置类相同的包,即soundsystem包。所以,这个包下的SgtPeppers就会被扫到了。
* */
@Configuration
@ComponentScan
/*
* 默认情况下,只扫描配置类所在的包,如果我想要扫描更多的包应该怎么做呢?
* @ComponentScan(basePackages = {"soundsystem","video"})    ,参数设置成想要扫的包的数组就可以了
* 为了安全考虑(因为写字符串毕竟会出错),可以使用:
* @ComponentScan(basePackageClasses = {CDPlayer.class,DVDPlayer.class})   ,参数设置成class的数组,这样更安全。
* */
public class CDPlayerConfig {

}

@Configuration注解声明这是一个配置类,它负责定义Spring的装配规则。从代码中可以看到,我们并没有显示的声明任何bean。
@ComponentScan默认会扫描与配置类相同的包。这个配置类与我们之前写的代码在同一个包下,所以,Spring会扫描配置类所在的包和这个包下的所有子包,查找带有@Component的类。这样就能扫到CompactDisc和CDPlayer了。
在上面的代码中,还有一个@Autowired的注解,它表明当Spring创建CDPlayer bean的时候,会对它进行实例化并会传入一个Compactdisc类型的bean。这样,实例之间的依赖关系就满足了。同时@Autowired注解还可以用在任何方法上,例如Setter方法上:

@Autowired
public void setCompactDisc(CompactDisc cd) {
  this.cd = cd;
}

在Spring初始化bean后,会尽可能的去满足bean的依赖。如果没有匹配的bean,Spring会抛异常。
下面是针对上面代码的Test

package soundsystem;

import static org.junit.Assert.*;

import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.junit.contrib.java.lang.system.StandardOutputStreamLog;
/*
* 这个类就是用来测试CompactDisc的bean有没有被生成
* */
@RunWith(SpringJUnit4ClassRunner.class)     //生成spring应用上下文
@ContextConfiguration(classes = CDPlayerConfig.class)   //告诉spring需要在CDPlayerConfig中加载配置
public class CDPlayerTest {

    @Rule
    public final StandardOutputStreamLog log = new StandardOutputStreamLog();

    @Autowired
    private MediaPlayer player;

    @Autowired
    private CompactDisc cd;         //SgtPeppers cd ;  也成立

    //验证自动创建bean功能
    @Test
    public void test(){
        assertNotNull(cd);          //如果不为null表示生成了。
    }

    //验证自动装配功能
    @Test
    public void play() {
        player.play();
        assertEquals("playing Sgt. Pepper's Lonely Hea
rts by The Beatles\n",log.getLog());
    }
}

2. 通过java代码装配bean

在看Spring实战这本书的时候,作者一直在强调在需要进行显示配置的时候,通过JavaConfig是更好的方式,因为,我们要更关注这种方式。
为什么要进行显示配置呢?通过组件扫描和自动装配不是更好吗?因为我们在做工程的时候,经常会遇到第3方的代码,这个时候我们总不能到别人的代码上去加@component和@Autowired吧。
其实,通过java代码显示配置也很简单,在上面我们已经使用过了。

package soundsystem;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
/*
* 这个类定义了spring的装配规则。
* 在没有其他配置的时候,@ComponentScan注解默认扫描与配置类相同的包,即soundsystem包。所以,这个包下的SgtPeppers就会被扫到了。
* */
@Configuration
//@ComponentScan
/*
* 默认情况下,只扫描配置类所在的包,如果我想要扫描更多的包应该怎么做呢?
* @ComponentScan(basePackages = {"soundsystem","video"})    ,参数设置成想要扫的包的数组就可以了
* 为了安全考虑(因为写字符串毕竟会出错),可以使用:
* @ComponentScan(basePackageClasses = {CDPlayer.class,DVDPlayer.class})   ,参数设置成class的数组,这样更安全。
* */
public class CDPlayerConfig {

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

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

    }
}

我们把@ComponentScan注释掉,这样Spring就不会自动创建bean了。然后我们在JavaConfig中声明@Bean,它会告诉Spring这个方法会返回一个对象,该对象要注册为Spring应用上下文的Bean。对于sgtPeppers()就是这样的,它不涉及别的依赖。对于cdPlayer(),它有对CompactDisc的依赖,需要请求一个CompactDisc作为参数,当Spring调用该方法创建CDPlayer bean的时候,会自动装配一个CompactDisc到配置方法中。同时,对于cdPlayer()下面两种方法也是可行的

 @Bean
    public CDPlayer cdPlayer(CompactDisc cd ){
        CDPlayer player = new CDPlayer();
        player.setCd(cd);
        return player;

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

3.通过xml装配Bean

用xml装配Bean与java代码装配Bean思路是一样的。只不过前者是通过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"
        xmlns:context="http://www.springframework.org/schema/context"
        xsi:schemaLocation="http://www.springframework.org/schema/beans
            http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
            http://www.springframework.org/schema/context
            http://www.springframework.org/schema/context/spring-context-3.0.xsd">
<!-- configuration details go here-->
</beans>

上面是配置文件的基本格式,以<beans>为根,在顶部需要声明多个xml模式文件。然后<bean>的配置在里边写
(1) 声明简单<bean>

<bean class="soundsystem.SgtPeppers" />
<bean id="compactDisc" class="soundsystem.SgtPeppers" /> 
<!-- 上面两条语句都相当于JavaConfig中的@Bean注解,用第一条配置时,会给
生成的Bean分配一个默认的Id,在这里就是soundsystem.Sgtpeppers#0,如果
再有一个相同的bean,会分配#1-->
<!--第2条语句是自定义bean ID,为compactDisc,除了id不一样,两者的效果是一样的-->

当Spring发现这个<bean>时,会调用默认的构造器来创建bean。
(2)借助构造器注入初始化bean
实现注入有两种方式:

  • <constructor-arg>元素
<bean id = "cdPlayer" class = "soundsystem.CDPlayer">
  <constructor-arg ref = "compactDisc" />
<!-- ref 后边加的就是bean的id,这是当参数是引用的时候-->
</bean>
<!--当参数是字符串的时候***********-->
<bean id = "cdPlayer" class = "soundsystem.BlankDisc"/>
  <constructor-arg value = "Sgt. Pepper's Lonely Hearts Club Band"/>
  <constructor-arg value = "字符串参数">
<!-- value 后边加的就是具体的字符串-->
</bean>

当构造器参数中某个参数时列表时,只能用<constructor-arg>

<bean id = "cdPlayer" class = "soundsystem.BlankDisc"/>
  <constructor-arg value = "Sgt. Pepper's Lonely Hearts Club Band"/>
  <constructor-arg value = "字符串参数">
  <constructor-arg>
    <list>
        <value>value1</value>
        <value>value2</value>
        <value>value3</value>
    </list>
  </constructor-arg>
<!-- value 后边加的就是具体的字符串-->
</bean>
<!--如果列表中存的是对象的引用的时候-->
<list>
  <ref bean="bean1" />
  <ref bean="bean2" />
  <ref bean="bean3" />
</list>
  • Spring3.0引入的c-命名空间
    使用c-命名空间,要在xml的顶部声明其模式。
    xmlns:c="http://www.springframework.org/schema/c
<bean id="cdPlayer" class="soundsystem.CDPlayer"
      c:cd-ref="compactDisc" />

c:是c-命名空间前缀,cd是构造器参数名,-ref注入bean的引用

c:_0-ref="compactDisc" 表示构造器的第一个参数
c:_1-ref="****"  构造器的第二锅参数
当构造器只有一个参数时,可以是
c:_-ref="param_name"

相关文章

网友评论

      本文标题:Spring装配bean的三种方式

      本文链接:https://www.haomeiwen.com/subject/mpdcpftx.html