HK2: привязка к реализации интерфейса с использованием немедленной области видимости - PullRequest
6 голосов
/ 11 октября 2019

Я создаю приложение, которое будет работать на Jetty Server. Мой основной класс расширен от ResourceConfig, чтобы запустить параметр инициализации "javax.ws.rs.Application" для этого класса. Я также использовал ServiceLocator для возврата экземпляров службы по требованию;также использовал AbstractBinder для связывания класса с областью Singleton & Immediate.

Мой код класса ResourceConfig, связанный с внедрением зависимостей, выглядит следующим образом:

public class MyServer extends ResourceConfig {

    @Inject
    public MyServer() {
      packages("My.REST");
    }

    public static void main(String[] args) {

    final Server server = new Server(MythreadPool);

    HttpConfiguration httpConfig = new HttpConfiguration();
    httpConfig.addCustomizer(new ForwardedRequestCustomizer());
    ServerConnector connector = new ServerConnector(server, new HttpConnectionFactory(httpConfig));

    //Code for connector porperties
    server.addConnector(connector);
    ContextHandlerCollection contexts = new ContextHandlerCollection();
    server.setHandler(contexts);

    final WebAppContext webApp = setupWebAppContext(contexts, conf);


    ServiceLocator serviceLocator = ServiceLocatorFactory.getInstance().create("my-locator");
    ServiceLocatorUtilities.enableImmediateScope(serviceLocator);
        ServiceLocatorUtilities.bind(
        sharedServiceLocator,
        new AbstractBinder() {
          @Override
          protected void configure() {
            bind(ClassA.class).to(InterfaceService.class).in(Immediate.class);
          }
         });
    }

    webApp.addEventListener(
        new ServletContextListener() {
          @Override
          public void contextInitialized(ServletContextEvent servletContextEvent) {
            servletContextEvent
                .getServletContext()
                .setAttribute(ServletProperties.SERVICE_LOCATOR, serviceLocator);
          }

          @Override
          public void contextDestroyed(ServletContextEvent servletContextEvent) {}
        });

    setupRestApiContextHandler(webApp, conf);

    try {
        server.start();
    } catch (Exception e) {
        LOG.error("Error while running jettyServer", e);
        System.exit(-1);
    }
}

private static WebAppContext setupWebAppContext(ContextHandlerCollection contexts, Configuration conf) {
    WebAppContext webApp = new WebAppContext();
    webApp.setContextPath(conf.getServerContextPath());
    webApp.addServlet(new ServletHolder(new DefaultServlet()), "/*");
    contexts.addHandler(webApp);

    webApp.addFilter(new FilterHolder(MyFilter.class), "/*", EnumSet.allOf(DispatcherType.class));
    webApp.setInitParameter("org.eclipse.jetty.servlet.Default.dirAllowed","true");

    return webApp;
}

private static void setupRestApiContextHandler(WebAppContext webapp, Configuration conf) {
    final ServletHolder servletHolder =
        new ServletHolder(new org.glassfish.jersey.servlet.ServletContainer());

    servletHolder.setInitParameter("javax.ws.rs.Application", MyServer.class.getName());
    servletHolder.setName("rest");
    servletHolder.setForcedPath("rest");
    webapp.setSessionHandler(new SessionHandler());
    webapp.addServlet(servletHolder, "/api/*");

    webapp.setInitParameter("shiroConfigLocations", "ShiroFilePathURI");
      webapp
          .addFilter(ShiroFilter.class, "/MyRestApiPath/*", EnumSet.allOf(DispatcherType.class))
          .setInitParameter("staticSecurityManagerEnabled", "true");
      webapp.addEventListener(new EnvironmentLoaderListener());
    }
  }

Мой ClassA выглядит следующим образом:

public class ClassA implements InterfaceService {
    @Inject
    public ClassA(SomeClass instances){
     //initialize some variable
    }
}

Существует класс REST, в который вводится InterfaceService:

@Path("/my_rest")
@Produces("application/json")
@Singleton
public class RestApi {

  private InterfaceService interfaceService;

  @Inject
  public RestApi(InterfaceService interfaceService) {
    this.interfaceService = interfaceService;
  }
}

Когда я запускаю этот код, я получаю следующее исключение:

"javax.servlet.ServletException: MultiException имеет 4 исключения: 1. java.lang.IllegalStateException: не удалось найти активный контекст для org.glassfish.hk2.api.Immediate 2. java.lang.IllegalStateException: при попытке создать службудля SystemDescriptor (реализация = контракты ClassA = {InterfaceService} "

  • В классе MyServer, когда я связываю класс с областью действия Singleton, он работает, как и ожидалось. То есть bind(ClassA.class).to(InterfaceService.class).in(Singleton.class);

  • Тогда, если я обновлю свой класс RestApi ниже

@Path("/my_rest")
@Produces("application/json")
@Singleton
public class RestApi {

  private ClassA classA;

  @Inject
  public RestApi(ClassA classA) {
    this.classA = classA;
  }
}

Тогда все будет работать, как и ожидалось, с немедленной областью действияа также.

Для меня требуется изменение области действия на Немедленное, так как мне нужно выполнить определенные операции в классе при запуске сервера. Кроме того, я не могу использовать ссылку на ClassA в RestApi, поскольку в будущем появятся другие реализации интерфейса InterfaceService, поэтому мне нужно кодировать интерфейс в RestApi. Любая подсказка о том, что мне нужно сделать, чтобы заставить код работать с немедленной областью действия, привязав его к InterfaceService

...