spring 4.0.2.RELEASE 自动化装配

    xiaoxiao2025-10-10  11

    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)