Получить ServletContext в приложении - программирование
Подтвердить что ты не робот

Получить ServletContext в приложении

Не могли бы вы объяснить, как я могу получить экземпляр ServletContext в моем подклассе Application? Является ли это возможным? Я попытался сделать это, как в следующем фрагменте, но он не работает - ctx не установлен:

import javax.ws.rs.core.Application;
import javax.ws.rs.core.Context;

//...

@ApplicationPath("/")
public class MainApplication extends Application {

    @Context ServletContext ctx;

    @Override
    public Set<Class<?>> getClasses() {     
        Set<Class<?>> classes = new HashSet<Class<?>>();
//...
        return classes;
    }
}

web.xml:

<web-app ...>
 <context-param>
  <param-name>environment</param-name>
  <param-value>development</param-value>
 </context-param>
 <filter>
  <filter-name>jersey-filter</filter-name>
  <filter-class>org.glassfish.jersey.servlet.ServletContainer</filter-class>
   <init-param>
   <param-name>javax.ws.rs.Application</param-name>
   <param-value>my.MainApplication</param-value>
  </init-param>
</filter>
...
</web-app>

Проблема в том, что мне нужно получить от него параметры контекста. Если будет другой способ, я был бы признателен, если бы кто-нибудь дал подсказку.


Я понимаю, что аннотация Context может быть не предназначена для этого. На самом деле мне не нужно ServletContext. Если бы я мог получить параметры контекста из web.xml, я был бы абсолютно счастлив.

Вот пример того, что мне действительно нужно:

import java.util.HashSet;
import java.util.Set;

import javax.servlet.ServletContext;
import javax.ws.rs.core.Application;
import javax.ws.rs.core.Context;

import org.glassfish.hk2.utilities.binding.AbstractBinder;

public class MainApplication extends Application {

    @Context ServletContext ctx;

    @Override
    public Set<Object> getSingletons() {
        Set<Object> set = new HashSet<Object>();
        final String environment = ctx.getInitParameter("environment");
        //final String environment = ... get context parameter from web xml
        set.add(new AbstractBinder() {

            @Override
            protected void configure() {
                bind(new BaseDataAccess(environment)).to(DataAccess.class);             
            }
        });
        //...
        return set;
    }
}

Спасибо.

4b9b3361

Ответ 1

Так как Jersey 2.5, ServletContext может быть введен непосредственно в конструктор: https://java.net/jira/browse/JERSEY-2184

public class MyApplication extends ResourceConfig {
    public MyApplication(@Context ServletContext servletContext) {
       // TODO
    }
}

Ответ 2

@Context можно сделать доступным на ResoureConfig, введя его как параметр конструктора, используя @Context. Другой способ доступа к нему - через обработчик событий.

Попробуйте приведенный ниже код.

@ApplicationPath("...")
public class MyApplication extends ResourceConfig {
    public MyApplication() {
        register(StartupHandler.class);
    }

    private static class StartupHandler extends  AbstractContainerLifecycleListener {
        @Context
        ServletContext ctx;

        @Override
        public void onStartup(Container container) {
            // You can put code here for initialization. 
        }
    }
// ...

Ответ 3

Инъекция происходит, когда вы вводите метод обслуживания. Проверьте, не является ли это проблемой.

Ответ 4

В документации для версии 1.18 для класса есть интересное выражение com.sun.jersey.spi.container.servlet.ServletContainer

Сервлет или фильтр могут быть настроены на инициализацию параметр "com.sun.jersey.config.property.resourceConfigClass" или "javax.ws.rs.Application" и значение которого является полностью квалифицированным именем класс, реализующий ResourceConfig или Application. Если бетон class имеет конструктор, который принимает один параметр типа Map то класс создается с помощью этого конструктора и экземпляра карты, содержащей все параметры инициализации, передается как параметр.

Если мое понимание верно, следующий конструктор должен быть вызван "экземпляром карты, содержащей все параметры инициализации"

public class ExampleApplication extends Application {
    public ExampleApplication(Map initParams) {
    }
    ...
}

Вот соответствующая часть web.xml:

<servlet>
  <servlet-name>Jersey Web Application</servlet-name>
  <servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer</servlet-class>
    <init-param>
       <param-name>javax.ws.rs.Application</param-name>
       <param-value>experiment.service.ExampleApplication</param-value>
    </init-param>
</servlet>

Но почему-то это не помогло мне со следующим сообщением:

SEVERE: Отсутствует зависимость для конструктора public Эксперимент .service.ExampleApplication(java.util.Map) в параметре индекс 0

И для текущей версии Джерси (2.5.1) в документе нет такого заявления: https://jersey.java.net/apidocs/latest/jersey/org/glassfish/jersey/servlet/ServletContainer.html

Ответ 5

Вы можете использовать интерфейс ApplicationEventListener для получения ServletContext. По завершении инициализации вы можете "поймать" ApplicationEvent и использовать введенный ServletContext для работы с.

Прекрасно работает с: org.glassfish.jersey: 2.12
Для дополнительных версий, PLS использовать комментарии - я не знаю, sry.

Jersey Docs - 20.1.2. Слушатели событий

Ваш MainApplication:

@ApplicationPath("/")
public class MainApplication extends Application {
    @Override
    public Set<Class<?>> getClasses() {     
        Set<Class<?>> set = new HashSet<Class<?>>();
        set.add(MainApplicationListener.class);
        return classes;
    }
}

... или альтернативный MainResourceConfig (я предпочитаю использовать этот):

public class MainResourceConfig extends ResourceConfig {
    public MainResourceConfig() {
        register(MainApplicationListener.class);
    }
}

И ApplicationEventListener:

public class MainApplicationListener implements ApplicationEventListener {

    @Context
    private ServletContext ctx; //not null anymore :)

    @Override
    public void onEvent(ApplicationEvent event) {
        switch (event.getType()) {
            case INITIALIZATION_FINISHED:
            // do whatever you want with your ServletContext ctx
            break;
    }

    @Override
    public RequestEventListener onRequest(RequestEvent requestEvent) {
        return null;
    }

}

Ответ 6

Не используйте @Context в Application, но в классе ресурсов.

@Path("/foos")
public class FooResource {

  @Context
  ServletContext ctx;

  @GET
  public Response getFoos() {
    return Response.ok().build();
  }
}