1 依赖注入

Wu Jun 2018-12-18 21:53:15
06 Spring > 02 IoC

IoC 负责装配 Bean,即创建应用对象之间协作关系,是依赖注入(DI,Dependency injection)的本质。

装配方式优先级:自动装配 > Java 配置文件 > XML 配置文件

1 自动装配

Spring 容器可以自动配置相互协作 beans 之间的关联关系。这意味着 Spring 可以自动配置一个 bean 和其他协作 bean 之间的关系。

Spring 从两个角度来实现自动装配

1.1 组件扫描

Spring 自动发现 ApplicationContext 中所创建的 bean

1)@Component

让 Spring 为类自动创建 bean,默认 ID 是类名称的首字母小写。也可给注解传入指定的参数指定名字。

@Component  
@Component("lonelyHeartsClub")

还有 @Repository、@Service、@Controller 等

2)@ComponentScan

开启 Component 扫描,默认设置该目录以及子目录下所有被 @Component 注解修饰的类。也可指定扫描的包。

@ComponentScan("soundsystem")//扫描指定包  
@ComponentScan(basePackages = "soundsystem")
@ComponentScan(basePackages = {"soundsystem", "video"})
@ComponentScan(basePackageClasses = {CDPlayer.class, DVDPlayer.class})//扫描指定类所属的包

1.2 自动装配

Spring 自动满足 bean 之间的依赖

@Autowired:声明自动装配,可用在构造器、方法、成员变量上。

只要对应类型的 bean 有且只有一个,则会自动装配。推荐通过构造器注入以避免 NullPointerException 问题。

1)注入到 Java 集合类

@Autowired 可直接将接口的实现 Bean 注入到如下几种类型的集合中

@Autowired
private List<BeanInterface> list;
@Autowired
private Map<String,Interface> map;

application.properties

table-info.list[0]=list_value1
table-info.list[1]=list_value2
table-info.map.map_key1=map_value1
table-info.map.map_key2=map_value2
table-info.maplist.map_key1[0]=maplist_value1
table-info.maplist.map_key1[1]=maplist_value2
table-info.maplist.map_key2[0]=maplist_value3

TableConfig

@ConfigurationProperties(prefix = "table-info")
public class TableConfig {
    private List<String> list;
    private Map<String, String> map;
    private Map<String, List<String>> maplist;
}
2)允许 null 值

默认要求依赖对象必须存在,如允许 null 值,可设置 @Autowired(required=false)

还有 @Resource 等

3)推荐对构造函数进行注释

@Autowired
private EnterpriseDbService service;

改为

private final EnterpriseDbService service;

@Autowired
public EnterpriseDbController(EnterpriseDbService service) {
    this.service = service;
}

可以明确成员变量的加载顺序

2 Java 配置文件

想要装配第三方库中的组件时,因为没办法在它的类上添加 @Component 和 @Autowired 注解,不能自动化配置,必须要采用显式装配。

2.1 创建配置类

@Configuration:表明是配置类

2.2 声明 bean

@Bean:声明 bean,需编写方法创建所需类型实例, 注解 @Bean。默认 ID 是方法名,也可通过 name 属性指定名字。

@Bean(name = "lonelyHeartsClub")
public CompactDisc sgtPeppers() {
    return new SgtPeppers();
}

2.3 装配 bean

在 JavaConfig 中装配 bean 的最简单方式就是引用创建 bean 的方法。

默认情况下,Spring 中所有的 bean 都是单例模式,Spring 会拦截 @Bean 注解的函数调用,并返回之前创建好的 bean。

@Bean
public CDPlayer cdPlayer() {
    return new CDPlayer(sgtPeppers());
}

3 XML 配置文件

维护已有的 XML 配置, 在完成新的 Spring 工作时, 使用自动化配置和 JavaConfig。

创建一个 XML 文件, 并且以 元素为根。使用 元素声明 bean 并指定 class 属性。 元素注入构造器

可以同时使用两种方式的依赖注入,最好的选择是使用构造器参数实现强制依赖注入,使用 setter 方法实现可选的依赖关系。

3.1 set 注入

首先容器会触发一个无参构造函数或无参静态工厂方法实例化对象,之后容器调用 bean 中的setter 方法完成 Setter 方法依赖注入。

private OrderServiceImp orderService;
public void setOrderService(OrderServiceImp orderService) {
    this.orderService = orderService;
}

Spring 配置 XML 文件:其中配置声明 OrderAction 类存在属性 orderService。程式运行时候,会将已经实例化的 orderService 对象调用 setOrderService 方式注入。

<bean name="orderAction" class="com.pec.action.OrderAction">
    <property name="orderService" ref="orderService"></property>
</bean>
<bean name="orderService" class="com.pec.service.imp.OrderServiceImp"></bean>

3.2 构造器注入

构造器依赖注入在容器触发构造器的时候完成,该构造器有一系列的参数,每个参数代表注入的对象。

private OrderServiceImp orderService;
public OrderAction(OrderServiceImp orderService) {
    this.orderService = orderService;
}

Spring 配置 XML 文件

<bean name="orderAction" class="com.pec.action.OrderAction">
    <constructor-arg ref="orderService"></constructor-arg>
</bean>
<bean name="orderService" class="com.pec.service.imp.OrderServiceImp"></bean>

4 多种配置方法混用

通常的做法是:无论使用 JavaConfig 或者 XML 装配,都要创建一个 root configuration;并且在这个配置文件中开启自动扫描机制

4.1 JavaConfig 中引用

@Import({CDPlayerConfig.class, CDConfig.class})
@ImportResource("classpath: cd-config.xml")

4.2 XML 配置中引用

标签引入其他的 XML 配置文件

<import resource="classpath:/spring/calculate-web.xml"/>

标签导入 Java 配置文件

<bean class="soundsystem.CDConfig" />