【问题标题】:Making business domain objects available to Jersey Servlet Context in embedded Jetty server使业务域对象可用于嵌入式 Jetty 服务器中的 Jersey Servlet 上下文
【发布时间】:2016-05-18 14:04:16
【问题描述】:

使用以下依赖项(Gradle):

  • org.glassfish.jersey.containers:jersey-container-servlet:2.22.2

  • org.eclipse.jetty:jetty-servlet:9.3.2.v20150730

我有一个嵌入式 Jetty 服务器,带有一个 Jersey servlet 容器......像这样......

package mypkg.rest.jersey;

import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.servlet.ServletHolder;
import org.glassfish.jersey.server.ServerProperties;
import org.glassfish.jersey.servlet.ServletContainer;
import se.transmode.tnm.alarm.api.AlarmRetrieval;
import mypkg.rest.RestServer;
import mypkg.rest.jersey.serviceImpl.ModelAdapter;

public class JerseyBasedRestServer implements RestServer {

public static final int INITIALIZE_ON_USE = 0;
private Server server;
private final ServletContextHandler context;
private final ServletHolder servlet;
private final ModelAdapter modelAdapter;

public JerseyBasedRestServer(BusinessObjects businessObjects) {
    this.modelAdapter = new ModelAdapter(businessObjects);  //I want this instance to somehow be available for my ServletContainer to use.

    context = new ServletContextHandler(ServletContextHandler.SESSIONS);
    servlet = context.addServlet(ServletContainer.class, "/*");
    servlet.setInitOrder(INITIALIZE_ON_USE);
    servlet.setInitParameter(ServerProperties.PROVIDER_PACKAGES, "mypackage.jersey.generated.api.service");
    servlet.setInitParameter(ServerProperties.MEDIA_TYPE_MAPPINGS, "json : application/json");
    context.setContextPath("/");
}

private void startServlet() {
    try {
        servlet.start();
        servlet.initialize();
    } catch (Exception e) {
        log.error("Failed to initialize servlet. {}", e.getMessage());
    }
}

@Override
public void init(int port) {
    server = new Server(port);
    server.setHandler(context);
    try {
        server.start();
        server.join();
        startServlet();
    } catch (Exception e) {
        log.error("Failed to start jetty server for rest interface");
    } finally {
        server.destroy();
    }
}

Jersey Container 将运行使用 Swagger 代码生成工具生成的服务器代码和模型

https://github.com/swagger-api/swagger-codegen#getting-started

提供生成的模型 JacksonJsonProviderRestApi 类:

package mypackage.jersey.generated.api.service

Path("/")
public class RestApi  {
   private final RestApiService delegate = new RestApiServiceImpl(); //Integration point of the generated code

   @GET
   @Path("/list/")
   @Consumes({ "application/json" })
   @Produces({ "application/json" })
   public Response retrieveAlarmList(@Context SecurityContext securityContext) throws NotFoundException {
    return delegate.retrieveAlarmList(securityContext);
   }
}

为了集成生成的代码,我们需要自己实现RestApiServiceImpl

ModelAdapter 的工作是将我们的业务对象转换为生成的休息模型。

所以问题是我如何使我们的业务对象的适配器实例,在本例中为 ModelAdapter,它位于 Jersey servlet 上下文的上下文之外,可用于 RestApi 类,或者更确切地说RestApiServiceImpl?

我从过去 24 小时的阅读中了解到,我需要通过 Jetty、Jersey 或其他一些库(Weld 似乎经常出现)使用某种上下文依赖注入,并尝试了 @ 的各种组合987654334@、@Context 等,但得出的结论是我不知道我实际上在做什么......我什至不确定我对这种情况的了解是否足够正确地表达我的问题。

可应要求提供更多信息。

感谢任何帮助。

编辑:在此处添加了指向https://github.com/englishbobster/JersetAndJetty的链接

使用@peeskillets 建议,但仍然无法正常工作。

【问题讨论】:

    标签: dependency-injection jersey jersey-2.0 embedded-jetty


    【解决方案1】:

    让 DI 工作所需的第一件事是AbstractBinder。在这里您可以让您的对象可以被注入。

    class Binder extends AbstractBinder {
        @Override
        protected void configure() {
           bind(modelAdapter).to(ModelAdapter.class);
        }
    }
    

    然后您需要在 Jersey 注册活页夹。最简单的方法是在泽西岛的ResourceConfig 注册。在你的情况下,你没有使用一个。您正在“web.xml”中配置所有内容。为此,您应该查看this post

    如果您想更改配置以使用ResourceConfig,我个人更愿意使用,您可以这样做

    package com.some.pkg;
    
    public class JerseyConfig extends ResourceConfig {
        public JerseyConfig() {
            packages("mypackage.jersey.generated.api.service");
            property(ServerProperties.MEDIA_TYPE_MAPPINGS, "json : application/json");
            register(new Binder());
        }
    }
    

    然后用 Jetty 来配置,就可以了

    servlet.setInitParameter(ServletProperties.JAXRS_APPLICATION_CLASS, 
                             "com.some.pkg.JerseyConfig");
    

    现在您可以摆脱其他两个初始化参数,因为您在 ResourceConfig 中配置它。

    另一种方法,没有任何初始化参数,是做

    ResourceConfig config = new JerseyConfig();
    ServletHolder jerseyServlet = new ServletHolder(ServletContainer(config));
    context.addServlet(jerseyServlet, "/*");
    

    查看最后一个代码 sn-p 的完整示例,here

    现在您几乎可以在泽西岛的任何地方注入ModelAdapter

    在字段中

    @Inject
    private ModelAdapter adapter;
    

    或者在构造函数中

    @Inject
    public RestApi(ModelAdapter adapter) {
        this.adapter = adapter;
    }
    

    或方法参数

    @GET
    public Response get(@Context ModelAdapter adapter) {}
    

    【讨论】:

    • 好的,谢谢您的回复。在我的实验中,我尝试过类似的东西。我刚刚尝试了上面的方法,创建了一个 Binder 和一个资源配置,然后在该字段上使用了注入,但是在使用我的 ModelAdapter 时仍然出现空指针异常。在调试器中查看上下文的最佳方法是什么(如果可能的话)?
    • 顺便说一句,我从未使用 web.xml 进行配置,(害怕 XML)并尝试以编程方式完成所有操作。
    • 它应该注入RestApi就好了。如果您尝试将其注入到服务中,那么您将无法自己实例化该服务。您需要 1) 也将服务与活页夹绑定,以及 2) 注入 服务到 RestApi,不要实例化它
    • OK 让他开始工作。似乎我的 ModelAdapter 的注入必须发生在 RestAPI 中,而不是其他地方。这与我大摇大摆的生成代码和我生成的 RestApi 类中的钩子有很大关系。也与我对 DI 的理解有很大关系。感谢您的帮助。
    猜你喜欢
    • 2013-12-28
    • 1970-01-01
    • 2023-03-20
    • 1970-01-01
    • 1970-01-01
    • 2020-05-18
    • 2012-04-21
    • 2022-08-18
    • 2016-03-18
    相关资源
    最近更新 更多