[img_assist | nid = 4980 | title = | desc = | link = none | align = right | width = 150 | height = 188] Методология AOP — это всего лишь методология. Чтобы быть полезным в реальном мире, оно должно быть реализовано или реализовано. Как и в любой методологии, она может быть реализована различными способами. Например, одна реализация спецификации методологии ООП состоит из языка Java и таких инструментов, как компилятор. Аналогичным образом, каждая реализация AOP включает в себя указание языка или структуры и связанных инструментов. Как и любая другая методология программирования, реализация AOP состоит из двух частей:
- Спецификация языка описывает языковые конструкции и синтаксис для выражения реализации основных и сквозных задач.
- Реализация языка проверяет соответствие кода спецификации языка и переводит код в исполняемую форму. Обычно это выполняется компилятором или агентом времени выполнения
Эта статья основана на главе 1 из AspectJ в действии, второе издание Рамниваса Ладдада. Предоставлено Manning Publications . Все права защищены.
Спецификация языка AOP
Любая реализация AOP должна указывать язык для реализации отдельных задач и язык для реализации правил объединения реализации задач. Хотя я говорю на двух разных языках, система AOP может не различать эти две части. Это, вероятно, будет иметь место в будущих языках АОП. Давайте внимательнее посмотрим на эти две части.
ОСУЩЕСТВЛЕНИЕ КОНЦЕРНОВ
Как и в других методологиях, проблемы системы реализованы в модулях, которые содержат данные и поведение, необходимые для предоставления их услуг. Например, модуль, который реализует основную часть задачи кэширования, будет поддерживать коллекцию кэшированных объектов, управлять достоверностью кэшированных объектов и обеспечивать ограниченное потребление памяти. Для реализации основных и сквозных задач мы обычно используем стандартные языки, такие как C, C ++ и Java.
СПЕЦИФИКАЦИЯ ПРАВИЛ ПЕТАНИЯ
Правила ткачества определяют, как интегрировать реализованные задачи для формирования окончательной системы. Например, как только вы реализуете основную часть проблемы кэширования в модуле (возможно, через стороннюю библиотеку классов), вам необходимо ввести кэширование в систему. Правило ткачества в этом случае определяет данные, которые должны быть
кешируется информация, которая формирует ключ в кеш-хранилище и т. д. Затем система использует эти правила для получения и обновления кэша из указанных операций.
Сила АОП заключается в экономичном способе выражения правил ткачества. Например, для модульной задачи отслеживания в листинге 1 вы можете указать, чтобы регистрировать все публичные операции в системе всего за несколько строк кода.
Листинг 1: Реализация бизнес-логики вместе со сквозными задачами
public class SomeBusinessClass extends OtherBusinessClass {
... Core data members
... Log stream #5
... Cache update status #3
... Concurrency control lock #2
... Override methods in the base class
public void someOperation1(<operation parameters>) {
... Ensure authorization #1
... Lock the object to ensure thread-safety #2
... Ensure cache is up-to-date #3
... Start transaction #4
... Log the start of operation #5
... Perform the core operation
... Log the completion of operation #5
... Commit or rollback transaction #4
... Unlock the object #2
}
... More operations similar to above addressing multiple concerns
}
# 1 Проверка безопасности
# 2 Контроль параллелизма
# 3 Кэширование
# 4 Управление транзакциями
# 5 Трассировка
Например, здесь приведена спецификация плетения для аспекта трассировки.
-
Правило 1: создайте объект регистратора.
-
Правило 2: регистрируйте начало каждой публичной операции.
-
Правило 3: регистрируйте завершение каждой публичной операции.
Это гораздо более кратко, чем изменение каждой общедоступной операции для добавления кода регистрации. Поскольку задача отслеживания имеет модульную структуру вне класса, она может фокусироваться только на основной проблеме следующим образом.
public class SomeBusinessClass extends OtherBusinessClass {
... Core data members
... Override methods in the base class
public void someOperation1(<operation parameters>) {
... Perform the core operation
}
... More operations similar to above
}
Сравните этот класс с классом, приведенным в листинге 1.1. Весь код для трассировки — вспомогательные проблемы с точки зрения класса — был удален, и осталась только основная бизнес-логика. Как мы увидим в следующем разделе, реализация AOP объединит классы и аспекты для создания тканого исполняемого файла.
Правила ткачества могут быть очень общими или очень конкретными в том, как они взаимодействуют с основными модулями. Например, в предыдущем примере ведения журнала правилам ткачества не требовалось упоминать какие-либо конкретные классы или методы в системе. На другом конце спектра правило ткачества может указывать, что бизнес-правило, которое должно применяться только к определенным методам, таким как кредитные и дебетовые операции в классе Account или те, которые содержат аннотацию @ReadOnly. Специфика правил плетения определяет уровень связи между аспектом и основной логикой.
Язык, используемый для определения правил плетения, может быть естественным продолжением этого языка или чем-то совершенно другим. Например, реализация AOP, использующая Java в качестве базового языка, может вводить новые расширения, которые хорошо сочетаются с основным языком Java, или она может использовать отдельный язык на основе XML для выражения правил ткачества.
Внедрение AOP
Реализация AOP выполняет два логических шага: сначала она объединяет отдельные задачи с использованием правил ткачества, а затем преобразует полученную информацию в исполняемый код. Таким образом, реализация AOP требует использования процессора — ткача — для выполнения этих шагов.
Ткач может быть реализован различными способами. Простой способ — перевод с источника на источник. Здесь ткач обрабатывает исходный код для отдельных классов и аспектов и создает тканый исходный код. Компилятор обычного языка может затем обработать сформированный код. Компилятор аспекта затем передает этот преобразованный код в компилятор базового языка для получения окончательного исполняемого кода. Используя этот подход, реализация AOP на основе Java преобразует отдельные исходные входные файлы в тканый исходный код Java, а затем позволяет компилятору Java преобразовывать его в байтовый код (фактически этот метод реализации использовался в ранних реализациях AspectJ). Этот простой подход имеет несколько недостатков, поскольку исполняемый код не может быть легко прослежен до записанных исходных файлов. Например,трассировки стека будут указывать номера строк в тканых исходных модулях.
Другой подход может заключаться в том, что исходный код сначала должен быть скомпилирован в файлы классов с использованием компилятора базового языка. Затем файлы классов будут передаваться в компилятор аспектов, который вплетает аспекты в файлы классов для создания тканых файлов классов. На рисунке 1 показана схема реализации языка AOP на основе компилятора.
[img_assist | nid = 4975 | title = | desc = Figure 1 Реализация языка AOP, предоставляющая ткач в форме компилятора. Компилятор берет реализацию основных и сквозных задач и объединяет их вместе, чтобы сформировать окончательную систему. | Link = none | align = undefined | width = 600 | height = 303]
Также может быть возможно подтолкнуть процесс плетения близко к выполнению системы. Например, если реализация AOP основана на Java, специальный загрузчик классов или агент виртуальной машины могут выполнять переплетение. Такая реализация сначала загрузит байт-код для аспектов, поместит их в классы по мере их загрузки и предоставит эти тканые версии классов в базовую виртуальную машину (ВМ).
Еще одна возможность реализации заключается в использовании автоматически созданных прокси. В этом случае каждый объект, который требует переплетения, может быть заключен в прокси. Такая реализация обычно хорошо работает в сочетании с другой средой, которая контролирует создание объектов. Таким образом, фреймворк может обернуть каждый созданный объект в прокси.
До сих пор мы рассматривали механику системы АОП. Теперь мы рассмотрим основные концепции, стоящие за АОП.
К настоящему времени должно стать очевидным, что системы АОП помогают в модульности сквозных задач. Однако, как и многие другие решения, такие как инструменты прямого байтового кода, например, CGLIB или ASM, прямое использование шаблона проектирования прокси или даже метапрограммирование. Как вы узнаете АОП из всех этих других вариантов? Чтобы выяснить это, нам нужно объединить основные характеристики систем АОП в общую модель. Если система соответствует этой модели, это система AOP; в противном случае это не так.
Для реализации сквозной задачи система AOP может включать в себя многие из следующих концепций:
-
Идентифицируемые точки в исполнении системы: такие точки могут включать выполнение методов, создание объектов или создание исключения. Такие идентифицируемые точки в системе называются точками соединения . Обратите внимание, что точки соединения присутствуют во всех системах, даже в тех, которые не используют AOP, поскольку точки соединения являются просто точками во время выполнения системы. АОП просто дает идентифицирует и классифицирует эти пункты.
-
Конструкция для выбора точек соединения: Реализация сквозной задачи потребует выбора определенного набора точек соединения. Например, рассмотренный ранее аспект трассировки должен выбирать только общедоступные методы в системе. В AOP конструкция pointcut выбирает любую точку соединения, которая удовлетворяет критериям. Это похоже на запрос SQL, выбирающий строки в базе данных (мы сравним AOP с базами данных в разделе 1.7.2). Pointcuts также собирают контекст в выбранных точках. Например, pointcut может собирать аргумент метода как контекст. Концепция точек соединения и конструкция точек вместе образуют модель точек соединения системы AOP .
-
Конструкция для изменения поведения программы. После того, как pointcut выбирает точки соединения, мы должны дополнить эти точки соединения дополнительным или альтернативным поведением. Например, при реализации трассировки вам необходимо войти в публичные методы. Конструкция с рекомендациями в AOP предоставляет возможность для этого. Совет добавляет поведение до, после или вокруг выбранных точек соединения. Around advice окружает выполнение точки соединения и может выполнять ее ноль или более раз. Совет — это форма динамического перекрестного взаимодействия, так как он влияет на работу системы.
-
Конструкция для изменения статической структуры системы. Иногда для эффективной реализации динамического перекрестного разреза вам необходимо изменить статическую структуру системы. Например, при реализации трассировки вам может понадобиться ввести поле регистратора в каждый отслеживаемый класс. Конструкции объявления между типами делают возможными такие модификации. Кроме того, в некоторых ситуациях вам может потребоваться обнаружить определенные условия, обычно наличие определенных точек соединения, перед выполнением системы. Конструкции объявления времени плетения допускают такие возможности. В совокупности все эти механизмы называются статическими перекрестными соединениями, учитывая их влияние на статическую структуру, а не на динамические изменения поведения при выполнении системы.
-
Модуль для выражения всех сквозных конструкций. Поскольку конечной целью AOP является наличие модуля, который внедряет сквозную логику, вам необходимо место для выражения этой логики. Аспектная конструкция обеспечивает такое место. Аспект будет содержать рекомендации, срезы в и статические сквозные конструкции. Аспект может быть связан с другими аспектами аналогично тому, как класс относится к другим. Кроме того, аспекты являются частью системы, а аспекты используют систему (например, классы в ней) для выполнения своей работы.
На рисунке 2 показаны все эти игроки и их отношения друг с другом в системе AOP.
[img_assist | nid = 4976 | title = | desc = Рисунок 2: Типовая модель систем AOP. Обратите внимание, что не каждая система будет реализовывать каждую часть модели. | Link = none | align = undefined | width = 601 | height = 365]
Каждая система AOP может выбрать подмножество модели. Например, Spring AOP не реализует объявления времени переплетения из-за его акцента на природе времени выполнения. С другой стороны, модель точек соединения настолько важна для АОП, что каждая система АОП должна поддерживать ее. Все остальное вращается вокруг модели точки соединения.
Когда вы сталкиваетесь с решением, которое модульно пересекает проблемы, попробуйте сопоставить его с общей моделью AOP. Если вы можете, то это действительно система AOP. В противном случае это альтернативный подход к решению проблемы сквозных задач. В следующем разделе мы рассмотрим некоторые общеизвестные альтернативы АОП.
Проблема с адресами AOP не нова. Проблемы аудита, управления транзакциями, безопасности и т. Д. Возникли, как только мы начали внедрять нетривиальные программные системы. Следовательно, существует много конкурентоспособных технологий для решения одной и той же проблемы: платформы, генерация кода, шаблоны проектирования и динамические языки. Давайте посмотрим на эти альтернативы. Обратите внимание, что, хотя я сравниваю эти методы в качестве альтернативы АОП и (что неудивительно) показывает, как АОП затмевает каждый из них, когда дело касается решения сквозных задач, я не имею в виду, что эти методы бесполезны. Каждый из этих методов подходит для ряда проблем. На самом деле, АОП может работать вместе с этими методами довольно хорошо. Кроме того, в некоторых случаях АОП может улучшить их реализацию.
Каркасы
Фреймворки, такие как сервлеты и EJB, предлагают конкретные решения для целого ряда проблем. Например, спецификация сервлета предлагает платформу для обработки запросов, сделанных с использованием протокола HTTP. Учитывая, что каждая структура имеет дело с определенной проблемой, она также может предоставить некоторые решения для решения общих сквозных проблем в этом проблемном пространстве. Например, платформа сервлетов обеспечивает базовую поддержку для перехвата HTTP-запросов.
Точно так же EJB-инфраструктура решает широкий круг сквозных задач, таких как управление транзакциями и безопасность. В спецификации EJB3 он даже предоставляет ограниченную поддержку перехватчиков, которые в определенной степени соответствуют целям AOP. Однако, как мы увидим позже, оно не является полным решением.
Обратите внимание, что вы можете использовать AOP вместе с базовой платформой. При таком расположении базовая структура имеет дело с целевой проблемой и позволяет аспектам решать сквозные проблемы. Например, базовая среда Spring имеет дело с внедрением зависимостей для конфигурации и абстракции корпоративных сервисов, чтобы изолировать bean-компоненты от деталей базовой инфраструктуры, в то же время используя AOP для решения сквозных задач, таких как управление транзакциями и безопасность.
Каркасные подходы к сквозным задачам часто, но не всегда, сводятся либо к использованию некоторой формы генерации кода, либо к реализации соответствующих шаблонов проектирования. Давайте рассмотрим два более подробно.
Генерация кода
Методы генерации кода переносят некоторую ответственность за написание кода с программиста на машину. Конечно, программисты должны писать код для самих генераторов. Эти методы представляют собой эффективные способы решения широкого спектра проблем и часто помогают повысить уровень абстракции. Они могут модулировать сквозные задачи, изменяя исходный код, такой как добавление уведомлений наблюдателей или создание дополнительных артефактов, таких как автоматические прокси-классы, таким образом заботясь об одном из недостатков непосредственного использования шаблонов проектирования — ручное изменение во многих местах.
Вариант генерации кода работает на уровне скомпилированного кода. Вместо создания исходного кода, который должен быть скомпилирован в машинный код, генератор кода напрямую создает машинный код. Для Java разница между генерацией на уровне исходного кода и генерацией байт-кода довольно мала, учитывая, как исходный код напрямую отображается в байт-код.
В Java 5 функция языка аннотаций позволяет добавлять дополнительную информацию к элементам программы. Методы генерации кода могут использовать эти аннотации для создания дополнительных артефактов (таких как код Java или файлы конфигурации XML). Java 5 даже предоставляет инструмент, инструмент обработки аннотаций (APT), чтобы упростить процесс. Однако APT заставляет понимать детали низкого уровня, такие как синтаксическое дерево, и это затрудняет его использование программистом, если он не приобретет определенные навыки. Неудивительно, что вы вряд ли увидите много не-каркасных программистов, использующих APT. AOP, с другой стороны, может предоставить более простые решения для обработки аннотаций, как мы увидим в оставшейся части книги.
Многие системы, особенно AspectJ, используют манипулирование байт-кодом в качестве основного метода при реализации AOP. Разница в том, как она использует технику как часть общей модели АОП. Во-первых, он предоставляет гораздо более простую модель программирования, облегчающую разработчику создание модульных сквозных реализаций без знания низкоуровневых деталей, таких как абстрактное синтаксическое дерево. По сути, он предоставляет язык, специфичный для предметной области (DSL), предназначенный для решения сквозных задач. Пользователь также изолирован от механизмов манипулирования байт-кодом, что не для слабонервных. Кроме того, ограничивая возможности, это подталкивает разработчиков к написанию лучшего кода. Короче говоря, хотя генерация кода способна делать все, что может делать AspectJ (и многое другое),AspectJ обеспечивает такой уровень дисциплины, который необходим для хорошей разработки программного обеспечения, когда дело касается решения сквозных задач.
Шаблоны проектирования
Шаблоны проектирования предоставляют понятные решения для повторяющихся проблем. Некоторые из повторяющихся проблем связаны с сквозными проблемами. Это должно быть большим сюрпризом, так как, хотя AOP всего около 10 лет, проблема сквозной обработки существовала до тех пор, пока мы создавали программные системы. В этом разделе мы рассмотрим некоторые шаблоны проектирования — наблюдатель, цепь ответственности, декоратор и прокси-сервер, а также перехватчик — которые помогают решать сквозные задачи. Вы увидите, что есть довольно много сходств, и на самом деле, вы можете рассматривать несколько шаблонов проектирования как реализацию АОП «бедняков».
НАБЛЮДАТЕЛЬ
Классическая техника в программировании пользовательского интерфейса — реагировать на такие события, как движение мыши и нажатие клавиши. Например, вы можете показать диалоговое окно при нажатии клавиши. Даже в корпоративных приложениях на стороне сервера архитектуры, ориентированные на сообщения, предполагают отправку и ответ на сообщения. Шаблон проектирования наблюдателя формирует основу для программирования события, чтобы отделить источник события (субъект) от респондента события (наблюдателя). Когда субъект изменяет свое состояние, он уведомляет всех наблюдателей об изменении, вызывая метод, такой как notify <ChangeType> (), передавая ему объект события, который инкапсулирует изменение.
Метод уведомления выполняет итерацию по всем наблюдателям и вызывает метод для каждого (в системах, ориентированных на сообщения, эти детали немного меняются, но общая схема остается неизменной). Вызываемый метод в наблюдателе включает в себя логику, подходящую для ответа на событие. Ключевым моментом модели наблюдателя является то, что субъект ничего не знает о том, какие конкретные объекты его наблюдают. Шаблон также поддерживает произвольное количество наблюдателей.
Совет АОП может внешне выглядеть как ответчик на событие. Тем не менее, есть некоторые важные различия. Во-первых, в АОП нет явного срабатывания «событий». Другими словами, вы не увидите вызовов, таких как notify <ChangeType> (), таким образом, разъединяя всю логику шаблона наблюдателя от класса субъекта. Во-вторых, контекст, собранный с помощью точек (эквивалентный информации, переносимой объектом «событие»), намного более гибок и мощен в АОП. Pointcuts может собрать только необходимое количество контекста, необходимого для логики совета. С типичной моделью события вы в конечном итоге пропускаете «все, что вам может понадобиться».
ЦЕПЬ ОТВЕТСТВЕННОСТИ
Шаблон цепочки ответственности (COR), как показано на рисунке 3, помещает цепочку обрабатываемых объектов перед целевым объектом. До или после вызова объекта команды обрабатываемые объекты могут выполнять дополнительную работу или прерывать цепочку.
Успешное использование шаблона COR имеет два предварительных условия: существует только один (или небольшое количество) целевых методов, и соответствующая среда уже поддерживает шаблон. Например, реализация фильтра в инфраструктуре Servlet реализует шаблон COR. Там он работает хорошо, потому что выполнены оба предварительных условия: он нацелен только на один метод — doService (), а код управления фильтрами реализован как часть самой платформы. В этой настройке некоторые грубые проблемы межсетевого взаимодействия — те, которые работают на уровне HTTP-запроса — могут быть модульными в фильтры сервлетов. Тем не менее, все, что должно выходить за рамки метода doService (), фильтр не предлагает решения.
[img_assist | nid = 4977 | title = | desc = Рисунок 3: Цепочка ответственности, реализованная в рамках сервлета. Цепочка фильтров позволяет применять дополнительную логику, такую как грубая защита, вокруг метода doService (). | Link = none | align = undefined | width = 599 | height = 234]
АОП работает аналогичным образом, за исключением того, что не имеет ни одного из предварительных условий. Вместо этого каждый аспект просто решает проблему, предлагая соответствующий код.
ДЕКОРАТОР И ПРОКСИ
Шаблон проектирования декоратора и прокси использует объект-оболочку, который может выполнять некоторую работу до, после или вокруг вызова обернутого объекта или его представления. Эта дополнительная работа может быть сквозной по своей природе. Например, каждый метод может выполнить проверку безопасности перед вызовом метода обернутого объекта.
[img_assist | nid = 4978 | title = | desc = Рисунок 4: Шаблон дизайна декоратора. Оригинальный объект оборачивается в декораторе, который представляет тот же интерфейс, что и декорированный объект. Каждый метод проходит через декорацию, которая может реализовать такие функции, как безопасность и транзакция | link = none | align = undefined | width = 479 | height = 365]
Непосредственное использование шаблонов проектирования декоратора и прокси-сервера для реализации сквозных задач требует значительных усилий. Тем не менее, эти шаблоны могут использоваться в качестве основного метода реализации как часть системы AOP. Spring Framework использует шаблон проектирования прокси для внутреннего использования, чтобы избежать его использования пользователям. Это мало чем отличается от техники манипулирования байт-кодом, громоздкой как метод программирования для решения сквозных задач, но совершенно прекрасной базовой технологии для реализации систем AOP.
Другой шаблон проектирования, перехватчик, часто используется вместе с шаблоном прокси-дизайна. Давайте сравним, как он противостоит AOP для сквозных задач.
INTERCEPTOR
Шаблон перехватчика позволяет выразить логику пересекающихся объектов в объекте перехватчика. Прикрепляя перехватчик к определенным элементам программы, вы можете задействовать логику перехватчика вокруг перехваченных элементов. Этот шаблон при использовании вместе с шаблоном дизайна прокси или декоратора предлагает разумное решение для широкого круга сквозных задач. Например, Java поддерживает создание динамических прокси, которые можно настроить с помощью перехватчика. Реализация шаблона перехватчика в целом и успешно требует значительного количества машин и, следовательно, лучше оставить на усмотрение платформы.
Давайте рассмотрим новейшую реализацию шаблона перехватчика в EJB3. Более ранние версии инфраструктуры EJB предлагали решение для определенного набора сквозных задач: управление транзакциями и безопасность на основе ролей, в первую очередь. EJB3 предлагает способ модульного решения специфичных для пользователя задач сквозного использования посредством подхода перехватчика.
public class TracingInterceptor {
private Logger logger = ...
@AroundInvoke
public Object trace(InvocationContext context) throws Exception {
logger.log("Entering " + context.getMethod().getName()
+ " in " + context.getBean().getClass().getName());
return context.proceed();
}
}
Затем вы можете применить перехватчик к целевым классам и методам, как показано в следующем фрагменте кода:
@Stateless
@Interceptors({TracingInterceptor.class})
public class InventoryManagementBean {
...
}
Вы можете выбрать конкретные методы, пометив каждый такой метод аннотацией @Interceptors. С другой стороны, вы можете объявить перехватчик как перехватчик по умолчанию, который применяется ко всем bean-компонентам, кроме тех, которые отказываются. Реализация EJB3 имеет несколько ограничений, например, перехватчик может применяться только к EJB, а не к обычным типам в системе, что может накладывать ограничения на определенные виды использования. Модель программирования также немного сложна и небезопасна по типу, поскольку доступ к перехваченному контексту (перехваченный компонент, имя метода, аргументы метода) доступен через объект InvocationContext, метод которого возвращает объект и может потребовать приведения перед использованием.
Однако реальная проблема с конструкцией перехватчика EJB (и многими другими подобными реализациями перехватчиков) заключается в отсутствующей ключевой абстракции точек. Вместо того, чтобы объявлять классы и методы, которые должны быть перехвачены, классы и методы должны объявить, что они должны быть перехвачены, уменьшая его до более похожего на макрос использования. В результате, хотя логика, эквивалентная рекомендации AOP, является модульной, эквивалентная логика pointcut распространяется на все перехваченные типы. Кроме того, из-за общего характера контекста точки соединения, методу перехватчика может потребоваться сложная логика для сбора аргументов из правильного места.
Обратите внимание, что среда Spring в версиях до 2.0 использовала механизм, аналогичный InvocationContext, поэтому страдает от сложностей программирования, аналогичных перехватчикам EJB3. Однако в AOP Spring всегда использовалось понятие pointcut, чтобы избежать проблемы распространения логики выбора в нескольких местах. Кроме того, интеграция AspectJ, представленная в Spring 2.0, устраняет необходимость в логике, подобной InvocationContext, и поднимает реализацию pointcut на новый уровень.
Динамические Языки
Динамические языки в последнее время приобрели популярность и это правильно. Особенно в сочетании со средами, основанными на языках, они могут предоставить мощные решения для ряда проблем. Например, Ruby в сочетании с Rails или Groovy в сочетании с Grails предоставляют более простые решения для определенных видов веб-приложений. Каждый динамический язык предлагает возможность метапрограммирования, которая позволяет изменять структуру и поведение программы во время ее выполнения. Средство метапрограммирования может быть модульным в части рекомендаций по сквозной проблематике. Например, вы можете изменить реализацию существующего метода, чтобы обернуть его кодом, который выполняет функцию сквозной обработки до или после отправки исходного метода.
Хотя метапрограммирование является прекрасным инструментом для решения сквозных задач, есть несколько соображений. Во-первых, такое использование требует переключения на динамический язык. «Война» между статическими и динамическими языками еще не завершена, и она не будет завершена в ближайшее время. Так что вам придется сделать взвешенный выбор здесь. Во-вторых, метапрограммирование может быть слишком мощным инструментом для многих программистов, и более дисциплинированный подход может быть более подходящим. В-третьих, из-за его ограниченной способности выражения, вероятно, легче создать инструментальные средства АОП, которые помогают в понимании сквозной структуры. Такой инструментарий трудно представить с помощью средств метапрограммирования общего назначения, предлагаемых динамическими языками.
Это причина, по которой Дин Уэмплер, давний эксперт по AOP, начал проект по внедрению AOP в Ruby через проект Aquarium ( http://aquarium.rubyforge.org ). Это показывает, что, хотя AOP популярен в статически типизированных языках, он играет роль даже в динамически типизированных языках. Интересно, что, как видно из этого проекта, относительно легко построить возможности AOP на основе базовой поддержки метапрограммирования, предоставляемой базовым языком. Предоставляя аспектно-ориентированный DSL для экспресс-создания точек, Aquarium предоставляет решение для модульной части точек обработки AOP в Ruby.
Поучительно отметить, что отец АОП Грегор Кичалес написал книгу «Искусство протокола метаобъекта (The MIT Press, 1991)». Он четко знает метапрограммирование! Он все еще думал, что АОП лучше подходит для сквозных задач и прямого применения метапрограммирования.
В некотором смысле, статически типизированные языки используют AOP на пути к более всесторонней поддержке метапрограммирования, чтобы освободиться от ограничений, налагаемых языком, тогда как динамические языки получают выгоду от AOP как «дисциплинированного» приложения метапрограммирования.