Java7技术系列:DI依赖注入

Java7技术系列:try-with-resource
Java7技术系列:int与二进制的转换优化
Java7技术系列:MultiCatchException
Java7技术系列:NIO.2异步IO
Java7技术系列:DI依赖注入
Java7技术系列:Queue
Java7技术系列:Java并发

1 依赖注入介绍

javax.inject:这个包指明了获取对象的一种方式,与传统的构造方法、工厂模式和服务器定位模式等相比,这种方式的可重用性、可测试性和可维护性都得到了极大提升。这种方式称为依赖注入,对于大多数非小型应用程序都很有帮助。

javax.inject 包里包括一个 Provider<T> 接口和5个注解类型(@Inject、@Qualifier、@Named、@Scope和@Singleton)

2 @Inject

@Inject 注解可以出现在三种类成员之前,表示该成员需要注入依赖项。按运行时的处理顺序,这三种类型是:

  • 构造器

  • 方法

  • 属性

在构造器上使用@Inject 时,其参数在运行时由配置好的Ioc容器提供。

规范中规定向构造器或方法中注入的依赖项为0个或多个,所以在没有参数的构造器或方法中添加注解是合法的。

注意:因为JRE无法决定构造器注入的优先级,所以规范中规定类中只能有一个构造器用@Inject注解。

构造器注入Header和Content

@Inject public MurmurMessage(Header header, Content content) {
	this.header = header;
        this.content = content;
}

注意:使用注入的方法不能声明为抽象方法,也不能声明其自身的类型参数。

方法注入

@Inject public void setContent(Content content) {
	this.content = content;
}

向构造器中注入的通常是类中必须的依赖项,而对于非必需的依赖项,通常是在set方法上注入。

比如已经给出了默认值的属性就是非必需的依赖项。该实践已经成了惯例。

在属性上注入虽然简单直接,但最好不好用。因为会让单元测试更加困难。

@Inject private MurmurMessage murmurMessage;

3 @Qualifier

支持JSR-330(标准注解规范)的框架要用注解 @Qualifier 限定要注入的对象。比如在Ioc容器中有两个类型相同的对象,需要把它们区分开。

创建一个@Qualifier实现必须遵循如下规则:

  • 必须标记为@Qualifier和@Rentetion(RUNTIME),以确保该限定注解在运行时一直有效。

  • 通常还应该击伤@Documented注解,这样该实现就能加入到API的公共javadoc中。

  • 可以有属性。

  • @Target注解可以限定其使用范围:比如将其使用范围限定为属性,而不是限定为属性的默认值和方法中的参数。

给音乐库框架提供限定符@MusicGenre

@Documented
@Rentention(RUNTIME)
public @interface MusicGenre {
     Genre genre() default Genre TRANCE;
     public enum GENRE { CLASSICAL, METAL, ROCK, TRANCE }
}
public class MetalRecordAlbums {
     @Inject @MusicGenre(GENRE.METAL) Genre genre;
}

4 @Named

JSR-330规范中要求所有Ioc容器都要提供一个默认的@Qualifier注解:@Named

@Named 是一个特别的@Qualifier注解,借助@Named可以用名字标明要注入的对象,与@Inject一起使用,符合指定名称并且类型正确的对象会被注入。

public class MurmurMessage {
     @Inject @Named("murmur") private MurmurMessage murmurMessage;
     @Inject @Named("broadcast") private MurmurMessage broadcastMesssage;
}

5 @Scope

@Scope 注解用于定义注入器(即IoC容器)对注入对象的重用方式。JSR-330规范中明确了如下几种默认行为:

  • 如果没有声明任何@Scope注解接口的实现,注入器应该创建注入对象并且仅使用该对象一次。

  • 如果声明了@Scope注解接口的实现,那么注入对象的生命周期由所声明的@Scope注解实现决定。

  • 如果注入对象在@Scope实现中要由多个线程使用,则需要保证注入对象的线程安全性。

  • 如果某个类上声明了多个@Scope注解,或声明了不受支持的@Scope注解,IoC容器应该抛出异常

6 @Singleton

@Singleton 注解接口在DI框架中应用广泛,在需要注入一个不会改变的对象时,就要用到@Singleton。

大多数DI框架都将@Singleton作为注入对象的默认生命周期,无需显式声明,框架会认为你向注入一个单例对象。

public MurmurMessage {
     @Inject @Singleton MessageHeader defaultHeader; // 显式声明为单例对象(切实有效的静态数值)
}

7 Provider接口

想对由DI框架注入代码中的对象拥有更多的控制权,可以要求DI框架将Provider接口实现注入该类,控制对象的好处在于:

  • 可以获取该对象的多个实例

  • 可以延迟获取该对象(延迟加载)

  • 可以打破循环依赖

  • 可以定义作用域,能在比整个被加载的应用小的作用域中查找对象
    该接口仅有一个 T get()方法,返回一个构造好的注入对象(T)

class MurmurMessage {
     @Inject MurmurMessage(Provider<Message> messageProvider) {
             Message meg1 = messageProvider.get();
             if (someGlobalCondition) {
                 // 如果直接注入Message,则无法获取另外一个Message实例
                 Message copyOfMsg1 = messageProvider.get(); // 获取第二个Message对象
             }
      }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值