Dagger2自定义@Qualifier用法

假设我正在制造一辆汽车,我有几个不同实施的刹车豆

class Car { @Inject Car(@BrakeType(value="abs")Brake frontBrake, @BrakeType(value="nonabs")Brake rearBrake) { } } @Qualifier @Retention(RetentionPolicy.RUNTIME) public @interface BrakeType { String value(); } interface Brake {} @BrakeType(value="abs") class AbsBrakeImpl implements Brake { @Inject AbsBrakeImpl() {} } @BrakeType(value="nonabs") class BrakeImpl implements Brake { @Inject BrakeImpl() {} } 

为什么我的CarModule必须为特定的制动类型定义@Provides? 自定义注释类型@BrakeType不应该足以确定要注入哪个impl? 或者这需要使用reflection,dagger2不使用?

 @Module public class CarModule { @Provides @BrakeType("abs") public Brake absBrake() { return new AbsBrakeImpl(); } @Provides @BrakeType("nonabs") public Brake nonabsBrake() { return new BrakeImpl(); } } 

Dagger不会在类上查看限定符注释,只能查看@Provides@Binds方法。 所以类上的@BrakeType(value="abs")注释没有任何效果。

编写代码的更规范的方法是:

 class AbsBrakeImpl implements Brake { @Inject AbsBrakeImpl() {} } class BrakeImpl implements Brake { @Inject BrakeImpl() {} } @Module abstract class CarModule { @Binds @BrakeType("abs") abstract Brake absBrake(AbsBrakeImpl impl); @Binds @BrakeType("nonabs") abstract Brake nonabsBrake(BrakeImpl impl); } 

请注意,由于在实现的构造函数上有@Inject ,因此只需使用Dagger的@Bind将实现直接绑定到适当的限定接口即可。

对于记录,您可以使用自己的限定符注释(作为BrakeType),或者只使用Dagger中的@Named。 使用最后一个,您的代码将类似于:

 @Inject @Named("abs") Brake frontBrake; @Inject @Named("nonabs") Brake rearBrake; 

在你的模块上:

 @Provides @Named("abs") static Brake provideAbsBrake() { return new AbsBrakeImpl(); } @Provides @Named("nonabs") static Brake provideNonAbsBrake() { return new BrakeImpl(); } 

请记住使用Dagger名称约定(如提供前缀)来获取大部分内容。 在您的模块上尝试使用所有@Provides方法静态,这样做结果实现不需要实例化它。

简而言之,提供和限定符一起工作,因此您需要两者。


来源: Dagger用户指南 。

@Inject constructor意味着提供一个类本身,在您的情况下,这意味着您提供AbsBrakeImpl类型和BrakeImpl类型,因此当您尝试注入Brake ,dagger无法找到提供者。

@Inject constructor限定符不起作用,因为类类型是唯一的,我们不需要添加限定符。

因此,在您的情况下,或者您必须使用CarModule明确告诉Dagger,或者更改您的构造函数

 class Car { @Inject Car(AbsBrakeImpl frontBrake, BrakeImpl rearBrake) { } } 

反思可能不是一个大问题,因为它会在编译时发生。

我没有查看源代码 ,但是dagger只是一个注释处理器 – 只要使用一组给定的注释,它就会被调用。 虽然单凭限定符可能足以找出你的意图,但我可以想到以下原因,为什么这不是最好的解决方案。

javax.inject.Qualifier是更大的API的一部分,也可能被不同上下文中的其他库使用。 所以你可能不希望匕首为方法生成代码,因为它是用限定符注释的。

另一个原因可能是因为有可能创建自定义限定符,dagger必须检查每个模块中每个方法的每个注释,然后依次确定该注释本身是否使用@Qualifier注释以查看该方法是否属于某些方法它的兴趣。 这是一个不必要的开销。

可能有更多的原因,但这里列出的2个似乎足以让匕首用户使用某种合同: @Provides

注释不会影响代码的性能,并且使用附加注释不会造成任何伤害,因此通过按照它们的方式处理它会有更多的损失。