Aspect. Net Framework и его применение в задаче протоколирования

М. К. Грачев

ASPECT.NET FRAMEWORK И ЕГО ПРИМЕНЕНИЕ В ЗАДАЧЕ ПРОТОКОЛИРОВАНИЯ

1. Введение. За долгие годы существования методологий программирования разработчиками было создано и применено значительное число различных подходов к созданию программного обеспечения (ПО). Без сомнения, наиболее признанным по праву считается объектно-ориентированный подход (ООП) [1]. За последние десятилетия он практически монопольно укоренился в разработке ПО и является стандартом. ООП решил огромное число проблем, существовавших, к примеру, в процедурном подходе. Разбиение элементов предметной области на классы позволило многократно упростить и структурировать исходный код программ. Однако с ООП проблема структурированности все же не решается до логического конца. Всегда остается функциональность в рамках метода, класса или целых компонент, не поддающаяся бесследному вынесению за пределы места в коде, из которого она вызывается. Используя принцип функционального дизайна [2], можно вынести функциональность, решающую ровно одну бизнес-задачу, из класса во множество элементарных классов, четко разграниченных с точки зрения функциональности и сущностей предметной области. Однако фрагменты исходного кода, обеспечивающие взаимодействие этого множества классов, все равно сохранятся и, более того, будут распространены по исходному коду программы в целом, ухудшая тем самым структурированность и возможность дальнейшей поддержки. Даже детальное проектирование модулей ПО с применением принципа функционального дизайна физически не может решить эту задачу в рамках одной лишь ООП методологии.

В качестве дальнейшего развития ООП и средства для решения некоторых задач, не вписывающихся в рамки ООП, была создана аспектно-ориентированная методология программирования [3] (АОП). Сравнительно современная методология, созданная Грегором Кикжалесом [4] почти 10 лет назад, открывает большие перспективы для разработки ПО, позволяя эффективно решать проблемы, с которыми многие из разработчиков уже смирились. Далее в п. 4 описан проект Aspect.NET [5-7] - инфраструктура для разработки ПО с использованием АОП методологии, созданная для платформы Microsoft.NET [8] и по некоторым параметрам положительно отличающаяся от аналогов, описанных в п. 2. В п. 6 представлены возможности применения компоненты системы - Aspect.NET Framework на популярном, с практической точки зрения, примере внедрения протоколирования на базе библиотеки log4net [9] в модули готового ПО. Задача внедрения протоколирования выбрана не случайно, так как эффективность и простота решения этой трудоемкой и рутинной задачи с применением комплекса средств Aspect.NET способны выявить высокую практическую пользу описываемой системы и АОП методологии в целом.

2. Обзор существующих инструментариев. Г. Киджалес является создателем первого практического воплощения АОП методологии - проекта AspectJ [10]. Именно

Грачев Михаил Константинович — аспирант кафедры информатики математико-механического факультета Санкт-Петербургского государственного университета. Под руководством проф. В. О. Сафонова занимается диссертацией на тему «Реализация комплекса средств инструментальной поддержки аспектно-ориентированной методологии программирования Aspect.NET Framework и его внедрение в процессы разработки с использованием Microsoft Visual Studio». E-mail: mikhail.gratchev@mail.ru.

© М. К. Грачев, 2008

AspectJ является на данный момент самым распространенным инструментарием для создания программ, использующих АОП для платформы Java [11]. Только в последние пару лет, благодаря инициативе программистов-энтузиастов, АОП медленными темпами стал проникать в реальные коммерческие проекты. В то же время среди более чем десятка АОП инструментариев, созданных для популярнейшей платформы Mi-crosoft.NET, существует не так уж много приемлемо развитых реализаций.

Проекты Weave.NET [12], NAsped; [13], Aspect# [14] и Spring.NET [15] отличает то, что они используют динамическое внедрение [16], описание правил внедрения в XML форме. NAsped и Spring.NET были портированы с Java платформы. У обоих отсутствует графический интерфейс. Phx.Morph [17] применяет статическое внедрение [16] и не имеет графического интерфейса. Некоторые из разработок явно или неявно являются вторичными копиями разработок для платформы Java и часто отстают от своих аналогов, будучи созданными для платформы Microsoft. NET, но в контексте платформы Java. Таким образом, невольно приходится отказываться от использования некоторых интересных возможностей, специфичных для платформы .NET. Большинство из них страдает от непрокомментированного и непрофессионально написанного исходного кода, отсутствия документации, а эти факторы нельзя недооценивать, так как именно они ключевые при принятии решения системными аналитиками о целесообразности применения сторонних компонент в серьезных коммерческих разработках. Низкая производительность большинства из существующих инструментариев под Mi-crosoft.NET обусловлена использованием либо подхода исполнения в реальном времени, либо неэффективно реализованных механизмов рефлексии и инструментирования. Отсутствие приемлемого графического интерфейса, который мог бы в значительной мере уменьшить время освоения инструментария и повысить его эффективность, заставляют отказаться от перспективы применения большинства инструментариев в реальных коммерческих проектах.

3. Основные термины АОП. Среди основных понятий АОП, по большей части введенных Грегором Кикжалесом, можно выделить следующие:

• сквозная функциональность - логически связанная функциональность, распространенная, в зависимости от уровня абстракции, в рамках метода, класса, модуля или всей программы. Примерами сквозной функциональности могут послужить поддержка протоколирования, поддержка объектной модели базы данных, многопоточной безопасности, работы с транзакциями баз данных;

• аспект - модуль, содержащий в себе логически связанную функциональность, описанную в терминах действий, типовых объявлений и правил внедрения (в некоторых реализациях правила внедрения обособлены от аспекта);

• правило внедрения - формула, на определенном языке задающая связи между целевым модулем и аспектом. Правила впоследствии используются компоновщиком для интеграции аспектов в целевой модуль. Правила могут быть основаны на именах членов классов, именах самих классов, именах пространств имен и видах инструкций программного потока. Они могут содержать логические операции, регулярные выражения и вспомогательные конструкции, обеспечивающие точное позиционирование связей. Например, правило внедрения может выглядеть так: «Перед всеми конструкторами классов, имена которых заканчиваются на строку “singleton” не, из пространства имен с названием, содержащим строку “test”»;

• целевой модуль - откомпилированная сборка, в которую будет впоследствии внедряться аспект;

• точка внедрения - инструкция в потоке управления целевой сборки, относительно

которой (например: до, после или вместо) будут интегрированы инструкции, связанные с использованием функциональности аспекта (вызов методов аспекта, скопированные объявления типов из аспекта);

• действие - метод, содержащийся в аспекте. Как правило, именно его вызов внедряется в целевой модуль;

• типовые объявления - объявления членов классов или самих классов, предназначенные для внедрения в целевой модуль;

• компоновщик - программа для основанного на правилах внедрения поиска точек внедрения в целевом модуле и последующей интеграции в них действий и типовых объявлений аспекта.

Стандартная схема работы компоновщика при статическом внедрении такова:

1) извлечение правил внедрения из сборки с аспектом либо какого-нибудь другого указанного файла;

2) осуществление поиска в программном потоке целевой сборки точек внедрения, соответствующих найденным ранее правилам;

3) для каждой точки внедрения встраивание в целевой модуль типового объявления или вызова действия.

4. Основы технологии Aspect.NET и Aspect.NET Framework. Проект As-pect.NET основан профессором кафедры информатики математико-механического факультета Санкт-Петербургского государственного университета В. О. Сафоновым в 2002 г. В настоящее время над проектом работает группа аспирантов и студентов под его руководством. Создавая АОП инструментарий для перспективнейшей на тот момент платформы Microsoft.NET, В. О. Сафонов, с фундаментальной точки зрения, по-новому интерпретировал идеи Кикжалеса, применяя их к широким возможностям платформы .NET.

Аспекты в Aspect.NET определяются при помощи описания классов со специальными аннотациями на метаязыке Aspect.NET ML, независимого от выбранного языка .NET платформы. Одна из компонент инфраструктуры Aspect.NET ответственна за конвертирование Aspect.NET ML аннотаций в пользовательские атрибуты, предназначенные для использования другими компонентами Aspect.NET. Таким образом, информация об аспектах, включающая правила внедрения, хранится в виде пользовательских атрибутов в метаданных сборки. Благодаря такому подходу, поддержка возможности создания аспектов на любом из существующих и будущих .NET языков занимает минимальное время.

Метаязык Aspect.NET.ML и его возможности подробно рассмотрены в статьях [5, 6]. Приведем пример простейшего аспекта «Test» с одним действием «TestWriteAction», выводящего на консоль строку «test» перед вызовом любого метода с именем, начинающимся на «Write»:

%aspect Test public class Test {

%rules

%before %call Write*

public static void TestWriteAction

{

Console.WriteLine("test");

}

}

Компоновщик Aspect.NET реализован на основе сравнительно новой инфраструктуры построения оптимизирующих компиляторов Microsoft Phoenix RDK [18]. В частности, были задействованы ее высокоуровневые сервисы и библиотеки API для анализа, создания и модификации .NET сборок. Компания Microsoft имеет большие планы, связанные с этой технологией, что во многом повлияло на широту предоставленной функциональности и высокую производительность библиотеки.

Поиск точек внедрения и внедрение функциональности аспекта в Aspect.NET производятся статически, благодаря чему достигается максимальная производительность по сравнению с динамическим внедрением (Aspect#) и внедрением во время выполнения загрузки сборки (Weave.NET). Компоновщик работает в два прохода: поиск точек внедрения и собственно внедрение. Между двумя проходами пользователю предоставляется удобная и новая, по сравнению с другими инструментариями, возможность просмотреть найденные точки внедрения и отключить какие-либо нежелательные из них. Она достигается через реализованный нами графический интерфейс системы -Aspect.NET Framework - путем отображения иерархии найденных точек по модулям, классам, методам и параллельного отображения исходного кода целевого модуля (при условии наличия отладочной информации модуля).

Aspect.NET Framework реализован на основе Microsoft Visual Studio SDK [19] - наиболее функционально богатого API, который позволяет практически неограниченно влиять на все аспекты среды разработки Microsoft Visual Studio: модифицировать обработчики любых событий среды разработки, преобразовывать окна, панели и мастера. Microsoft Visual Studio SDK дает возможность контролировать подсветку исходного кода и анализ языков программирования, создавать/менять отладчики различных языков.

Процессы поиска и интеграции точек внедрения реализованы как задачи MS-Build [20] и запускаются незаметно для разработчика.

5. Постановка задачи протоколирования. Данная задача состоит в выводе в указанный приемник некой информации о состоянии программы в процессе ее выполнения. Она - наиболее известный пример применения АОП. Решение именно этой задачи ассоциируется с АОП у большинства программистов, обладающих базовыми знаниями о ней. В наши дни протоколирование - важнейшее требование к практически любому коммерческому программному продукту.

Наиболее популярным инструментарием для протоколирования является log4net -адаптация самого используемого инструментария протоколирования для платформы Java - log4j [21]. Log4net позволяет выводить информацию в огромное множество приемников: от консоли и XML файлов до баз данных и удаленных компьютеров по всем существующим протоколам связи. Log4net настраивается через конфигурационный файл сборки. Помимо указания приемника в конфигурационном файле, от программиста требуется добавить в сборку ссылку на библиотеки log4net, вставить в классы ссылку на объект-протокол и добавить в оговоренные заранее места вызовы методов прокола, передавая им информацию для протоколирования. Проблема состоит в том, что количество оговоренных мест в программах растет вместе с количеством исходного кода, и искать эти места программистам приходится вручную. Вот лишь небольшой фрагмент исходного кода с объявленной ссылкой на объект-протокол «log» и тремя вызовами метода протокола:

internal class Area : IArea {

/// <summary>

/// Logger object

/// </summary>

private static ILog log =

LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType) ;

internal Area

{

log.Debug("Area constructor begin");

EntityCollection<ModuleInstanceEntity> ecmie = new EntityCollection<ModuleInstanceEntity>(); adapter.FetchEntityCollection(

ecmie, area.GetRelationInfoModuleInstance());

foreach

{

IModuleInstance moduleInstance = new ModuleInstance(mie, adapter);

_modules.Add(moduleInstance);

log.DebugFormat(

"New instance of module ’{0}’ was added to area.", moduleInstance.Module.Name);

}

log.Debug("Area constructor end");

}

}

Например, требования реального заказчика к протоколированию могут быть следующие:

1. Все catch() блоки должны записывать информацию о перехваченном исключении в журнал (с уровнем ошибки или предупреждения).

2. Протоколирование следует вставлять во все публичные методы. В текст сообщения следует включить все входящие и выходящие параметры. Также для отладочных целей разработчики могут добавить дополнительное протоколирование.

3. Протоколируемое сообщение не должно расползаться на несколько строк. Это усложняет чтение журналов.

4. Название метода, из которого был сделан протоколирующий вызов, должно быть добавлено в начало строки протокольного сообщения. Например, «GetProduct: Pro-ductId is null».

5. Вызов ILog.Info() (протоколирования информационного уровня) должен быть подставлен во все ключевые места системы. Например: запуск программы, завершение каких-либо действий, перезагрузка кэша и т. д. Подобные вызовы не следует использовать для запросов и других часто случающихся событий.

6. Если отладочное сообщение содержит один и более параметров, настоятельно рекомендуется использовать метод ILog.DebugFormat() вместо вычисления текста сообщения непосредственно в коде.

Как показывает практика, требования заказчика могут сильно меняться, что приводит к еще одной проблеме - необходимо пересматривать всю функциональность, связанную с протоколированием, и делать соответствующие коррективы. Таким образом, трудозатраты на внедрение и поддержку протоколирования очень существенны.

6. Решение задачи при помощи АОП и Aspect.NET Framework. Изначально поставленная автором цель создания визуальной части Aspect.NET - компоненты Aspect.NET Framework - заключалась в повышении удобства и эффективности применения АОП конечными разработчиками. Учитывая это, а также популярность задачи протоколирования и того, что требования к протоколированию очень часто являются типичными, возникла идея свести работу по внедрению протоколирования, даже для малоопытного разработчика, всего до нескольких действий мышью (в простом случае). При применении АОП программисту не надо заботиться о протоколировании в процессе разработки. Достаточно лишь один раз перевести требования к протоколированию в правила внедрения и создать один аспект с одним типовым объявлением члена - ссылки на объект протокол и действиями, обертывающими несколько методов класса протокола. Есть возможность также использовать базовый аспект, готовый к применению.

Для визуализации процесса задания правил внедрения протоколирования был выбран способ, аналогичный мастеру создания правил (Rules Wizard) фильтрации писем в Microsoft Outlook 2007 [22]. Этот способ удобен тем, что позволяет специфицировать правила от общего к частному, последовательно предлагая пользователю наборы условий, сформированных на основе всех предыдущих выборов пользователя.

Реализованный мастер генерирует правила из логических связок на основе параметризованных шаблонов, соответствующих ответам пользователя. При необходимости пользователю дается возможность посмотреть и отредактировать полученные правила внедрения на языке Aspect.NET ML. Как показал опыт использования мастера, в простых случаях такая необходимость возникает редко. Далее полученные правила сохраняются и применяются так же, как и при обычной работе с Aspect.NET Framework: по явному запросу разработчика либо неявно и незаметно для разработчика, внедряясь в процесс построения сборки посредством MSBuild задач.

Вот базовый набор параметризованных шаблонов правил, существующий в реализованном мастере:

1) для {смещение} каждого catch блока внутри {модификаторы} {маска имени} метода выполнить {действие};

2) для {смещение} каждого finally блока внутри {модификаторы} {маска имени} метода выполнить {действие};

3) для {смещение} каждого {модификаторы} {маска имени} метода из {маска имени} пространства имен выполнить {действие};

4) для {смещение} каждого {модификаторы} {маска имени} метода, помеченного атрибутом {маска имени} выполнить {действие};

5) для {смещение} каждого присвоения {модификаторы} {маска имени} переменной в классе {маска имени} выполнить {действие};

6) для {смещение} каждого обращения к {модификаторы} {маска имени} переменной в {маска имени} классе выполнить {действие};

7) для {смещение} вызова внешнего {модификаторы} {маска имени} метода выполнить {действие};

8) для {смещение} {модификаторы} {маска имени} конструктора выполнить {действие},

где

• {смещение} - смещение точки внедрения действия. Принимает значения «перед» и «после»;

• {модификаторы} - множество модификаторов доступа типа и членов типа, а также других их модификаторов, по которым можно осуществлять поиск. Допустимое множество значений: «public», «private», «protected», «internal», «static», «sealed», «readonly», «abstract», «new», «virtual», «volatile», «unsafe»;

• {маска имени} - маска полного имени (состоит из: имени пространства имен, имени класса, имени метода или имени поля), относительно которой происходит поиск точки внедрения. Представлена в виде регулярного выражения, сопоставляемого с полным именем точки в программном потоке. Значение «*» эквивалентно любому имени метода и поля. Маска имени «*.*Reader.*» из-за наличия «.*» на конце соответствует уже не члену класса, а непосредственно классу, имя которого оканчивается на «Reader»;

• {действие} - действие для выполнения в данной точке внедрения. Есть возможность выбрать и настроить одно из множества существующих либо подключить аспектную сборку и сослаться на действия из нее. Примерами предустановленных действий являются:

— протоколирование информации о перехваченном (текущем) исключении в формате {формат записи},

— протоколирование информации о текущем стеке вызовов в формате {формат записи},

— протоколирование информации о параметрах текущего метода и их значений в формате {формат записи},

— протоколирование информации об атрибутах текущего метода в формате {формат записи},

— протоколирование информации о старом и новом значении переменной в месте присвоения ей значения в {формате записи},

— протоколирование информации о значении переменной в месте ее использования в {формате записи};

• {формат записи} - строка, состоящая из текста и специальных предопределенных блоков, заключенных в символы «{» и «}», подменяемых при выводе на соответствующие им значения. Примером предопределенного блока является «{method_name}». Он заменяется на название метода, в котором действие, использующее этот формат записи, было вызвано. Более сложный пример блока формата записи «{$parameters {parameter_name}:{parameter_type}={parameter_value} }» позволяет сформировать текст из разделенных пробелами характеристик входных параметров того метода, в который было внедрено связанное действие. Элемент Sparameters означает итерацию по всему множеству доступных параметров метода. Применение предложенного нами комплекса средств Aspect.NET на исходном коде

коммерческого программного продукта, предназначенного для генерации и модификации полнофункциональных Интернет-магазинов на базе технологии ASP.NET 2.0 (C# 2.0), выявило возможность исключения всех строк, реализующих протоколирование

(по достаточно точно заданным правилам). Таким образом, исходный код продукта размером в 180 000 строк кода уменьшился до 171 000, т. е. примерно на 5%. Внедрение и отладка протоколирующей функциональности в проект впоследствии заняли менее одного человеко-дня у разработчика, который до этого никогда не использовал Aspect.NET Framework и не был детально ознакомлен с АОП методологией. По мнению упомянутого разработчика, наглядность процесса задания правил, широкий диапазон предопределенных шаблонов вместе с простотой интерфейса освободили его от необходимости редактировать Aspect.NET.ML вручную.

Мастер в дальнейшем может быть использован в качестве основы для создания других аналогичных мастеров, решающих иные типовые задачи: обеспечение безопасной многопоточности, обеспечение целостности данных при работе с базами данных и т. д.

7. Заключение. Мастер внедрения протоколирования позволяет значительно сократить время решения по-настоящему трудоемкой типовой задачи, доказывая практическую пользу АОП методологии и адекватность развития проекта Aspect.NET в сторону расширения функциональности и повышения комфорта использования инструментария конечными разработчиками.

Документация, примеры и дистрибутив системы доступны на сайте Microsoft Academic Alliance [23]. Результаты проекта были представлены на научных конференциях, опубликованы в международных и отечественных изданиях. Реализованный инструментарий был высоко оценен многими пользователями.

Summary

Grachev M. K. Aspect.NET Framework and its application in journaling problem.

The paper describes aspect-oriented programming (AOP) methodology and Aspect .NET — AOP tool that we created for Microsoft.NET platform. The article discovers basic ideas and terms of AOP paradigm, main principles and technical details of Aspect.NET. We propose a way to solve the task of logging by means of the effective graphical user interface (GUI) of Aspect.NET Framework component and log4net library on top of Aspect.NET infrastructure. Usage of the GUI significantly reduces time and effort needed for integration and maintenance of logging functionality within existing applications. The paper presents a set of logging support related capabilitiesimplemented in Aspect.NET Framework. The GUI uses Microsoft Outlook like wizards and a predefined set of customizable parameterized templates that cover the most common and popular cases of logging application. Due to that customization it can be extended and modified to be effectively used for another common tasks like secure multithreading and data integrity support.

Key words: aspect-oriented programming, AOP, programming methodologies, aspect, Aspect.NET.

Литература

1. Booch G. Object-Oriented Analysis and Design with Applications. — USA: Addison-Wesley, 2007. — 430 p.

2. Гамма Э., Хэлм Р., Джонсон Р., Влиссидес Дж. Приемы объектно-ориентированного проектирования: Паттерны проектирования / Пер. с англ.; Под ред. А. Слинкина. — СПб.: Питер, 2001. — 336 с.

3. Kiczales G., Lamping J., Mendhekar A. Aspect-oriented programming // Proc. of the European Conference on Object-oriented Programming (ECOOP) in Finland — Springer-Verlag, June 1997. — Heidelberg, Germany, 1997. - P. 365-389.

4. Официальная страница Грегора Кикжалеса // http://www.cs.ubc.ca/ gregor/.

5. Safonov V. O. Aspect.NET: a new approach to aspect-oriented programming // NET Developer’s Journal. - 2003. - N 4. - P. 36-40.

6. Safonov V. O. Aspect.NET: concepts and architecture // NET Developer’s Journal. — 2004. — N 10. - P. 44-48.

7. Safonov V. O., Grigoriev D. Aspect.NET: concepts and architecture // NET Developer’s Journal. — 2005. — N 7. — P. 28—33.

8. Simmons C., Rofail A. The Microsoft .Net Platform and Technologies. — Indianapolis, USA: Prentice Hall PTR, 2001. — P. 5—10.

9. Официальный сайт проекта Apache log4net // http://logging.apache.org/log4net/.

10. Miles R. AspectJ Cookbook. — Cambridge, USA: O’Reilly, 2004. — 354 p.

11. Flanagan D. Java in a Nutshell. — Cambridge, USA: O’Reilly, 2005. — 1224 p.

12. Официальный сайт проекта Weave.NET // www.dsg.cs.tcd.ie/sites/Weave.NET.html.

13. Официальный сайт проекта Puzzle.NET и инструмента NAspect // http://www. puzzleframework.com/wikiengine/WikiPageViewer.aspx?ID=80.

14. Официальный сайт проекта Aspect# // http://aspectsharp.sourceforge.net/.

15. Официальный сайт проекта Spring.NET // Aspect Oriented Programming with Spring.NET http://www.springframework.net/doc-latest/reference/html/aop.html.

16. Frakes W. B. OP Technologies and statement of the problem // Proc. of the 6th Intern. Conference on Software Reuse, ICSR-6. June 2000. — Vienna, Austria, 2000. — P. 390—397.

17. Официальный cайт проекта Wicca и его компоненты Phx.Morph // http://www1. cs.columbia.edu/ eaddy/wicca/.

18. Официальный сайт проекта Microsoft Phoenix // http://research.microsoft.com/phoenix.

19. Visual Studio SDK в MSDN // http://msdn2.microsoft.com/en-us/library/bb166441 (VS.80). aspx.

20. Детальное описание MSBuild задач в MSDN // http://msdn2.microsoft.com/en-us/library/ 0k6kkbsd.aspx.

21. Официальный сайт проекта log4j // http://dmi.ensica.fr/doc/Java/log4j/.

22. Campbell T., Hassell J. Outlook 2007: Beyond the Manual. — Berkeley, CA, USA: Apress, 2007. — P. 47—51.

23. Страница проекта Aspect.NET на сайте Microsoft Academic Resource Center // https:// www.academicresourcecenter.net/curriculum/pfv.aspx?ID=6801.

Статья рекомендована к печати проф. А. Н. Тереховым.

Статья принята к печати 29 апреля 2008 г.