Guice нетерпеливые / ленивые экземпляры Singleton - PullRequest
8 голосов
/ 08 ноября 2011

У меня проблемы с пониманием того, как работают синглтон-инстанции Guice. Я прочитал доступную документацию (здесь - http://code.google.com/p/google-guice/wiki/Scopes), но я все еще не могу понять некоторые вещи:

1) Я интегрировал Guice с Tomcat и настроил некоторые привязки в модуле ServletModule:

bind(MyServlet.class).asEagerSingleton();
serve("myUrl").with(MyServlet.class);
serve("myOtherUrl").with(MyOtherServlet.class);

(где класс MyOtherServlet имеет аннотацию @Singleton над ним) Мое намерение здесь состояло в том, чтобы иметь два сервлета, один из которых активно создается, а другой нет. Однако кажется, что строка "serve ... with ..." автоматически создает экземпляры объектов сервлетов, даже если этот класс не связан как активный одиночный объект. Ссылка, которую я прикрепил выше, упоминает различие между Guice, работающим в Stage.Development и Stage.Production - однако это все же происходило, даже когда я явно использовал Stage.Development (который по умолчанию в любом случае). Есть ли способ избежать этого?

2) (продолжение 1) Пытаясь убедиться, что MyServlet сначала создается, хотя все сервлеты создаются с нетерпением, я изменил порядок модулей (и операторов связывания) при создании Injector, так что появляется привязка для MyServlet первый. Однако я обнаружил, что он все еще создается позже, чем некоторые другие привязки (классов не сервлетов), которые имели вид:

bind(MyInterface.class).to(MyClass.class).asEagerSingleton()

, хотя эти другие привязки появились позже в порядке модулей / привязок. Я изучил его и обнаружил, что Guice просто создает экземпляры нетерпеливых синглетонов, которые были связаны формой «bind ... to ... asEagerSingleton ()», прежде чем он выполняет один из «bind ... asEagerSingleton ()», и поэтому я решил это, изменив строку: связывания (MyServlet.class) .asEagerSingleton (); в: связывания (MyServletDummyInterface.class) .то (MyServlet.class) .asEagerSingleton ()

и это действительно сработало. Тем не менее, я бы предпочел не использовать фиктивный интерфейс только для решения этой проблемы, поэтому мне было интересно, есть ли у кого-нибудь лучшее решение для этого ..?

3) У меня есть два модуля Guice - один ServletModule и один AbstractModule. ServletModule configureServlets () имеет следующую привязку:

serve("aUrl").with(SomeServlet.class);

Настройка абстрактного модуля () имеет следующие привязки:

bind(SomeImpl.class).asEagerSingleton();
bind(SomeInterface.class).to(SomeImpl.class).in(Singleton.class);

Кроме того, класс SomeServlet имеет внедренное поле типа SomeInterface и имеет аннотацию @Singleton поверх класса.

Теперь можно ожидать, что при создании инжектора будет создан экземпляр класса SomeImpl, и тот же экземпляр будет внедрен в экземпляр SomeServlet. Как упоминалось ранее, сервлеты, ограниченные выражением «serve ... with ...», также, похоже, стремительно создаются, но в любом случае должен быть только один экземпляр SomeImpl. И все же по какой-то причине я получил два экземпляра SomeImpl, созданных при этом. Чтобы обойти это, я немного смешал две строки в configure (), и вместо вышеупомянутых у меня были следующие строки:

bind(SomeImpl.class).in(Singleton.class)
bind(SomeInterface.class).to(SomeImpl.class).asEagerSingleton();

и затем все заработало, и я получил только один экземпляр SomeImpl. Я не совсем понимаю, почему переключение должно иметь значение - я вижу, как последний способ «лучше», но я ожидаю, что оба будут работать правильно, поэтому мне просто интересно, если я здесь что-то не так делаю ..



Извините за длину,
Спасибо за помощь!

1 Ответ

8 голосов
/ 09 ноября 2011

1) Невозможно избежать этого, поскольку Guice вызывает метод init() всех сервлетов при инициализации своего собственного конвейера фильтра и таким образом создает их все.Если вам действительно нужна такая ленивая логика инициализации, вы должны поместить ее в сам сервлет (или использовать вспомогательный класс-помощник, или ... есть много способов, в зависимости от вашего варианта использования).

2) ОбычноПри этом модули Guice объявляют привязки , поэтому не предназначены для определения начальной загрузки с точными порядками создания экземпляров.Если вам нужен такой определенный порядок создания экземпляров, создайте объекты самостоятельно в нужном порядке и свяжите их с помощью bind(...).toInstance(...).Если вам нужно внедрение в самостоятельно построенные экземпляры, вы можете использовать requestInjection(...) (если инъекции поля / метода достаточно, это более громоздко для внедрения конструктора).

3) Область действия Guice применяется к ключу привязки,не значение привязки, Применение областей действия описывает, почему только ваш второй пример работает так, как задумано.

...