spring 4.0.2.RELEASE 自动化装配

spring 4.0.2.RELEASE 自动化装配

Spring从两个角度实现了自动化装配:

组件扫描(component scanning):Spring会自动扫描上下文中所创建的bean

自动装配(autowiring):Spring自动满足bean之间的依赖

创建可被发现的bean

音乐专辑为例,一张音乐专辑(CD)需要一个CD播放器才能放出音乐,在这期间需要将CD插入(注入)CD播放器中才能达到我们想要的效果,而这个CD与CD播放器之间的依赖关系能够生动的向我们阐述DI是如何运行的。

首先我们要定义一个CD的概念:创建接口类Disc
package demo;

public interface IDisk {
    public void play();
}
根据这个接口类声明一个带有@Component注解的实现类fristAlbum
package demo.impl;

import demo.IDisk;
import org.springframework.stereotype.Component;

@Component
public class firstAlbum implements IDisk {
    private static String songTitle = "first song";
    private static String artist = "carl";
    public void play() {
        System.out.println("Playing " + songTitle + "by " + artist);
    }
}

这里的@Component注解是标识这个类为组件类并告知Spring为其创建bean对象。与以往不同的是不需要再xml中显示的配置bean,Spring会根据你所做的标识来完成配置工作。

Spring会根据注解来扫描指定包中需要创建bean对象的类,但Spring的组件扫描默认是不启动的,所以我们还需要进行一些配置,来启用组件扫描。

启用组件扫描

启用组件扫描有两种方式,一种是以java注解的形式启用,另外一种则是在xml中配置启用

java注解启用
package demo.impl;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

@Configuration
@ComponentScan
public class CDPlayerConfig {
       
}
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.xsd
                           http://www.springframework.org/schema/context
                           http://www.springframework.org/schema/context/spring-context.xsd">

    <context:component-scan base-package="demo.impl"/>

</beans>

在用两种配置方法配置之后,我们来测试一下Spring是否能够扫描到注解配置过得实现类,这里编写测试用例来测试一下。

package demo.demoTest;

import demo.IDisk;
import demo.impl.CDPlayerConfig;
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;

@RunWith(SpringJUnit4ClassRunner.class)
//@ContextConfiguration(locations = "classpath:applicationContext.xml")
@ContextConfiguration(classes = CDPlayerConfig.class)
public class demoTest {

    @Autowired
    private IDisk disk;

    @Test
    public void run(){
        disk.play();
    }
}

注释掉的一行就是测试xml配置的注解,@Autowired注解则是让Spring创建的bean注入到disk对象中,由此来验证是否扫描成功。(这里使用了spring-test包,maven加一下依赖就好了)

为被扫描的bean命名

我们假设一种情况:如果有两个实体类实现了同一个接口类,那么在依赖注入的时候会出现冲突因为@Autowired是根据类型注入的,这时候有两个相同类型的bean要注入那必然会出现冲突。这里就需要对bean进行命名,我们创建一个新的实体类secondAlbum并依旧使用@Conponent 注解,只是这回要为它加上参数

package demo.impl;

import demo.IDisk;
import org.springframework.stereotype.Component;

@Component("secondAlbum")
public class secondAlbum implements IDisk {
    private static String title = "second song";
    private static String artist = "carl";
    public void play() {
        System.out.println("Playing "+ title + " by " + artist);
    }
}

这样就可以在注入的时候根据名称判断需要注入的是哪个bean,对测试用例进行以下修改

public class demoTest {

    @Autowired
    @Qualifier("secondAlbum")
    private IDisk disk;

    @Test
    public void run(){
        disk.play();
    }
}

或者

public class demoTest {

    @Resource(name = "secondAlbum")
    private IDisk disk;

    @Test
    public void run(){
        disk.play();
    }
}

这里要提一句的是,@Autowired要和@Qualifier一起用才能达到ByName的目的,因为Autowired是负责ByType注入的,然后Qualifier再根据Name选择注入哪个Bean,从而实现对应Name注入需要的Bean。

另一种方法使用了@Resource注解,这个注解用于将一个_named bean_注入。当然,可以同时限定_name_和_type_来保证注入的bean是需要的bean。

设置多个扫描包或指定扫描类

使用@ComponentScan注解默认是扫描当前包下的所有组件,当然按照需要也可以设置多个扫描包或者扫描类,@ComponentScan注解提供了两个参数,分别是__basePackages__和__basePackageClasses__,前者需要字符串类型的数组作为参数,后者测需要class类型的数组

package demo.impl;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

@Configuration
@ComponentScan(basePackages = {"demo.impl","demo.demoTest"})
//@ComponentScan(basePackageClasses = {demo.impl.firstAlbum.class})
public class CDPlayerConfig {

}
通过为bean添加@Component注解实现自动注入

创建__MediaPlayer__接口类

package demo;

public interface MediaPlayer {

    public void play();

}

创建__CDPlayer__类并实现MediaPlayer接口

package demo.impl;

import demo.IDisk;
import demo.MediaPlayer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;

@Component
public class CDPlayer implements MediaPlayer {

    @Autowired
    @Qualifier("secondAlbum")
    private IDisk disk;

    public void play() {
        disk.play();
    }
}

__@Autowired__注解同样可以作用于set方法和构造方法上

    //构造方法使用@Autowired
    @Autowired
    public CDPlayer(@Qualifier("firstAlbum")IDisk disk){
        this.disk = disk;
    }
    //set方法使用Autowired
    @Autowired
    @Qualifier("firstAlbum")
    private void setDisk(IDisk disk){
        this.disk = disk;
    }

这里注意,@Resource不适用于构造方法和set方法。

测试自动化装配
package demo.demoTest;

import demo.IDisk;
import demo.MediaPlayer;
import demo.impl.CDPlayerConfig;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import javax.annotation.Resource;

@RunWith(SpringJUnit4ClassRunner.class)
//@ContextConfiguration(locations = "classpath:applicationContext.xml")
@ContextConfiguration(classes = CDPlayerConfig.class)
public class demoTest {


    @Autowired
    private MediaPlayer mediaPlayer;

    @Test
    public void run(){
        mediaPlayer.play();
    }
}

Done!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值