如何让 HK2 像 Guice 一样注入未明确配置的 类?

How do I make HK2 act like Guice for injecting classes that weren't configured explicitly?

我有一个项目使用 Jersey 2.25 (with HK2 2.5-b30). Originally, I was using the HK2-Guice Bridge。但是,这在某些情况下似乎会意外失败(特别是,当 Guice 进行注入时,使用 Guice 中配置的自定义注释对字符串进行注释的情况将正常工作,但在 HK2 进行注入时会静默失败)。因为同一个对象可能会根据注入方式的不同而有所不同,所以我越来越害怕同时使用两者。

我现在正在切换一切以使用 HK2,但遗憾的是,对于某些 Guice 会成功的情况,HK2 似乎失败了。特别是,HK2 似乎不喜欢在未明确配置类型的地方注入。 Guice 很乐意为这些 classes 创建一个新实例并递归注入,但 HK2 就没那么多了。例如,

1. org.glassfish.hk2.api.UnsatisfiedDependencyException: There was no object available for injection at SystemInjecteeImpl(requiredType=TimeRangeRequestValidator,parent=GetWatchlistEventsImpl,qualifiers={},position=-1,optional=false,self=false,unqualified=null,1218743359)

如您所见,错误消息一点用处都没有。它应该能够创建一个 TimeRangeRequestValidator,它引用了一些其他对象,Guice 能够毫无问题地创建所有这些对象。 HK2 和 Guice 之间是否有一些不同行为的列表,以便我可以查明为什么这不起作用?

请注意,TimeRangeRequestValidator 是一个 class(不是接口),用 @Singleton 注释,它有一个默认的 public 构造函数和一个用 [=15= 注释的字段]. Guice 在实例化它时没有问题。

a few extra steps you need 配置 HK2 自动填充您的服务:

  1. 确保您已使用 @Contract 注释您的接口并使用 @Service
  2. 注释您的实现
  3. 您需要在构建过程中 运行 HK2 Metadata Generator。这会生成 HK2 在 运行 时需要的服务文件,以确定 类 实现哪些合约接口。
  4. 使用 ServiceLocatorUtilities.createAndPopulateServiceLocator() 检索 ServiceLocator 个实例。

请注意,具体细节或它如何为您工作取决于您使用的框架(例如球衣)。参见 Using HK2 with Jersey

你也可以使用贪心JustInTimeResolver。我在下面写了一个:

@Singleton
@Visibility(DescriptorVisibility.LOCAL)
public class GreedyResolver implements JustInTimeInjectionResolver {
    private final ServiceLocator locator;

    @Inject
    private GreedyResolver(ServiceLocator locator) {
        this.locator = locator;
    }

    @Override
    public boolean justInTimeResolution(Injectee failedInjectionPoint) {
        Type type = failedInjectionPoint.getRequiredType();
        if (type == null) return false;

        Class<?> clazzToAdd = null;
        if (type instanceof Class) {
            clazzToAdd = (Class<?>) type;
        }
        else if (type instanceof ParameterizedType) {
            Type rawType = ((ParameterizedType) type).getRawType();
            if (rawType instanceof Class) {
                clazzToAdd = (Class<?>) rawType;
            }
        }

        if (clazzToAdd == null) return false;
        if (clazzToAdd.isInterface()) return false;

        ServiceLocatorUtilities.addClasses(locator, clazzToAdd);
        return true;
    }

}

您在使用上述解析器时应该小心,因为它会向您的 ServiceLocator 添加您可能没有预料到的内容。它也可能不会很好地注入诸如字符串或其他类似类型的东西。不过,可能适用于您的用例。

如果您的注入点正在注入一个接口,将不起作用!