Guice and Wicket: использование инъекций SessionScoped
У меня есть работающее приложение Wicket [v6] с Guice [v3] - я прямо сейчас использовал внедрение зависимостей для операций с репозиторием, и я хочу потратить его на использование сервисов, находящихся в области сеанса (по одному на сеанс пользователя). Я прочитал официальную документацию, различные сообщения в блогах и вопросы здесь, но я не уверен, что использую правильный подход.
У меня есть два вопроса: 1. Я использую правильный путь? 2. Нужно ли что-то особенное для запуска тестов TestNG в классах, основанных на инъекциях SessionScoped?
Моя настройка: web.xml:
<filter>
<filter-name>guiceFilter</filter-name>
<filter-class>com.google.inject.servlet.GuiceFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>guiceFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<listener>
<listener-class>com.xxx.CustomServletConfig</listener-class>
MyApplication init:
@Override
protected void init()
{
super.init();
getResourceSettings().setResourcePollFrequency(null);
getMarkupSettings().setStripWicketTags(true);
getDebugSettings().setDevelopmentUtilitiesEnabled(true);
GuiceComponentInjector injector = new GuiceComponentInjector(this, new WebModule(), new GuiceModule());;
}
CustomServletConfig:
public class CustomServletConfig extends GuiceServletContextListener {
@Override
protected Injector getInjector() {
return Guice.createInjector(new GuiceModule(), new WebModule());
}
WebModule:
public static class WebModule extends ServletModule {
@Override
protected void configureServlets() {
bind(WebApplication.class).toProvider(WicketGuiceAppProvider.class).asEagerSingleton();
bind(IUserService.class).to(UserService.class).in(ServletScopes.SESSION);
Map<String, String> params = new HashMap<String, String>();
params.put(WicketFilter.FILTER_MAPPING_PARAM, "/*");
filter("/*").through(WicketGuiceFilter.class, params);
}
}
На странице примера у меня есть:
@Inject
IUserService userService
...
userService.doSomething
На userService.doSomething во время модульного тестирования я получаю Guice OutOfScopeException, указывая на мои привязки в ServletModule: ошибка в настраиваемом поставщике, com.google.inject.OutOfScopeException?: Невозможно получить доступ к объекту области. Либо мы в настоящее время не находимся внутри запроса сервлета HTTP, либо вы, возможно, забыли применить com.google.inject.servlet.GuiceFilter? в качестве фильтра сервлетов для этого запроса.
Моя конфигурация в порядке, и мне нужно выполнить модульные тесты по-другому (я просто запускаю свое приложение с помощью WicketTester), или мой дизайн неисправен?
1 ответ
Это очень распространенная ошибка.
Все объекты в ServletScopes
или же RequestScopes
должен быть передан как Providers
,
Итак, ваш код должен быть:
@Inject
Provider<IUserService> userServiceProvider
public IUserService getUserService() {
userServiceProvider.get();
}
Почему так?! Все хорошо, пока вы используете его в Stage.DEVELOPMENT и родительский класс не создан с нетерпением. Если вы связываете родительский класс как asEagerSingleton
или переключитесь на Stage.PRODUCTION ваши классы начинают создаваться с нетерпением во время запуска. В противном случае они создаются ленивым способом, только когда к ним обращаются (очень вероятно во время первого запроса).
И там ваша проблема выходит на сцену. Ваш WebApplication
инициализируется с нетерпением во время запуска. Затем guice пытается внедрить все дочерние зависимости и находит IUserService
который является полевой инъекцией в SessionScope
, Проблема в том, что вы в данный момент не находитесь внутри GuiceFilter и нет запроса, поэтому guice не может определить текущий сеанс или создать новый. Таким образом, эти области не могут быть достигнуты. Вы в настоящее время в вашем ContextListener
и ваша заявка создается с нетерпением. Все могло бы быть хорошо, если бы вы использовали просто Singleton
вместо asEagerSingleton
из-за ленивой загрузки.
В любом случае, передача объектов Session и Request в качестве провайдеров является наилучшей практикой. Вы можете узнать больше о провайдерах здесь и Scopes здесь (есть также хорошая таблица со сравнением загрузки с нетерпением и ленивостью)