Jersey 1.x и Tomcat: как зарегистрировать ContainerRequestFilter программно, т.е. без web.xml?

Мое приложение

В моем приложении JAX-RS/Jersey, работающем в Tomcat, мне нужно запустить класс фильтра, который реализует ContainerRequestFilter перед каждым методом ресурса. Фильтр определяет, доступна ли служба прямо сейчас1. Делается это довольно просто, если я пропишу фильтр в web.xml:

DataResource.java:

package thepackage;

import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;

@Path("/data")
public class DataResource {

  @GET
  @Produces("application/json")
  public String getData() {
    return "{\"data\": [{\"id\": 1},{\"id\": 2}]}";
  }

}

ServiceAvailabilityFilter.java:

package thepackage;

import com.sun.jersey.spi.container.ContainerRequest;
import com.sun.jersey.spi.container.ContainerRequestFilter;
import java.util.Random;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;

public class ServiceAvailabilityFilter implements ContainerRequestFilter {

  private static final Random RANDOM = new Random();

  private boolean isServiceAvailable(ContainerRequest request) {
    // Actual logic goes here; for this sample, just flip a coin
    return RANDOM.nextBoolean();
  }

  @Override
  public ContainerRequest filter(ContainerRequest request) {
    if (isServiceAvailable(request)) {
      return request;
    } else {
      throw new WebApplicationException(
          Response.serverError().type(MediaType.APPLICATION_JSON_TYPE)
              .entity("{\"error\":\"Service not available\"}").build()
      );
    }
  }

}

web.xml:

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
         version="3.1">
  <servlet>
    <servlet-name>jersey</servlet-name>
    <servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer</servlet-class>
    <init-param>
      <param-name>com.sun.jersey.config.property.packages</param-name>
      <param-value>io.github.garysheppardjr.jersey1xfiltertest</param-value>
    </init-param>
    <init-param>
      <param-name>com.sun.jersey.spi.container.ContainerRequestFilters</param-name>
      <param-value>io.github.garysheppardjr.jersey1xfiltertest.ServiceAvailabilityFilter</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
  </servlet>
  <servlet-mapping>
    <servlet-name>jersey</servlet-name>
    <url-pattern>/*</url-pattern>
  </servlet-mapping>
</web-app>

Мой вопрос

Однако я не хочу объявлять ServiceAvailabilityFilter в XML. Я хочу зарегистрировать его в коде Java. Как бы я это сделал?

Вещи, которые я бы предпочел не делать

  • Объявите фильтр в файле web.xml. Почему бы и нет? Если я поставлю это приложение как локальное программное обеспечение, я хочу убедиться, что кто-то не сможет отключить мой фильтр, отредактировав файл web.xml.
  • Проверить наличие услуги в классе DataResource. Почему бы и нет? Я не хочу писать и поддерживать новый код во всех своих классах ресурсов. Этого можно избежать с помощью фильтров.
  • Переход с Джерси 1.x на Джерси 2.x. Почему бы и нет? У меня есть зависимости и крайние сроки, которые сделают переход на Jersey 2.x очень сложным.

1 Вы можете спросить, почему служба может быть недоступна? Это не имеет значения. Использовать ваше воображение. Эта логика не имеет отношения к этому вопросу, поэтому я заменил ее на Random.nextBoolean().


person Gary Sheppard    schedule 28.08.2019    source источник


Ответы (1)


Удалите элемент <servlet> из web.xml (или вообще удалите web.xml, если это все, что у вас есть, и вы используете как минимум Servlet API 3.0). Чтобы заменить элемент <servlet>, создайте класс, расширяющий javax.ws.rs.core.Application. В случае этого вопроса проще всего расширить com.sun.jersey.api.core.PackagesResourceConfig. Аннотируйте свой новый класс с помощью javax.ws.rs.ApplicationPath. Сделайте свои настройки <init-param> в конструкторе этого класса.

DataResource.java: без изменений.

ServiceAvailabilityFilter.java: без изменений.

MyApplication.java (или как вы хотите его назвать):

package thepackage;

import com.sun.jersey.api.core.PackagesResourceConfig;
import javax.ws.rs.ApplicationPath;

@ApplicationPath("/")
public class MyApplication extends PackagesResourceConfig {

  public MyApplication() {
    // "com.sun.jersey.config.property.packages" init-param
    super(DataResource.class.getPackageName());
    // "com.sun.jersey.spi.container.ContainerRequestFilters" init-param
    getContainerRequestFilters().add(ServiceAvailabilityFilter.class);
  }

}

web.xml: удалите хотя бы элемент <servlet>, или вы можете полностью удалить файл.

person Gary Sheppard    schedule 28.08.2019