之前学习了Spring的简单依赖注入的表现形式,我们知道了依赖注入是通过属性注入以及构造器注入的形式,来达到对象与对象之间的弱关联。那么Spring是如果将对象所依赖的对象Bean注入(装配)到类中的呢?
在Spring中,对象无需自己查找或创建与其所关联的其他对象。相反,容器负责把需要相互协作的对象引用赋予各个对象。例如:一个订单管理组件需要信用卡认证组件,但它不需要自行创建信用卡组件。订单管理组件只需要表明自己两手空空,容器就会主动赋予它一个信用卡认证组件。
创建应用对象之间协作关系的行为通常称为装配(wiring),这也是依赖注入(DI)的本质。接下来让我们见识一下Spring装配Bean的知识。
Spring有多种装配Bean的方式。
- 在XML种进行显示配置;
- 在Java种进行显示配置;
- 隐式的bean发现机制和自动装配;
一、自动装配Bean
首先让我们看看怎么使用Spring实现自动装配bean,在之后再看如何借助Java和XML来进行Spring装配。相比较而言,自动装配比显示装配更加的便利而且容易配置,当然自动装配也有无法替代显示装配的地方:
- 基本数据类型的值、字符串字面量、类字面量无法使用自动装配来注入
- 如果使用了构造器注入和Setter注入,将覆盖自动装配的依赖关系
- 优先考虑显示的装配进m行更精确的依赖注入而不是使用自动装配
Spring从两个角度实现自动装配:
- 组件扫描(componment scanning):Spring会自动发现应用上下文种所创建的bean。
- 自动装配(autowiring):Spring自动满足bean之间的依赖。
通过一段示例程序来了解自动装配:
package soundsystem;
public interface CompactDisc {
void play();
}
我们创建了一个CD播放器的类CompactDisc ,它是一个接口,并且只有一个方法的定义play(),将交由子类去实现
package soundsystem;
import org.springframework.stereotype.Component;
@Component
public class SgtPrppers implements CompactDisc {
private String title = "Sgt. Prpper's Lonely Hearts Club Band";
private String artist = "The Neatles";
public void play() {
System.out.println("Playing " + title + " by " + artist);
}
}
CompactDisc 类实现了CompactDisc 类,并且扩展了play()方法,他会打印出播放的因为的名字标题,除了使用了Spring的@Component注解之外没有其他的代码,就只是一个简单的Bean,Component注解会告诉Spring框架这个类是一个组件,需要被Spring管理起来,让我们看看Spring是怎么将这个Bean管理起来并注入到需要这个类的对象中的!
package soundsystem;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
@Configuration
@ComponentScan
//@ComponentScan("soundsystem")
//@ComponentScan(basePackages = "soundsystem")
//@ComponentScan(basePackages = {"soundsystem"})
/**
* ComponentScan 注解可以通过指定包名设置需要扫描的基础包,
* 也可以直接设置basePackages属性来指定需要被扫描的包的路径(也可以同时指定复数的包的路径,使用","逗号分隔)
*/
public class CDPlayConfig { }
CDPlayConfig 类通过Java的方式向Spring定义了装配的规则,通过使用@Configuration注解告诉Spring框架这是一个配置类,并且使用了@ComponentScan告诉Spring扫描这个类相同的包,将标注了Component注解的类管理起来。
如果希望使用XML的方式配置,则是一下配置的方式。
基于XML的Spring自动扫描配置
<?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> 元素会有与@ComponmentScan注解相同的属性与子元素 -->
<context:component-scan base-package="soundsystem"/>
</beans>
测试:
package soundsystem;
import org.junit.Assert;
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(classes = CDPlayConfig.class)
public class CDPlayTest {
@Autowired
private CompactDisc compactDisc;
@Test
public void testCDPlay(){
//通过断言 判断compactDisc不为null,Spring框架将我们需要的compactDisc对象通过自动装配注入进来
Assert.assertNotNull(compactDisc);
}
public CompactDisc getCompactDisc() {
return compactDisc;
}
public void setCompactDisc(CompactDisc compactDisc) {
this.compactDisc = compactDisc;
}
}