Диссертация (1148251), страница 12
Текст из файла (страница 12)
Для этого выделен интерфейс с базовыми операциями:public interface IProxy {bool IsEnabled();void Open();void Close();}ЛИСТИНГ 11. ИНТЕРФЕЙС IPROXYВ тех местах, где требуется инстанцирование конкретного класса,реализующего данный интерфейс, применяется контейнер Unity:62// Создание контейнераIUnityContainer container = new UnityContainer();// Загрузка его спецификации из конфигурационного файлаcontainer = Microsoft.Practices.Unity.Configuration.UnityContainerExtensions.LoadConfiguration(container);// Создание контейнером конкретного объекта, реализующего интерфейс IProxyvar proxy = Microsoft.Practices.Unity.UnityContainerExtensions.Resolve<IProxy>(container);//Работа с только что созданным объектом через интерфейс IProxyif (proxy.IsEnabled())proxy.Open();proxy.Close();ЛИСТИНГ 12.
КОНТЕЙНЕР ДЛЯ IPROXYТеперь появляется возможность менять реализации интерфейса черезконфигурационный файл, без перекомпиляции проекта. Ниже приведен примерсопоставления с объектом класса Proxy:<?xml version="1.0" encoding="utf-8"?><configuration><configSections><!-- Для применения Unity необходимо организовать секцию с названием unity --><sectionname="unity"type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection,Microsoft.Practices.Unity.Configuration" /></configSections><unity xmlns="http://schemas.microsoft.com/practices/2010/unity"><!-- Определяем сокращенные названия IProxy и Proxy, указывая здесь полные названияклассов --><aliasalias="IProxy"type="AspectOriented.Infrastructure.Services.IProxy,AspectOriented.Infrastructure" /><aliasalias="Proxy"type="AspectOriented.Terminal.Services.Proxy,AspectOriented.Terminal" /><container><!-- Сопоставляем интерфейсу IProxy ссылку на объект класса Proxy --><register type="IProxy" mapTo="Proxy" /></container></unity></configuration>ЛИСТИНГ 13.
СОПОСТАВЛЕНИЕ ИНТЕРФЕЙСУ IPROXY ССЫЛКИ НА ОБЪЕКТ КЛАССА PROXYПерехват обращений к методам интерфейса осуществляется классомперехватчиком, наследником IInterceptionBehavior, причем разные перехватчикимогут выстраиваться в цепочку, передавая друг другу результаты своей работы ирезультат целевого метода [30]:63Рисунок 6. Перехват целевых методов в UnityНиже приведен пример такого перехватчика [15]:public class DiagnosticInterceptor : IInterceptionBehavior {//Для перехвата требуется определить метод Invokepublic IMethodReturn Invoke(IMethodInvocation input,GetNextInterceptionBehaviorDelegate getNext) {// Здесь определяется действие BEFORE.// Информация о целевом методе содержится в аргументе inputSystem.Console.WriteLine(String.Format("{0}", input.MethodBase));// Получаем результат работы следующих перехватчиков данного целевого методаvar methodReturn = getNext().Invoke(input, getNext);// Далее идет действие AFTER.if (methodReturn.Exception == null)System.Console.WriteLine(String.Format("Successfully finished {0}",input.MethodBase));elseSystem.Console.WriteLine(String.Format("Finished {0} with exception {1}:{2}", input.MethodBase,methodReturn.Exception.GetType().Name, methodReturn.Exception.Message));}//Требуется вернуть результат работы предыдущим перехватчикамreturn methodReturn;public IEnumerable<Type> GetRequiredInterfaces() {return Type.EmptyTypes;}}public bool WillExecute{get{ return true; }}ЛИСТИНГ 14.
КЛАСС «ПЕРЕХВАТЧИК»Сопоставление данного перехватчика и целевого метода производится черезконфигурационный файл:64<unity xmlns="http://schemas.microsoft.com/practices/2010/unity"><!-- Перед использованием перехватчиков требуется подключить элемент sectionExtension --><sectionExtension type="Microsoft.Practices.Unity.InterceptionExtension.Configuration.InterceptionConfigurationExtension, Microsoft.Practices.Unity.Interception.Configuration" /><!-- Сопоставляем короткое имя перехватчика с полным именем класса--><aliasalias="DiagnosticInterceptor"type="AspectOriented.UnityInterceptors.DiagnosticInterceptor,AspectOriented.UnityInterceptors" /><container><!-- Запускаем механизм перехвата--><extension type="Interception" /><register type="IProxy" mapTo="Proxy"><!-- Указываем тип перехвата (перехват интерфейса)--><interceptor type="InterfaceInterceptor" /><!-- Подключаем перехватчик DiagnosticInterceptor --><interceptionBehavior type="DiagnosticInterceptor" /></register></container></unity>ЛИСТИНГ 15.
СОПОСТАВЛЕНИЕ ПЕРЕХВАТЧИКА И ЦЕЛЕВОГО МЕТОДАПодобная регистрация перехватчика приведет к тому, что все вызовыметодов интерфейса IProxy у объекта, созданного через контейнер, будутперехвачены методом Invoke класса перехватчика. Однако следует учесть, чтоперехватить конструкторы таким образом не удастся. Кроме перехвата методовинтерфейса (interface interceptor), в Unity есть возможность перехватить всеметоды целевого класса, если он унаследован от MarshalByRefObject (transparentproxy interceptor) [99]. Эти два метода могут быть применены динамически к ужесуществующим объектам. Существует и третий способ, позволяющий присоздании объекта подставить вместо него объект-наследник (virtual methodinterceptor). В этом случае перехватываются только виртуальные методы.Рассмотренные принципы перехвата вызовов целевых методов в IoCконтейнерах удобны для разработчиков, если те уже работают с выделениеминтерфейсов и управлением зависимостями через контейнер.
В этом случаеобращения к IoC-контейнеру распределены по всему исходному коду и его смена(при такой необходимости) будет затруднительна. IoC-контейнеры помогаютсоздавать слабосвязанные компоненты и бесшовно менять их реализацию вконфигурации, но только в том случае, если приложение уже разработано получшим практикам инверсии зависимостей. Далее приводятся некоторыеограничениядинамическихIoC-контейнеровинструментами статической компоновки.посравнениюсАОП-651. Низкая производительность, т.к. прокси-объекты строятся во времявыполнения программы.2. Ограниченные возможности по спецификациям точек внедрения, нетвозможности указать условия, которые должны быть выполнены привызове целевого метода для его перехвата.3. Отсутствует доступ к контексту точки внедрения.4. Ряд ошибок может быть выявлен АОП-инструментами ещё на этапекомпиляции.5.
Нет возможности перехватывать работу с целевыми объектами,созданными вне контейнера.6. АОП-инструменты предоставляют расширения к средам разработки,позволяющие облегчить разработку аспектов и навигацию по местам ихвнедрения в целевом коде.7. Избыточность кода и настроек для создания IoC-контейнера.Несмотря на свои недостатки, IoC-контейнеры более популярны вповседневном программировании, чем АОП-инструменты. Связано это с большейориентированностьюнапривычныепаттерныобъектно-ориентированнойразработки и большей гибкостью, когда действия перехватчиков можно менятьпрямо во время выполнения целевой программы.2.4 Статическое применение аспектов в PostSharp на платформе .NETИнструмент PostSharp [80] появился в 2007 году на всплеске интереса кАОП и с тех пор активно развивается.
Его активное развитие обусловленокоммерциализациейпродукта,чтопозволяеткомпании-разработчикуSharpCrafters контролировать и управлять всем процессом разработки. Однако этоодновременно является препятствием для его применения в академических,государственных и проектах с открытым кодом.66PostSharp имеет тесную интеграцию с Microsoft Visual Studio, в том числешаблоны для быстрого добавления аспектов и графический интерфейс длянавигации по ним и точкам внедрения. Аналогично Aspect.NET внедрениеаспектов происходит на этапе пост-компиляции (статически), однако если первыйпозволяет создавать аспекты в отдельном проекте, то второй устанавливаетсячерез менеджер пакетов Nuget прямо в целевой проект, добавляя в него своизависимости. В этом смысле PostSharp не может полностью обеспечитьбесшовность расширения целевого проекта.В какой-то степени по своим возможностям PostSharp превосходит AspectJ,например, возможностью вызывать действия аспектов во время компиляциипроекта и предоставлять всю доступную информацию времени построения.
Такимобразом, принимать решение о внедрении в заданную точку целевого кода, аспектможет на этапе компиляции, проанализировав целевой код или настройки. Болеетого, аспекты могут исследовать архитектуру целевого проекта и выдаватьрекомендациипоней(architecturevalidation),аналогичнопродуктупостатическому анализу FxCop [34].Аспекты могут применяться к целевым методам, обращениям к полю илисвойству, исключениям или событиям. Сами аспекты реализуются в видесериализуемых классов-наследников от соответствующих атрибутов.
Применениеаспекта заключается в:1) пометке атрибутом целевого класса, поля или метода. Этот способприменяется для точечного указания места внедрения;2) указанию в свойствах сборки (AssemblyInfo.cs) маски названияцелевого класса или метода. Таким образом, аспект применяется кнескольким местам (multicast).
Пример:[assembly: ConsoleApplication1.LoggingAspect(AttributeTargetTypes="ConsoleApplication1.*")];3) определение конкретных целевых классов и методов в XML-файлеPostSharp. Так можно определять точки внедрения, не меняя67исходных текстов приложения (однако его зависимость от PostSharpостается).<?xml version="1.0" encoding="utf-8"?><Project xmlns="http://schemas.postsharp.org/1.0/configuration"><Multicast xmlns:my="clr namespace:MyCustomAttributes;assembly:MyAssembly"><my:AutoDataContractAttributeAttributeTargetTypes="MyNamespace.Customer" /></Multicast></Project>ЛИСТИНГ 16.