Получить 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;
}
}
Спасибо.
Ответы
Ответ 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();
}
}