Внедрение зависимостей в. Внедрение зависимостей в .NET. Руководство по применению этого механизма. Net приложениях. Книга демонстрирует основные паттерны на обычном языке C#, поэтому вы в полной мере поймете, как работает механизм внедрения зависимостей
Скачать 5.66 Mb.
|
Что происходит на данной фазе? Что прочитать дальше Register Регистрация компонентов контейнера. Вы конфигурируете контейнер, сообщая ему о том, какие классы он может использовать, как ему следует преобразовыват ь абстракции в конкретные типы и о том (необязательная информация), как определенные классы должны соединяться вместе. В разделе "Конфигурирование DI-контейнеров" я уже обсуждал то, как сконфигурировать DI- контейнер. В части "DI-контейнеры" я буду подробно обсуждать конфигурацию шести индивидуальных DI- контейнеров. Resolve Преобразует компоненты основания. Запрос одного типа преобразуется в одну диаграмму объектов. В разделе "Знакомство с DI- контейнерами" мы увидели, как преобразовывать диаграммы объектов с помощью DI- контейнера. В части "DI-контейнеры" вы можете более подробно почитать об API конкретных контейнеров. Release Освобождает компоненты из контейнера. Все диаграммы объектов, образованные на предыдущей фазе, должны быть освобождены в тот момент, когда в них уже нет нужды. Это сигнализирует о том, что контейнер может очистить диаграмму объектов, что определенно важно в тех случаях, когда некоторые компоненты являются лишними. В главе "Жизненный цикл объектов" я обсуждаю вопрос управления жизненным циклом объектов, включая важность процесса очистки объекта. Кроме того в части "DI- контейнеры" я рассматриваю API управления жизненным циклом индивидуальных DI- контейнеров. Вы должны использовать эти три фазы в правильном порядке и вам не разрешается волей- неволей двигаться назад или вперед. К примеру, вам не следует возвращаться и заново конфигурировать контейнер, как только вы приступили к преобразованию диаграммы объектов. Иногда люди спрашивают о том, как добавить в контейнер дополнительные компоненты уже после того, как они приступили к преобразованию компонентов. Не делайте этого – это принесет вам одни огорчения. П римечание Некоторые DI-контейнеры не поддерживают явный Release диаграмм объектов и вместо этого полагаются на .NET сборщика мусора (garbage collector). При использовании таких контейнеров вы должны применять модифицированный паттерн Register Resolve и обращаться к потенциальным утечкам ресурсов в ваших реализациях объекта. Более подробно читайте об этом в главе "Жизненный цикл объектов". В следующем разделе я буду говорить о методах Register, Resolve и Release, а также о фазах. Castle Windsor действительно обладает тремя методами с точно такими же 108 названиями, а фазы названы в честь этих методов. Другие DI-контейнеры могут использовать другие названия, но их основополагающая сущность идентична. Я использую названия только Castle W indsor, поскольку они обеспечивают логичную терминологию – а также приятную аллитерацию. С татическая структура В своем истинном представлении паттерн Register Resolve Release утверждает, что вам следует выполнять вызов только одного метода в каждой фазе. Кшиштоф Козмиц называет это паттерном трех вызовов (T hree Calls Pattern) – вам разрешено сделать только три вызова методов в контейнере. Методы Resolve и Release упрощают это. В разделе "Com position Root" я уже утверждал о том, что в приложении должен содержаться единственный вызов метода Resolve. Как следствие вы должны всегда выпускать то, что вы преобразовываете. П одсказка Любая диаграмма объектов, сформированная с помощью метода Resolve, должна быть списана при помощи метода Release. Конфигурирование DI-контейнера в единственном вызове метода требует более подробных разъяснений. Причиной того, что регистрация компонентов должна происходить в рамках единственного вызова метода, является то, что вы должны расценивать конфигурацию DI-контейнера как единичное, элементарное действие. После завершения конфигурации контейнер должен расцениваться как доступный только для чтения. Autofac даже делает это представление явным при помощи выделения конфигурации контейнера в отдельный ContainerBuilder : вы регистрируете компоненты с помощью ContainerBuilder , и когда вы делаете это, вы просите ContainerBuilder создать экземпляр контейнера из конфигурации. В Autofac вы не конфигурируете контейнер напрямую. При рассмотрении конфигурации в виде элементарного действия становится проще управлять кодом конфигурации, поскольку становится очевидным, в каком месте она должна выполняться. Многие DI-контейнеры также используют эту концепцию для того, чтобы замораживат ь конфигурацию, как только вы приступаете к преобразованию диаграмм объектов из него. Т акой подход заставляет их выполняться лучшим образом. Если вы вспомните листинг 3-2, то можете заявить, что он содержит более одного вызова метода. Регистрация всегда включает в себя множество операторов, но большинство DI- контейнеров обладают механизмом пакетирования, который позволяет инкапсулировать все эти конфигурационные операторы в единственном классе (возможно состоящим из других классов). Autofac называет их модулями (Modules), StructureMap называет их реестрами (Registries), а Castle W indsor – инсталляторами (Installers). Общим для всех них является тот факт, что все они могут использоваться для конфигурации контейнера с помощью единственного вызова метода. В разделе "Composition Root" вы уже видели, как Castle W indsor использует инсталлятор: container.Install(new CommerceWindsorInstaller()); 109 Для DI-контейнеров, не обладающих механизмом пакетирования, вы всегда можете создать пользовательский класс, который инкапсулирует конфигурацию в единичном методе. К совету, заключающемус я в том, что для Resolve и Release необходимо использовать только по одной единственной строке кода, следует отнестись серьезно – но для фазы Register данный факт должен восприниматься более концептуально. Важным вопросом является тот факт, что регистрация должна быть завершена до вызова метода Resolve. Рисунок 3-11 иллюстрирует то, как выглядит последовательность, включая инкапсуляцию множества вызовов метода Register. Рисунок 3-11: На фазе Register может иметь место любое количество вызовов метода Register, но вы все еще должны расценивать его как элементарное действие. На фазах Resolve и Release вам, буквально, нужно только по одному вызову каждого метода. Универсальным источником заблуждений является то, что паттерн трех вызовов создает твердое убеждение о том, как часто каждый метод должен появляться в базе кода, но он ничего не говорит о том, сколько раз он должен вызываться. Динамическое взаимодействие Название паттерна T hree Calls Pattern может привести вас к мысли о том, что каждый метод должен вызываться всего лишь раз. Источник этого заблуждения находится в самом названии, и это одна из нескольких причин того, почему я предпочитаю название Register Resolve Release. Паттерн T hree Calls утверждает, что для вызова каждого метода должна существовать единственная строка кода. Т ем не менее, в зависимости от обстоятельств, некоторые методы могут вызываться более одного раза. В однопоточном приложении таком, как настольное приложение, утилита командной строки или пакетное задание, каждый метод обычно вызывается только один раз, что проиллюстрировано на рисунке 3-12. Рисунок 3-12: В однопоточном приложении каждый метод будет вызываться только один раз. За конфигурацией контейнера непосредственно следует формирование диаграммы объектов приложения, которая выполняет реальную работу. После окончания работы перед выходом из приложения вызывается метод Release. 110 В приложениях, основанных на запросах, таких, как веб-сайт, веб-сервис или получатель асинхронного сообщения, Com position Root формирует диаграмму объектов для каждого входящего запроса. В этом типе приложения, как это проиллюстрировано на рисунке 3-13, метод Register вызывается только один раз, тогда как методы Resolve и Release вызываются попарно для каждого запроса – потенциально большее число раз. Рисунок 3-13: В приложениях, основанных на запросах, метод Register вызывается только один раз, тогда как методы Resolve и Release вызываются много раз – по одному на каждый запрос Важно отметить, что вам нужно сконфигурировать контейнер только один раз. Контейнер – это совместно используемый экземпляр, применяемый для преобразования составных запросов, но конфигурация должна оставаться стабильной и завершенной. Динамическая картина Register Resolve Release – это почти инверсия статического представления – сравните рисунок 3-11 и рисунок 3-13. В статическом представлении мы допускаем составные строки кода, которые вызывают метод Register , а в динамическо м представлении этот блок кода должен вызываться строго один раз. С другой стороны, статическим правилом является то, что вы должны иметь только одну строку кода, которая вызывает Resolve и Release, но во время выполнения они могут вызыват ься много раз. Это может казаться сложным и трудным, но как демонстрирует следующий пример, этого всего лишь вызовы трех методов. Пример: использование Register Resolve Release В данном примере вы будете реализовывать Com position Root шаблонного приложения из раздела "Р асширение шаблонного приложения" с помощью DI-контейнера Castle W indsor. Это тот же самый контейнер, который вы использовали в примере раздела "Com position Root", поэтому этот пример нужно читать как продолжение предыдущего. Точкой входа в приложение является метод Application_Start , и поскольку это приложение является веб-сайтом, фаза Register изолирована от фаз Resolve и Release, потому что вы должны сконфигурировать контейнер всего лишь раз. Код остается таким же, как и в предыдущем примере, но я хочу немного сместить фокус: 111 protected void Application_Start() { MvcApplication.RegisterRoutes(RouteTable.Routes); var container = new WindsorContainer(); container.Install(new CommerceWindsorInstaller()); var controllerFactory = new WindsorControllerFactory(container); ControllerBuilder.Current.SetControllerFactory(controllerFactory); } Согласно паттерну Register Resolve Release вызов первого метода, который вы совершаете для экземпляра container , должен быть вызовом элементарного Register. В данном случае метод называется Install и CommerceWindsorInstaller инкапсулирует индивидуальные регистрации в единственном классе. Следующий листинг демонстрирует реализацию CommerceWindsorInstaller Листинг 3-3: Инкапсуляция составных регистраций 1. public class CommerceWindsorInstaller : IWindsorInstaller 2. { 3. public void Install(IWindsorContainer container, IConfigurationStore store) 4. { 5. container.Register(AllTypes 6. .FromAssemblyContaining |