Spring从两个角度实现了自动化装配:
组件扫描(component scanning):Spring会自动扫描上下文中所创建的bean
自动装配(autowiring):Spring自动满足bean之间的依赖
以音乐专辑为例,一张音乐专辑(CD)需要一个CD播放器才能放出音乐,在这期间需要将CD插入(注入)CD播放器中才能达到我们想要的效果,而这个CD与CD播放器之间的依赖关系能够生动的向我们阐述DI是如何运行的。
这里的@Component注解是标识这个类为组件类并告知Spring为其创建bean对象。与以往不同的是不需要再xml中显示的配置bean,Spring会根据你所做的标识来完成配置工作。
Spring会根据注解来扫描指定包中需要创建bean对象的类,但Spring的组件扫描默认是不启动的,所以我们还需要进行一些配置,来启用组件扫描。
启用组件扫描有两种方式,一种是以java注解的形式启用,另外一种则是在xml中配置启用
在用两种配置方法配置之后,我们来测试一下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加一下依赖就好了)
我们假设一种情况:如果有两个实体类实现了同一个接口类,那么在依赖注入的时候会出现冲突因为@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 { }创建__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方法。
Done!
