Dagger2自定义@Qualifier用法

问题描述 投票:11回答:4

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

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?或者这需要使用反射,dagger2不使用?

@Module
public class CarModule {
    @Provides @BrakeType("abs")
    public Brake absBrake() {
        return new AbsBrakeImpl();
    }
    @Provides @BrakeType("nonabs")
    public Brake nonabsBrake() {
        return new BrakeImpl();
    }
}
java dagger-2
4个回答
6
投票

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将实现直接绑定到适当的限定接口。


1
投票

对于记录,您可以使用自己的限定符注释(作为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 users guide


1
投票

@Inject constructor意味着提供类本身,在你的情况下,这意味着你提供AbsBrakeImpl类型和BrakeImpl类型,所以当你尝试注入Brake时,匕首无法找到提供者。

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

所以,在你的情况下,或者你必须使用CarModule明确地告诉Dagger,或者改变你的构造函数

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

0
投票

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

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

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

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

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

注释不会影响代码的性能,并且具有额外的注释不会造成任何伤害,因此通过以它们的方式处理它而获得的收益远远超过丢失。

© www.soinside.com 2019 - 2024. All rights reserved.