java - 吉斯。如何在父类的一个字段中注入(inject)不同的对象?

标签 java guice

我在 Guice 字段注入(inject)方面遇到问题。考虑遵循类的层次结构。

abstract class Base{
    @Inject
    protected MyService myService;
}

class A extends Base{
    @Inject
    private AnotherService anotherService;
 }

class B extends Base{
   ...
}

我希望在运行时有两个不同的 MyService 实例 - 一个用于注入(inject) A 类的所有对象,另一个用于 B 类的对象。 我知道如何通过构造函数注入(inject)来实现该行为:

  bind(MyService.class).annotatedWith(Names.named("forA")).to(MyServiceImpl.class).in(Singleton.class);
  bind(MyService.class).annotatedWith(Names.named("forB")).to(MyServiceImpl.class).in(Singleton.class);

  class A extends Base{
    @Inject @Named(value = "forA")
    public A(MyService service1, AnotherService service2) {
      this.myService = service1;
      this.anotherService = service2;
    }

问题是迁移到构造函数注入(inject)会非常复杂,所以我想坚持使用字段注入(inject)。 是否可以像我想要的那样调整场注入(inject)?

最佳答案

我会使用Custom Injections来自 Guice 来实现这一点。

首先,我将创建一个注释来注释我想要根据父类(super class)类型注入(inject)的 MyService。

@BindingAnnotation
@interface MyServiceInject {
}

然后我将使用注释来注释我的 MyService 字段。

static abstract class Base {

    @MyServiceInject
    protected MyService myService;
}

现在我们需要一个自定义的TypeListener,每次遇到注入(inject)点时都会调用它。

这就是我们创建它的方式。

static class ClassBasedMyServiceInjectionListener implements TypeListener {

    @Override
    public <I> void hear(TypeLiteral<I> typeLiteral, TypeEncounter<I> encounter) {
        Class<?> clazz = typeLiteral.getRawType();

        while (clazz != null) {
            for (Field field : clazz.getDeclaredFields()) {
                if (field.getType() == MyService.class && field.isAnnotationPresent(MyServiceInject.class)) { //if type of field is MyService and it has MyServiceInject annotation
                    encounter.register(new ClassBasedMyServiceInjector<>(field,
                                    typeLiteral.getType(),
                                    encounter.getProvider(MyServiceA.class),
                                    encounter.getProvider(MyServiceB.class)
                            )
                    ); //Now register a MemberInjector for this encounter.
                }
            }
            clazz = clazz.getSuperclass();
        }
    }
}

现在我们需要如下所示的 MemberInjector。

static class ClassBasedMyServiceInjector<T> implements MembersInjector<T> {

    private final Field field;
    private final Type superClassType;
    private final Provider<MyServiceA> myServiceAProvider;
    private final Provider<MyServiceB> myServiceBProvider;

    ClassBasedMyServiceInjector(Field field, Type superClassType, Provider<MyServiceA> myServiceAProvider, Provider<MyServiceB> myServiceBProvider) {
        this.field = field;
        this.superClassType = superClassType;
        this.myServiceAProvider = myServiceAProvider;
        this.myServiceBProvider = myServiceBProvider;

        field.setAccessible(true);
    }

    public void injectMembers(T t) { //this will be called when guice wants to inject members
        try {
            if (superClassType == A.class) {//if super class is of type A
                field.set(t, myServiceAProvider.get()); //inject MyServiceA
            } else if (superClassType == B.class) { //if super class is of type B
                field.set(t, myServiceBProvider.get()); //inject MyServiceB
            }
        } catch (IllegalAccessException e) {
            throw new RuntimeException(e);
        }
    }
}

最后,我将像这样在模块的配置方法中绑定(bind)我们的自定义 TypeListener

    @Override
    protected void configure() {
        bindListener(Matchers.any(), new ClassBasedMyServiceInjectionListener());
    }

希望这有帮助。

关于java - 吉斯。如何在父类的一个字段中注入(inject)不同的对象?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60401037/

相关文章:

java - 使用AOP和Guice 3在第三方代码中将 `new Socket()`重新定义为 `new Bar()`?

java - 从 guiceModule 访问 dropwizard Bundle 实例

java - 控制java调度算法

java - Wicket 口 6 中的异常处理进入反馈面板

java - 使用 fork ="yes"forkmode ="perTest"运行 junit 的 Ant 脚本不会创建单独的虚拟机

java - Guice 在急切的单例中命名注入(inject)

java - 使用 ReplicationDriver 在 mysql slave 上调用存储过程

java - 生成一个 'special matrix'

java - gwt 使用 guice - 引导或部署时发生的情况

java - 使用 Guice 将参数传递给构造函数