Главная страница
Навигация по странице:

  • Что находится в загруженном файле

  • Какие платформы поддерживаются .NET 3.5 SP1, .NET 4 Client Profile, .NET 4, Silverlight 3, Silverlight 4. Сколько он стоит

  • Где мне получить помощь

  • Castle W indsor основана данная глава

  • Внедрение зависимостей в. Внедрение зависимостей в .NET. Руководство по применению этого механизма. Net приложениях. Книга демонстрирует основные паттерны на обычном языке C#, поэтому вы в полной мере поймете, как работает механизм внедрения зависимостей


    Скачать 5.66 Mb.
    НазваниеРуководство по применению этого механизма. Net приложениях. Книга демонстрирует основные паттерны на обычном языке C#, поэтому вы в полной мере поймете, как работает механизм внедрения зависимостей
    АнкорВнедрение зависимостей в .net
    Дата14.12.2019
    Размер5.66 Mb.
    Формат файлаpdf
    Имя файлаВнедрение зависимостей в .NET.pdf
    ТипРуководство
    #100226
    страница26 из 43
    1   ...   22   23   24   25   26   27   28   29   ...   43
    Откуда мне его получить?
    Перейти на сайт http://www.castleproject.org/downloa d/
    и нажать на ссылку соответствующего релиза.
    Из Visual Studio 2010 можно получить его посредством NuGet. Имя пакета –
    Castle.Windsor

    Что находится в загруженном файле?
    Можно загрузить zip-файл, содержащий предварительно скомпилированные бинарные файлы. Кроме того, можно получить текущий исходный код и скомпилировать его самостоятельно.
    Бинарные файлы – это dll-файлы, которые можно размещать там, где захочется, и ссылаться на них из собственного кода.

    Какие платформы поддерживаются?
    .NET 3.5 SP1, .NET 4 Client Profile, .NET 4, Silverlight 3, Silverlight 4.

    Сколько он стоит?
    Нисколько. Это программное обеспечение с открытым исходным кодом, обладающее мягкой лицензией.

    Где мне получить помощь?
    Коммерческое сопровождение можно получить от Castle Stronghold.
    Больше информации по этому вопросу можно получить на сайте www.c astlestronghold.com/servic es/support

    370
    Вопрос
    Ответ
    Помимо коммерческого сопровождения, Castle W indsor остается программным обеспечением с открытым исходным кодом, имеющим бурно развивающу юся экосистему, поэтому, скорее всего
    (но не гарантированно), вы получите помощь на официальном форуме http://groups.google.com/gro up/castle-pro ject-users
    . Stack
    Overflow (
    htt p://stackoverflow.com/
    ) – еще одно место, где можно задать вопросы.
    На какой версии

    Castle W indsor основана данная глава?
    2.5.2
    После окончания изучения данного раздела вы должны будете уже хорошо разбираться в
    Castle W indsor, а также уметь использовать его в сценариях, в которых все компоненты руководствуются соответствующими DI-паттернами, например, Constructor Injection. Мы начнем с самого простого сценария и увидим, как можно разрешать объекты с помощью контейнера Windsor.
    Разрешение объектов
    Основная цель каждого DI-контейнера – разрешать объекты посредством подключе ния к ним всех их зависимостей. Castle Windsor предоставляет простое API для разрешения сервисов, но перед тем, как вы сможете разрешить сервис, его необходимо зарегистрировать с помощью контейнера. Ниже приведено самое простое возможное применение Windsor: var container = new WindsorContainer(); container.Register(Component.For());
    SauceBéarnaise sauce = container.Resolve();
    Перед тем, как попросить WindsorContainer чт о-т о разрешить, вы должны явным образом зарегистрировать соответствующие компоненты. В данном примере вы можете достичь этого, регистрируя единственный конкретный тип. Тем не менее, как вы увидите далее, чаще всего вы будете регистрировать преобразования от абстракции к конкретному типу.
    После соответствующей конфигурации контейнера можно разрешить тип
    SauceBéarnaise для того, чтобы получить его экземпляр. Вам не придется выполнять проверку на null
    - значение, поскольку
    WindsorContainer выдаст исключение, если не сможет выполнить автоматическую интеграцию и вернуть экземпляр запрашиваемого типа.
    П римечание
    Для Windsor необходимо, чтобы все запрашиваемые компоненты были зарегистрированы, даже если они являются конкретными типами. Это сделано намеренно, но данная схема не используется в других DI-контейнерах.
    Этот первый пример функционально эквивалентен прямому созданию экземпляра класса
    SauceBéarnaise с помощью ключевого слова new
    : ничего нового еще не приобретено.
    Вспомните, что механизм внедрения зависимостей – средство достижения результата, а

    371 результатом является слабое связывание. Для того чтобы достичь слабого связывания, вы должны преобразовать абстракции к конкретным типам.
    П реобразование абстракций к конкретны м типам
    Несмотря на то, что иногда нужно регистрировать сам конкретный класс, гораздо более универсальное требование – преобразовать абстракцию к конкретному классу. В конце концов, это и есть основная услуга, предлагаемая DI-контейнерами.
    Ниже вы преобразуете интерфейс
    IIngredient к конкретному классу
    SauceBéarnaise
    , который позволяет вам успешно разрешать
    IIngredient
    : var container = new WindsorContainer(); container.Register(Component
    .For()
    .ImplementedBy());
    IIngredient ingredient = container.Resolve();
    Вместо регистрации конкретного типа вы преобразуете абстракцию к конкретному типу.
    Когда вы позднее запросите экземпляр
    IIngredient
    , контейнер вернет экземпляр
    SauceBéarnaise
    Строго типизированное свободное API, доступное через класс
    Component
    (
    Castle.MicroKernel.Registration.Component
    , а не
    System.ComponentModel.Component
    ), помогает предотвратить ошибки конфигурации, поскольку метод
    ImplementedBy имеет generic-ограничитель, который гарантирует, что тип, указанный в аргументе типа, реализует аргумент типа абстракция, заданный в методе
    For
    . Т о есть, предыдущий код примера компилируется, потому что
    SauceBéarnaise реализует
    IIngredient
    Во многих случаях строго типизированное API – это все, что вам нужно, и, поскольку оно обеспечивает желаемую проверку во время компиляции, вы должны использовать его там, где это возможно. Кроме того, существуют ситуации, в которых вам необходим слабо типизированный способ разрешения сервисов. Это также возможно.
    Разрешение слабо типизированных сервисов
    В некоторых случаях мы не можем писать generic-код для разрешения типа, так как можем даже не знать точный тип абстракции на этапе проектирования. Хороший пример такой ситуации –
    DefaultControllerFactory в ASP.NET MVC, который мы обсуждали в разделе 7.2 "Построение ASP.NET MVC приложений". Соответствующая часть этого класса – виртуальный метод
    GetControllerInstance
    : protected internal virtual IController GetControllerInstance(
    RequestContext requestContext, Type controllerType);
    В этом API нет строго типизированных generic-ов. Вместо них нам предоставляют
    Type и просят вернуть экземпляр
    IController
    . Класс
    WindsorContainer также обладает слабо типизированной версией метода
    Resolve
    . Вы можете использовать этот метод для реализации
    GetControllerInstance
    : return (IController)this.container.Resolve(controllerType);

    372
    Обратите внимание на то, что в этом примере вы передаете аргумент controllerType в метод
    Resolve
    . Поскольку слабо типизированная версия метода
    Resolve возвращает экземпляр
    System.Object
    , вы должны явным образом выполнить приведение к
    IController перед тем, как вернуть результат.
    Не важно, какую перегрузку метода
    Resolve вы используете, Windsor гарантирует, что она вернет экземпляр требуемого типа или выдаст исключение, если существуют зависимости, не удовлетворя ющие данным условиям. После правильной регистрации всех необходимых зависимостей Windsor будет автоматически интегрировать необходимый тип на основании его конфигурации.
    В предыдущем примере this.container
    – это экземпляр
    IWindsorContainer
    . Для того чтобы иметь возможность разрешать требуемые типы, необходимо перед этим зарегистрировать все типы и их зависимости. Существует множество способов конфигурации контейнера Windsor, и в следующем разделе рассматриваются наиболее универсальные из этих способов.
    Конфигурирование контейнера
    Как обсуждалось в разделе 3.2 "Конфигурирование DI-контейнеров", существует несколько, концептуально разных способов конфигурирования DI-контейнера. На рисунке
    10-3 представлен обзор возможных вариантов.
    Рисунок 10-3: Концептуально разные варианты конфигурирования. Использование кода в качестве конфигурации подразумевает строгую типизированность и явное объявление.
    XML, с другой стороны, – позднее связывание, но все равно явное объявление.
    Автоматическая регистрация полагается на соглашения, которые могут быть строго типизированными и более слабо определенными.

    373
    Как и другие, имеющие длинную историю DI-контейнеры, Castle Windsor сначала использовал XML в качестве главного источника конфигурации. Но многие команды разработчиков вскоре поняли, что определение регистрации типов с помощью XML – чрезвычайно хрупкий способ. На сегодняшний момент мы предпочитаем строго типизированную конфигурацию. Это можно сделать, используя код в качестве конфигурации, но чаще всего более эффективно делать это при помощи автоматической регистрации, которая в большей степени основывается на соглашениях.
    Castle W indsor поддерживает все три подхода и даже позволяет нам сочетать их в пределах одного и того же контейнера. В этом отношении, Castle Windsor дает нам все, что мы только могли бы попросить. В данном разделе вы увидите, как можно использовать каждый из этих трех типов источников конфигурации.
    C ode as Con figuration
    В главе 3 вы видели примеры API Castle Windsor, использующего код в качестве конфигурации. Каждая регистрация инициализиру ется с помощью метода
    Register и обычно указывается при помощи Fluent API.
    Мы конфигурируем
    WindsorContainer методом
    Register
    , который в качестве входных данных принимает массив
    IRegistration
    . На первый взгляд все это выглядит довольно абстрактным. Но вместо того, чтобы возлагать на нас обязанность определения того, какую реализацию
    IRegistration использовать, Castle W indsor предоставляет Fluent
    Registration API, которое позволяет создавать экземпляры
    IRegistration с более понятным синтаксисом.
    Для того чтобы применять Fluent Registration API, мы используем статический класс
    Component в качестве точки входа.
    П редупреждение
    Не путайте
    Castle.MicroKernel.Registration.Component с
    System.ComponentModel.Component из стандартной библиотеки классов.
    Как вы уже видели ранее, самая простая возможная регистрация – регистрация конкретного типа: container.Register(Component.For());
    Данный код регистрирует класс
    SauceBéarnaise с помощью контейнера, но не обеспечивает никакого преобразования. Даже если
    SauceBéarnaise будет реализовывать
    IIngredient
    , контейнер выдаст исключение, если вы попросите его разрешить
    IIngredient
    : container.Resolve()
    Для возможности такого более релевантного сценария вы должны преобразовать конкретный тип в абстракцию: container.Register(Component
    .For()
    .ImplementedBy());

    374
    Обратите внимание на то, что теперь вместо класса
    SauceBéarnaise вы регистрируете интерфейс
    IIngredient
    . Это позволит вам разрешить
    IIngredient
    , но, что может показаться слегка удивительным, вы при этом потеряли способность разрешать конкретный класс
    SauceBéarnaise
    . Изредка тот факт, что код слабо связан, становится проблемой, но в исключительных ситуациях, когда вам нужно уметь разрешать оба типа, вы можете обеспечить это с помощью перегрузки метода
    For
    : container.Register(Component
    .For());
    Данный код регистрирует компонент
    SauceBéarnaise
    , в то же самое время перенаправляя регистрацию к интерфейсу
    IIngredient
    . Это означает, что и
    SauceBéarnaise
    , и
    IIngredient регистрируются как разрешаемые типы. В обоих случаях реализация обеспечивается с помощью
    SauceBéarnaise
    . Заметьте, что при использовании этой перегрузки вам не нужно неявно использовать метод
    ImplementedBy
    Очевидно, вы можете регистрировать составные типы при помощи последовательных вызовов метода
    Register
    : container.Register(Component
    .For()
    .ImplementedBy()); container.Register(Component
    .For()
    .ImplementedBy());
    Данный код регистрирует и интерфейс
    IIngredient
    , и интерфейс
    ICourse
    , а также преобразует их к конкретным типам. Тем не менее, регистрация одной и той же абстракции несколько раз имеет приводит к некоторым интересным последовательнос тям: container.Register(Component
    .For()
    .ImplementedBy()); container.Register(Component
    .For()
    .ImplementedBy());
    В этом примере вы регистрируете
    IIngredient дважды. Если вы разрешаете
    IIngredient
    , то получаете экземпляр
    Steak
    . Выигрывает первая регистрация, но последующие регистрации не забыты. Castle Windsor имеет изощренную модель работы с составными регистрациями. Мы вернемся к этому в разделе 10.3 "Работа с составными компонентами".
    В Fluent Registrat ion API доступны более продвинутые варианты, но данным способом мы можем сконфигурировать все приложение. Тем не менее, для того чтобы уберечь нас от слишком явного сопровождения конфигурации контейнера, мы можем рассмотреть в большей степени основанный на соглашениях подход, в котором используется автоматическая регистрация.
    Автоматическая регистрация
    Во многих случаях большинство регистраций похожи друг на друга. Такие регистрации трудно сопровождать, а явная регистрация каждого компонента часто сокращает производительно сть.

    375
    Давайте рассмотрим библиотеку, которая содержит множество реализаций
    IIngredient
    Вы можете регистрировать каждый класс индивидуально, но это приведет к многочисленным, схожим вызовам метода
    Register
    . Что еще хуже, каждый раз при добавлении новой реализации
    IIngredient вы должны также явно регистрировать эту реализацию с помощью контейнера, если хотите, чтобы эта реализация была доступной.
    Было бы более продуктивно установить, что все реализации
    IIngredient
    , обнаруженные в данной сборке, должны быть зарегистрированы.
    Сделать это можно путем применения статического класса
    AllTypes
    , который играет роль, аналогичную той роли, которую играет класс
    Component
    . М ы можем использовать один из методов класса
    AllTypes для того, чтобы просмотреть сборку на факт наличия типов, удовлетворяющих определенному критерию. Приведенный ниже код регистрирует все реализации
    IIngredient за один шаг: container.Register(AllTypes
    .FromAssemblyContaining()
    .BasedOn());
    Класс
    AllTypes предоставляет множество методов, которые дают нам возможность обратиться к конкретной сборке, но я считаю generic-метод
    FromAssemblyContaining наиболее кратким: предоставь ему тип представителя в качестве параметра типа, и он будет использовать сборку, содержащую данный тип. Существуют также и другие методы, предоставляющие возможность обеспечения
    Assembly с помощью других средств.
    В предыдущем примере вы, безусловно, регистрируете все реализации интерфейса
    IIngredient
    , но можете задать другие критерии отбора, либо сузив отбор, либо выполняя отбор не на основании интерфейсов и базовых классов, а на основании других критериев.
    Ниже представлена основанная на соглашениях регистрация, при которой вы добавляете все классы, имя которых начинается с
    Sauce
    , и регистрируете их относительно всех интерфейсов, которые они реализуют: container.Register(AllTypes
    .FromAssemblyContaining()
    .Where(t => t.Name.StartsWith("Sauce"))
    .WithService.AllInterfaces());
    Обратите внимание на то, что вы применяете предикат к методу
    Where
    , который выполняет фильтрацию по типу имени. Любой тип, имя которого начинается с
    Sauce
    , будет отобран из сборки, содержащей класс
    SauceBéarnaise
    . Свойство
    WithService позволяет задать правило регистрации типа. В данном примере вы регистрируете все типы относительно всех интерфейсов, которые они реализуют.
    Благодаря регистрации на основании соглашений вы можете перейти от строгого контроля типов к той области, где безопасность типов, кажется, исчезает. Пример, подобный предыдущему, компилируется, но при этом не гарантируется, что будет регистрироваться вообще любой тип. Это зависит от того, существуют ли какие-либо типы, удовлетворяющие критерию отбора. Вы можете переименовать все sauce-классы во что-то еще и останетесь без sauce
    В классе
    AllTypes существует даже метод, который принимает в качестве входного параметра имя сборки. Он будет использовать Fusion (средство загрузки сборки .NET

    376
    Fram ework) для обнаружения соответствующей сборки. Сочетая сборку с поздним связыванием и нетипизированный предикат, можно продвинуться вглубь территории позднего связывания. Т акая возможность могла бы стать полезным приемом реализации дополнений, поскольку Castle Windsor также может просматривать все сборки в директории.
    Еще один способ регистрации дополнений и других сервисов с поздним связыванием – применение возможности XML конфигурации Castle Windsor.
    XML конфигурация
    Когда вам нужно уметь изменять конфигурацию без повторной компиляции приложения,
    XML конфигурация – наилучший вариант.
    П одсказка
    Используйте XML конфигурацию только для тех типов, которые вам нужно изменить без повторной компиляции приложения. Для остальных случаев используйте автоматическую регистрацию или технологию использования кода в качестве конфигурации.
    Мы можем вставить XML конфигурацию в обычные файлы .NET конфигурации или импортировать XML из специализированных файлов. В Castle W indsor ничего не происходит, пока мы об этом явно не попросим, поэтому мы должны также указать, хотим ли загрузить конфигурацию из XML.
    Сделать это можно несколькими способами, но рекомендуемый способ – использовать метод
    Install
    (подробнее об
    Installer
    'ах мы поговорим в разделе 10.1.3 "Пакетирование конфигурации"): container.Install(Configuration.FromAppConfig());
    Метод
    FromAppConfig возвращает экземпляр
    ConfigurationInstaller
    , который читает
    XML конфигурацию Castle W indsor из конфигурационного файла приложения и преобразует ее в объекты, понятные контейнеру.
    Для того чтобы разрешить размещать конфигурацию Castle Windsor в конфигурационном файле, вы должны сначала добавить секцию конфигурации:
    < configS ect ions>

    < /config Sec tions>
    Данный код позволяет вам добавить секцию конфигурации castle в конфигурационный файл. Ниже приведен простой пример, который преобразует интерфейс
    IIngredient в класс
    Steak
    :
    < castle>



    < /castle >

    377
    Обратите внимание на то, что вам не приходится применять квалифицированное имя типа сборки для сервиса или для класса. Пока имена в рамках всех загруженных сборок будут уникальными, они будут корректно разрешаться – но если бы вам захотелось получить конфликт имен, вы могли бы все равно использовать квалифицированные имена типов.
    Очевидно, вы можете добавить столько компонентов, сколько вам потребуется.
    ConfigurationInstaller преобразует эту XML конфигурацию в объекты регистрации, которые конфигурируют контейнер, и вы можете последовательно разрешать сконфигурированные типы.
    XML конфигурация – это хороший вариант в тех ситуациях, когда вам нужно изменить конфигурацию одного или более одного компонента без повторной компиляции приложения. Т ем не менее, поскольку это может быть довольно хрупким вариантом, то для таких случаев вам следует сделать резервную копию и использовать либо автоматическую регистрацию, либо использовать код в качестве конфигурации для основной части конфигурации контейнера.
    П одсказка
    Помните, каким образом выигрывает первая конфигурация? Вы можете использовать это поведение для того, чтобы перезаписать жестко-закодиро ванную конфигурацию XML конфигурацией. Для этого вы должны не забыть установить
    ConfigurationInstaller до того, как установите любые другие компоненты.
    В данном разделе мы, главным образом, рассматривали различные API конфигурации
    Castle W indsor. Несмотря на то, что наверняка можно написать один большой блок неструктурированного кода конфигурации, лучше всего разделить конфигурацию на модули. Для этих целей у нас есть
    Windsor Installer
    'ы.
    Пакетирование конфигурации
    Иногда хочется упаковать логику конфигурации в повторно используемые группы, и даже когда повторное использование само по себе не является для нас самым приоритетным, мы можем пожелать обеспечить некоторого рода структуру в случае, если нам нужно сконфигурировать большое и сложное приложение.
    Благодаря Castle W indsor мы можем упаковать конфигурацию в
    Installer
    'ы.
    Installer
    – это класс, который реализует интерфейс
    IWindsorInstaller
    : public interface IWindsorInstaller
    { void Install(IWindsorContainer container, IConfigurationStore store);
    }
    Все, что вы делали до настоящего момента, вы также можете сделать и внутри
    Installer
    Следующий листинг демонстрирует
    Installer
    , который регистрирует все реализации
    IIngredient

    378
    Листинг 10-1: Реализация
    Windsor Installer public class IngredientInstaller : IWindsorInstaller
    { public void Install(IWindsorContainer container,
    IConfigurationStore store)
    { container.Register(AllTypes
    .FromAssemblyContaining()
    .BasedOn());
    }
    }
    IngredientInstaller реализует интерфейс
    IWindsorInstaller посредством использования точно такого же API, которое вы видели ранее, для регистрации всех реализаций
    IIngredient
    Для того чтобы зарегистрировать
    Installer
    , вызовите метод
    Install
    : container.Install(new IngredientInstaller());
    Несмотря на то, что метод
    Install можно вызывать бессчисленное множество раз, в документации к Castle Windsor рекомендуется выполнять всю конфигурацию в единственном вызове метода
    Install
    . М етод
    Install принимает в качестве параметра массив экземпляров IW indsorInstaller: public IWindsorContainer Install(params IWindsorInstaller[] installers);
    П одсказка
    Windsor Installer
    'ы позволяют вам упаковывать и структурировать код конфигурации вашего контейнера. Используйте их вместо встроенной конфигурации: это сделает вашу
    Composition Root более читабельной.
    П одсказка
    Кроме преимуществ, которые
    Installer
    'ы предлагают для вашего собственного кода,
    Castle W indsor также движется по направлению оптимизации большинства своих API вокруг
    Installer
    'ов. Это своеобразный и рекомендуемый способ конфигурирования в большей степени Castle W indsor, нежели других контейнеров.
    Кроме того, вы можете задать один или более одного
    Installer
    'а в XML, и загрузить конфигурационный файл, как это было описано ранее:



    Используя,
    Installer
    'ы вы можете конфигурировать
    WindsorContainer таким способом, каким вам только захочется – используя код в качестве конфигурации, автоматическую регистрацию или XML – или же вы можете сочетать все три подхода. После того, как контейнер сконфигурирован, вы можете попросить его разрешить сервисы.
    Данный раздел познакомил вас с DI-контейнером Castle Windsor и продемонстрировал основные принципы: как сконфигурировать контейнер и впоследствии использовать его

    379 для того, чтобы разрешать сервисы. Выполнять разрешение сервисов легко с помощью единичного вызова метода
    Resolve
    , поэтому вся сложность заключается в конфигурировании контейнера. Это можно сделать несколькими различными способами, включая императивный код и XML. До настоящего момента мы рассматривали только самое основное API. Есть и более перспективные области, которые нам необходимо рассмотреть. Одна из наиболее важных тем – как управлять жизненным циклом компонентов.

    380 10.2. Управление жизненным циклом
    В главе 8 мы обсуждали механизм управления жизненным циклом, в том числе самые универсальные, принципиальные стили существования, например, Singleton и Transient.
    Castle W indsor поддерживает множество различных стилей существования и позволяет вам сконфигурировать жизненный цикл всех сервисов. Стили существования, продемонстрированные в таблице 10-2, доступны в виде составляющей API Castle
    W indsor.
    Таблица 10-2: Стили существования Castle Windsor
    Название
    Комментарии
    Singleton
    Этот стиль существования используется в Castle Windsor по умолчанию.
    T ransient
    Каждый раз создается новый экземпляр, но экземпляр все равно отслеживается контейнером.
    PerT hread
    На один поток создается один экземпляр.
    PerW ebRequest
    Необходима регистрация в web.config (см. раздел 10.2.2 "Использование продвинутых стилей существования").
    Pooled
    Чаще всего будет уместно конфигурировать размер пула (см. раздел
    10.2.2).
    Custom
    Создайте свой собственный пользовательский стиль существования (см. раздел 10.2.3 "Разработка пользовательс кого стиля существования").
    Некоторые из встроенных стилей существования полностью эквивалент ны основным паттернам стилей существования, описанным в главе 8. Это, в частности, справедливо и для стилей существования Singleton и T ransient , поэтому в этой главе я не буду выделять для их описания какое-то специальное пространство.
    П римечание
    Стиль существования, используемый в Castle W indsor по умолчанию, – это Singleton. Это отличает его от многих других контейнеров. Как мы уже обсуждали в главе 8, Singleton – самый эффективный, но, тем не менее, не всегда самый безопасный из всех стилей существования. В Castle W indsor по умолчанию эффективность имеет приоритет над безопасностью.
    В этом разделе вы увидите, как можно конфигурировать стили существования для компонентов и как использовать некоторые более специфичные стили существования, например, PerW ebRequest и Pooled. Мы также рассмотрим реализацию пользовательского стиля существования для того, чтобы продемонстрироват ь, что мы не ограничены использованием только встроенных стилей существования. После прочтения данного раздела вы должны будете уметь использовать стили существования Castle Windsor в своем собственном приложении.
    Давайте начнем с обзора того, как конфигурировать стили существования для компонентов.

    381
    Конфигурирование стиля существования
    В данном разделе мы разберем то, как управлять стилями существования компонентов с помощью Castle Windsor. Стиль существования конфигурируется в виде составляющей части регистрации компонента, поэтому нам доступны те же самые возможности, что и при выполнении конфигурации в целом: код или XML. М ы будем рассматривать каждую из этих возможностей поочереди.
    Конфигурирова ние стиля существования с помощью кода
    Стиль существования конфигурируется с помощью Fluent Registration API, которое мы используем для регистрации компонентов. Это настолько просто, как и представленный ниже код: container.Register(Component
    .For()
    .LifeStyle.Transient);
    Обратите внимание на то, что вы определяете стиль существования при помощи свойства
    Lifestyle
    . В данном примере вы устанавливаете в качестве стиля существования стиль
    T ransient . Т аким образом, каждый раз, когда разрешается
    SauceBéarnaise
    , возвращается новый экземпляр.
    Вы все равно можете явным образом определить стиль существования Singleton, даже если он и является используемым по умолчанию. Два примера, приведенные ниже, являются эквивалентными: container.Register(Component
    .For()
    .LifeStyle.Singleton); и container.Register(Component
    .For());
    Поскольку Singleton является используемым по умолчанию стилем существования, вам не нужно явно определять его, но вы можете это сделать, если пожелаете.
    Т очно так же, как мы можем конфигурировать компоненты в коде и XML, мы можем конфигурировать стили существования и в коде, и в XML.
    Конфигурирова ние стиля существования с помощью XML
    В разделе 10.1.2 "Конфигурирование контейнера" вы видели, как конфигурировать компоненты с помощью XML, но не применяли никакого стиля существования. Как и в случае с конфигурированием компонента при помощи Fluent Registration API, Singleton является используемым по умолчанию стилем существования, но при необходимости вы можете явно определить другой стиль существования:


    382
    Единственное отличие от примера из раздела 10.1.2 "Конфигурирование контейнера" заключается в добавленном атрибуте lifestyle
    . Как вы видите, определение стиля существования легко выполняется и с помощью кода, и при помощи XML.
    Высвобожде ние компонентов
    Как мы уже обсуждали в разделе 8.2.2 "Управление устраняемыми зависимостями", важно высвободить объекты после того, как мы завершили работу с ними. Это также просто, как и вызов метода
    Release
    : container.Release(ingredient);
    Данный код будет высвобождать экземпляр, предоставленный в метод
    Release
    (переменная ingredient из предыдущего примера), а также все те зависимости экземпляра, жизненный цикл которых завершился. То есть, если экземпляр обладает
    T ransient зависимостью, то эта зависимость будет высвобождена (и возможно уничтожена), тогда как Singleton зависимость останется в контейнере.
    П одсказка
    Castle W indsor отслеживает все, даже T ransient компоненты, поэтому важно, не забывать высвобождать все разрешенные экземпляры для того, чтобы избежать утечек памяти.
    П одсказка
    Высвобождайте явно то, что вы явно разрешаете.
    П одсказка
    Не забывайте уничтожать сам контейнер при закрытии приложения. Такое поведение приведет к уничтожению Singleton компонентов и даст гарантию того, что приложение правильно очищается.
    Т еперь давайте обратим наше внимание на некоторые из тех стилей существования, для которых нужно немного больше конфигурации, нежели простой оператор.
    Использование продвинутых стилей существования
    В данном разделе мы рассмотрим два стиля существования Castle W indsor, для которых необходимо больше конфигурации, нежели простое объявление: Pooled и PerW ebRequest.
    И спользование стиля существования Pooled
    В разделе 8.3.5 "Pooled" мы рассматривали общую концепцию стиля существования
    Pooled. В данном разделе мы увидим, как использовать реализацию Windsor. Стиль существования Pooled в Castle Windsor уже идет с заданным по умолчанию размером пула, но, поскольку оптимальный размер пула всецело зависит от обстоятельств, вам следует явно сконфигурировать размер пула. Вы можете определить стиль существования
    Pooled с заданными по умолчанию размерами таким же способом, как вы конфигурируете любой другой стиль существования:

    383 container.Register(Component
    .For()
    .ImplementedBy()
    .LifeStyle.Pooled);
    Тем не менее, данный код не передает размер пула. Несмотря на то, что я не смог найти какую-либо документ ацию, в которой указано, каковы значения пула по умолчанию, исходный код Castle Windsor 2.1.1 показывает, что по умолчанию первоначальный размер пула равен 5, а максимальный размер – 15. Для меня эти значения кажутся довольно произвольными, что является еще одной причиной определения размера явным образом.
    Для того чтобы явным образом сконфигурировать размеры пула, вы можете использовать метод
    PooledWithSize
    : container.Register(Component
    .For()
    .ImplementedBy()
    .LifeStyle.PooledWithSize(10, 50));
    Данный пример устанавливает первоначальный размер – 10, а максимальный размер – 50.
    Пулы Castle W indsor имеют два конфигурационных значения: первоначальный размер и максимальный размер. Первоначальный размер, очевидно, регулирует первоначальный размер пула, а максимальный размер – максимальный размер пула, но в крайних случаях поведение может быть неожиданным. Рисунок 10-4 демонстрирует, как эволюционирует размер пула в течение жизненного цикла контейнера.
    Рисунок 10-4: Прогрессия размера пула с первоначальным размером, равным 3, и максимальным размером, равным 5. Даже если первоначальный размер равен 3, пул остается пустым до тех пор, пока не разрешается первый экземпляр. На данном этапе созданы все три экземпляра для первоначального размера, и один из них непосредственно используется. Когда экземпляр высвобождается, он возвращается в пул. Пул увеличивается в размере, если необходимо больше экземпляро в, чем для первоначального размера. Обратите внимание на то, что можно превысить максимальный размер, но что излишние экземпляр ы не используются повторно при высвобождении.
    Когда экземпляр разрешается из пула, он помечается как используемый. Поскольку он остается в этом состоянии до тех пор, пока не будет явным образом высвобожден из контейнера, важно, не забывать высвобождать экземпляр ы после завершения работы с ними. Это позволяет контейнеру повторно использовать экземпляры: container.Release(ingredient);

    384
    П римечание
    Т о, что происходит, когда пул полностью утилизируется, довольно неожиданно. Вместо того чтобы выдавать исключение или блокировать вызов, создаются избыточные экземпляр ы. После использования они отбрасываются вместо того, чтобы повторно использоваться.
    Несмотря на то, что стиль существования Pooled более продвинут, чем Singleton или
    T ransient , его все равно легко использовать. Единственное дополнительное усилие, которое вам необходимо сделать – передать два дополнительных числа для того, чтобы сконфигурировать размеры пула. Стиль существования PerW ebRequest не сильно отличается от Pooled, но его несколько сложнее конфигурировать.
    И спользование стиля существования PerWebRequest
    Как и подразумевает его имя, работа стиля существования PerWebRequest заключается в создании экземпляра для веб-запроса. Объявление этого стиля столь же просто, как и объявление стиля существования Transient: container.Register(Component
    .For()
    .ImplementedBy()
    .LifeStyle.PerWebRequest);
    Т ем не менее, если мы попытаемся использовать его без дальнейшей конфигурации, то получим исключение:
    Looks like you forgot to register the HTTP module Castle.MicroKernel.Lifestyle.P erWeb-
    RequestLifestyleModule
    Add ‘’ to the
    1   ...   22   23   24   25   26   27   28   29   ...   43


    написать администратору сайта