Spring装配Bean

Sping通过容器来管理javaBean,既然Spring要管理Bean那我们日常使用中接触的无非就是一个“放”,和一个“取”了。通常把Bean放入Spring容器叫做注册,注册有两种方式

  1. 组件扫描
  2. 显示配置

下面分别介绍两种方式。

1.组件扫描

首先创建一个CD播放器接口

/**
 * 光碟机,CD
 * @author: XuWei
 * @date: 2018年2月27日 
 */
public interface CompactDisc {
    void play();
}

然后是一个具体实现类,音乐播放器

/**
 * 音乐播放器 
 * @author: XuWei
 * @date: 2018年2月27日 
 */
@Component
public class MusicDisc implements CompactDisc {
    private String music="菊花台";
    /**  
     * @see com.xu.CompactDisc#play() 
     */
    @Override
    public void play() {
        System.out.println(music);
    }
}

@Component 是Spring扫描类时识别的注解,凡是打了这个注解的类,都会被注册到Sprign容器中。同理@Service @Controller @Repository是供Spring识别注册。

1.1.基于xml配置的组件扫描

这种方式应该说是使用最广泛的方式了
在Spring配置文件配置一个扫描器,扫描指定包下的类

<context:component-scan base-package="com.xu" />

测试一下

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath*:/applicationContext.xml")
public class CDTest {
    @Autowired
    private CompactDisc compactDisc;
    @Test
    public void DITest1(){
        assertNotNull(compactDisc);
    }
}
  • @RunWith(SpringJUnit4ClassRunner.class)意思是要在测试开始前创建Spring上下文。
  • @ContextConfiguration(“classpath*:/applicationContext.xml”)加载的配置文件。
  • assertNotNull是org.junit.Assert的静态方法,利用静态导报引入:import static org.junit.Assert.*;

如果compactDisc成功注入,通过测试。

1.2.基于java的组件扫描

@Configuration
@ComponentScan
public class CDConfig {

}
  • @Configuration表示这个类是个配置类
  • @ComponentScan这个注解的作用是启用Spring的组件扫描,扫描范围是这个类的所在包以及它的子包但是如果想扫描别的包怎么办?在后边加上扫描路径的报名,类似于@ComponentScan(“com.sk”)如果扫描多个包呢?@ComponentScan(basePackages ={“com.sk”,”com.sk”})或@ComponentScan(basePackageClasses = {MusicDisc.class, Printer.class})

扫描配置有一个缺陷:外部引入的类可能没办法打@Component注解。这时就需要显示把javaBean显示的配置到Spring容器中

2.显示配置

显示配置一般用于注入三方库中的bean,所以现在的MusicDisc没有@Component,类似于这样

public class MusicDisc implements CompactDisc {
    private String music;
        public MusicDisc() {
        super();
    }

    public MusicDisc(String music) {
        super();
        this.music = music;
    }

    public String getMusic() {
        return music;
    }

    public void setMusic(String music) {
        this.music = music;
    }
    /**  
     * @see com.xu.CompactDisc#play() 
     */
    @Override
    public void play() {
        System.out.println(music);
    }
}

2.1.基于xml的显示配置

<bean id="compactDisc" class="com.xu.MusicDisc"></bean>

这个id就是要注册到Spring容器中的Bean的id,class里填写具体实现类。

2.1.1.构造方法属性设置

    <bean id="compactDisc" class="com.xu.MusicDisc">
        <constructor-arg name="music" value="成都"></constructor-arg>
    </bean>

2.1.2.set方法属性设置

确保有该属性有set方法

    <bean id="compactDisc" class="com.xu.MusicDisc">
        <property name="music" value="音乐"></property>
    </bean>

2.1.3List注入

如果属性是List呢?

<!--构造器-->
    <bean id="compactDisc" class="com.xu.MusicDisc">
        <constructor-arg>
            <list>
                <value>音乐1</value>
                <value>音乐2</value>
                <value>音乐3</value>
            </list>
        </constructor-arg>
    </bean>

<!--属性-->
<bean id="compactDisc" class="com.xu.MusicDisc">
        <property name="music">
            <list>
                <value>音乐1</value>
                <value>音乐2</value>
                <value>音乐3</value>
            </list>
        </property>
    </bean>

2.2.基于java的显示配置

@Configuration
public class CDConfig {
    @Bean
    public CompactDisc musicDisc(){
        List<String> musics = new ArrayList<>();
        musics.add("音乐一");
        musics.add("音乐二");
        musics.add("音乐三");
        return new MusicDisc(musics);
    }
}

核心就是写一个方法,打上@Bean注解,然后new一个实例返回。可见,在创造这个实例时比基于xml的配置有更大的灵活性。创建的bean id就是方法名musicDisc

如果要配置一个依赖了其他类的类呢?比如说现在有一个电影cd ,依赖了音乐cd

/**
 * 音乐播放器 
 * @author: XuWei
 * @date: 2018年2月27日 
 */
public class MusicDisc implements CompactDisc {
    private String music = "菊花台";

    /**  
     * @see com.xu.CompactDisc#play() 
     */
    @Override
    public void play() {
        System.out.println(music);
    }
}


/**
 * 电影播放器 
 * @author: XuWei
 * @date: 2018年2月28日 
 */
public class MovieDisc implements CompactDisc {
    private MusicDisc musicDisc;
    public MovieDisc(MusicDisc musicDisc) {
        super();
        this.musicDisc = musicDisc;
    }
    public MovieDisc() {
        super();
    }
    /**  
     * @see com.xu.CompactDisc#play() 
     */
    @Override
    public void play() {
        musicDisc.play();
    }
}

这时配置类要这样写

@Configuration
public class CDConfig {
    @Bean
    public CompactDisc musicDisc(){
        return new MusicDisc();
    }
    @Bean
    public CompactDisc movieDisc(){
        return new MovieDisc((MusicDisc)musicDisc());
    }
}

创建MovieDisc,时构造方法调用了musicDisc()。该方法执行前会被Spring拦截,由于musicDisc已经存在于Spring容器中,所以Spring会直接把容器中的muiscDisc注入进来,并不会重新new一个新的实例。上面的代码也可以这样写:

@Bean
    public CompactDisc movieDisc(CompactDisc musicDisc){
        return new MovieDisc((MusicDisc)musicDisc);
    }

声明成方法的参数,Spring会自动注入实例。
测试一下,看看MusicDisc和MovieDisc是否被注册到Spring容器中。

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes=CDConfig.class)
public class CDTest {
    @Autowired
    @Qualifier("musicDisc")
    private CompactDisc compactDisc;

    @Autowired
    @Qualifier("movieDisc")
    private MovieDisc movieDisc;
    @Test
    public void DITest1(){
        assertNotNull(compactDisc);
        assertNotNull(movieDisc);
    }
}

因为CompactDisc接口在Spring容器中有两个具体的实现MusicDisc和MovieDisc。所以需要给Spring明确注入哪个。@Qualifier(“movieDisc”)就是这个作用。否则会报一个Unsatisfied dependency expressed through field 'compactDisc'; nested exception is org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'com.xu.CompactDisc' available: expected single matching bean but found 2: musicDisc,movieDisc的错误。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值