Guice нетерпеливые / ленивые экземпляры Singleton

У меня возникают некоторые проблемы с пониманием того, как работают синглтон-инстанции 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()", и поэтому я решил это, изменив строку: bind(MyServlet.class).asEagerSingleton(); into: bind(MyServletDummyInterface.class).to(MyServlet.class).asEagerSingleton()

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

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

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

Configure() AbstractModule имеет следующие привязки:

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 ответ

Решение

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

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

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

Другие вопросы по тегам