如何在Jersey 2中禁用依赖注入?

4

我刚开始使用Jersey 2创建REST Web服务。我已经成功地完成了一些简单的案例,现在我要开始进行“真正”的工作。

我创建了自己的ResourceConfig实例,并用Guice返回的REST控制器实例填充了ResourceConfig实例:

<!-- language: lang-java -->
final ResourceConfig rc = new ResourceConfig();

//register an *instance* of a REST controller
rc.register(injector.getInstance(MyRestController.class));

请注意,由于这些REST控制器实例是由Guice提供的,因此这些实例将被填充标有@Inject注释的所有必要依赖项。
然而,当我运行上述代码引导Jersey时,我会看到以下错误:
org.glassfish.hk2.api.UnsatisfiedDependencyException: There was no object available for injection at SystemInjecteeImpl(....

显然,发生的情况是,Jersey 也试图解决 REST 控制器实例上的 @Inject 依赖关系,因为它看到了和 Guice 相同的 @Inject 注释。
我不希望 Jersey 进行任何依赖注入。我认为有从 Jersey 到 Guice 的桥接,但基于此处无法展示的程序要求,我需要自己创建 REST 控制器实例并向 Guice Injector 请求它们。
我的问题是:如何在 Jersey 中禁用依赖注入?
我目前正在使用 javax.inject.Inject 注释。也许我可以改用 com.google.inject.Inject 注释,认为 Jersey 不会查找这些注释。但是,我宁愿关闭 Jersey 中的依赖注入。我该怎么办?
谢谢!
1个回答

2

首先,您的解决方案:

public class GuiceJerseyManualBridge extends io.dropwizard.Application<Configuration> {

    @Override
    public void run(Configuration configuration, Environment environment) throws Exception {
        JerseyEnvironment jersey = environment.jersey();

        // create the Guice env and its dependencies
        Injector i = Guice.createInjector(new AbstractModule() {
            @Override
            protected void configure() {
                Map<String, String> props = new HashMap<>();
                props.put("testme", "Hello World Guice Inject Test");
                Names.bindProperties(binder(), props);
                bind(HelloResource.class).in(Singleton.class);
            }
        });

        // get instance

        HelloResource resourceInstance = i.getInstance(HelloResource.class);
        jersey.register(new AbstractBinder() {

            @Override
            protected void configure() {
                // teach jersey about your guice dependency 
                bind(resourceInstance).to(HelloResource.class);
            }
        });

        jersey.register(HelloResource.class); // register resource - jersey will discover this from the binding
    }

    @Override
    public void initialize(Bootstrap<Configuration> bootstrap) {
        super.initialize(bootstrap);
    }

    public static void main(String[] args) throws Exception {
        new GuiceJerseyManualBridge().run("server", "/home/artur/dev/repo/sandbox/src/main/resources/config/test2.yaml");
    }

    @Path("test")
    @Produces(MediaType.APPLICATION_JSON)
    public static class HelloResource {


        @Inject
        @Named("testme")
        private String testString;

        public HelloResource() {
            System.err.println("I am created now");
        }

        @GET
        @Path("test")
        public String test(String x) {
            return testString;
        }

    }

}

请忽略我的DropWizard设置。它使用Jersey和Guice,因此注册部分是相同的。
您在这里面临两个困境:
1. Jersey DI将尝试注入对象中的字段。这是因为它没有意识到已经有一个对象完成了。它假设必须注入字段。
因此,我上面的解决方案执行以下操作:
将Guice bean绑定到jersey环境。这将使jersey能够找到您创建的bean。由于它绑定到jersey env中,它不会尝试重新初始化bean,而是将其视为完全有效的对象。 为使其工作,您需要将Resource注册为类参数(触发jersey搜索已注册的bean,或者如果需要,则创建一个)。
另一种解决方案是将Injects移动到Constructor中(通常是避免字段注入的良好实践)。因为您注册了一个对象,所以调用构造函数是非法的。因此,jersey不会尝试进行任何注入(因为没有要注入的内容)。
最后,我不知道您的要求如何工作,但您想要做的实际上是手动创建一个Guice-Jersey桥接器。以您演示的方式将您的bean教给jersey正是Guice-Jersey桥接器所做的事情,除了修复所有这些小边缘情况(如您现在看到的情况)之外。强烈建议您实现该桥接器。
该桥接器实际上只是将bean的创建委托给guice。这意味着它将(1)向guice请求一个实例,然后自己创建一个(如果Guice没有返回任何实例)。
希望有所帮助,
祝好!Artur

这个方法可行,谢谢!对于那些正在阅读的人,我的一个快速解决办法是使用 com.google.inject.Inject 注释而不是标准的 javax.inject.Inject 注释。然而,我仍然想要一个基于 Jersey 的解决方案。在我的特定情况下,上面代码中的 JerseyEnvironment 实际上是 ResourceConfig 的一个实例,但所有必要的方法都存在。奇怪的是 Jersey 没有一个禁用 DI 的开关。同时也很奇怪一个类被绑定到了一个实例上;通常情况下是反过来的。无论如何,谢谢! - user3303372
这对于Dagger会怎么样?https://dev59.com/S1UM5IYBdhLWcg3wKNyB - Rinke

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接