如何使用Guice

时间:2016-05-27 21:55:37

标签: java dependency-injection guice

我最近一直在攻击Google Guice,我想出了一个想法,根据声明的类和其他几个参数在构造函数中注入一个String。注解。例如: 如果我定义一个由Guice使用的新限定符注释@NamedInjectable

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.FIELD, ElementType.PARAMETER })
@Qualifier
public @interface NamedInjectable
{
    String name() default "";

    boolean indexed() default true;
}

其中name是字符串的新名称基础(默认只是类&#39;名称),indexed表示每次注入新字符串时是否应该递增名称。<登记/> 例如

public MyClass {
    @Inject
    public MyClass(@NamedInjectable(name = "foo", indexed = true) String name) {
        // some code
    }
}

并且name param应该被赋予诸如&#34;之类的值。 我考虑过使用 Provider Bindings AssistedInject ,但我可以完成它。失败的一个主要原因是以某种方式得到了班级的名称。

你还有其他想法吗?

2 个答案:

答案 0 :(得分:3)

没有内置方法可以根据名称自定义标准Guice绑定。如果你想单独坚持Guice,你可能需要Custom Injections

  

除了标准的@Inject驱动注射外,Guice还包括用于定制注射的钩子。这使Guice能够托管具有自己的注入语义或注释的其他框架。大多数开发人员不会直接使用自定义注射;但是他们可能会在扩展和第三方库中看到它们的用途。每个自定义注入都需要一个类型侦听器,一个注入侦听器和每个注册侦听器。

Guice的自定义注入文档示例演示了一个使用注入类类型自定义的记录器实例,这听起来非常像您想要做的事情 - 从TypeListener中读取您创建的注释的参数并不困难。但是,这不能直接与@Inject注释或构造函数一起使用,因此如果您尝试完全在幕后进行注入,则可能会遇到麻烦。

另一种选择更简单:只需使用工厂并传入新构造的类。

public MyClass {
    private final String name;

    @Inject
    public MyClass(NameInjector nameInjector) {
        this.name = nameInjector.get(this, "foo", true);
    }
}

答案 1 :(得分:1)

对于普通的Guice注射,您无法访问注入某物的类的名称。如果您确实需要这样做,则需要使用自定义注入。

通过使用自定义TypeListener,您可以侦听注入事件并了解正在注入的类。在听到注射事件时,您可以注册一个自定义的MembersInjector,Guice将在完成自己的注射后调用。这个MembersInjector可以访问类的完全构造的实例,因此它可以反映字段并检查注释。但是,它显然无法注入构造函数参数,因为该对象已经创建。

简而言之,没有办法自定义注入构造函数参数。但是你描述的想法非常可能用于现场注射!

怎么做

首先,您需要注册TypeListener(此代码基于链接的Guice维基页面):

public class NamedStringListener implements TypeListener {
    public <T> void hear(TypeLiteral<T> typeLiteral, TypeEncounter<T> typeEncounter) {
        Class<?> clazz = typeLiteral.getRawType();
        while (clazz != null) {
             for (Field field : clazz.getDeclaredFields()) {
             if (field.getType() == String.class &&
                 field.isAnnotationPresent(NamedInjectable.class)) {
                     Annotation annotation = field.getAnnotation(NamedInjectable.class);

                     // How you create and configure this provider is up to you.
                     Provider<String> provider = new MyStringProvider(clazz, annotation);
                     typeEncounter.register(new MyMembersInjector<T>(field, provider));
                 }
             }
         clazz = clazz.getSuperclass();
         }
     }
}

然后,在MyMembersInjector<T>内:

public class MyMembersInjector<T> implements MembersInjector<T> {
    final Field field;
    final Provider<String> provider;

    NamedMembersInjector(Provider<String> provider) {
        this.field = field;
        this.provider = provider;
        this.field.setAccessible(true);
    }

    public void injectMembers(T t) {
         field.set(t, provider.get());
    }
}

我将MyStringProvider的实现留给您。

有关详情,请参阅Guice CustomInjections维基页面。