Диссертация (1148251), страница 10
Текст из файла (страница 10)
Если изначально облачные технологии были разработаны длясоздания отказоустойчивых сайтов и для надежного хранения данных, то теперьежегодно появляются облачные сервисы по новым направлениям: мобильныеприложения, прогнозная аналитика (Azure Machine Learning) [56], интернетвещей, интеллектуальное общение с пользователем (Microsoft Cortana IntelligenceSuite) [21]. Более того, фокус разработчиков смещается на продукты с открытымкодом, что влияет на политику таких крупных компаний как Microsoft, котораяобеспечивает всё большую интеграцию своих технологий с Linux, Android, iOS(например, Xamarin [31], SQL Server на Linux [93], эмулятор Ubuntu в Windows 10[98]) и т.п. Благодаря сильной конкуренции, стоимость облачной инфраструктурыпостоянно снижается, а качество предоставляемых облачных сервисов растёт.
Всёэто говорит о том, что облачные технологии прочно заняли свою нишу, активноразвиваются и постоянно увеличивают свое влияние на повседневную жизньпользователей Интернет.47Глава 2. Аспектно-ориентированные технологииАспектно-ориентированное программирование (АОП) — парадигмапрограммирования,восновекоторойлежитидеявыделениясквознойфункциональности в отдельные модули, называемые аспектами.В таких модулях описываются действия, выполняемые в определенныхточках программы и правила их “вплетения” в эти точки.
К сквознойфункциональностиотносятся:протоколирование,кэширование,сбордиагностической информации, авторизация и т.д. Инкапсуляция сквознойфункциональности в отдельных модулях повышает качество архитектурыпрограммногопроектавсоответствииспринципомединственнойответственности SRP [121]. При этом основное приложение будет сосредоточенона бизнес-логике, в то время как аспекты — на нефункциональных требованиях.В настоящее время уже сформировался комплексный АОП-подход (AOSD[83]) к сбору требований, построению архитектуры и дизайну систем. Обзор егометодик и инструментов представлен в работе [20].Необходимо учитывать, что при разработке ПО с помощью АОП решаютсясовсем иные задачи чем с применением ООП.
Хотя паттерны объектноориентированного проектирования призваны улучшать структуру программы,предоставляя руководство по распределению обязанностей между классами, нообеспечить полную инкапсуляцию сквозной функциональности в одном модулеони не способны. На рисунке 1 приведен дизайн приложения, разработанного встиле ООП [82]:48РИСУНОК 1. КЛАССЫ ООП ПРИЛОЖЕНИЯКак можно видеть, сквозная функциональность горизонтально пронизываетиерархии классов, увеличивая объем кода и потенциальное число ошибок. Напримере протоколирования (tracing) на рисунке 2 демонстрируется переплетение(tangling) бизнес-логики и сквозной функциональности:РИСУНОК 2. ДУБЛИРОВАНИЕ ФУНКЦИОНАЛЬНОСТИВ подобных случаях ООП рекомендует применять наследование и выноситьдублирующее поведение в общий родительский класс (паттерн “Template method”[111]). Но следование этому принципу может быть затруднено из-за отсутствиямножественного наследования. Также возможно возникновение ситуации, когдаизменения в родительском классе неявно сказываются на большом числе егонаследников (fragile base class problem) [67].
В свою очередь, применение АОПпозволяет локализовать всю логику протоколирования в одном модуле (аспекте),как показано на рисунке 3:49РИСУНОК 3. ЛОКАЛИЗАЦИЯ ЛОГИКИНаконец, стоит упомянуть результаты работы [35], где на примере AspectJпродемонстрировано, что замена большинства классических паттернов GOF [111]аспектно-ориентированнымианалогамиприводиткулучшениюметриксвязности, зацепления и количества строк кода (LOC). Однако эффективностьприменения АОП не ограничивается исключительно улучшением качестваисходного кода, а также является инструментом для построения систем сбора ианализа данных об использовании целевой системы пользователями (usagetracing) [17], что позволяет найти её “слабые звенья”, переработать их и, вконечном итоге, повысить удобство работы с ней (usability).В таблице 1 приведены существующие инструменты, реализующие АОПфункциональность для веб-ориентированных языков программирования [108]:Таблица 1.
Инструменты АОП для различных языков программированияДля .NETPostSharpSpring.NETAspect.NETRapier LOOM.NETPuzzle.NETPuzzle.NAspectAspectDNGAspect#Для PHPS2Container.PHPAOP Library for PHPGAP: Generic Aspectsfor PHPДля JAVAAspectJSpringCaesarJDynaopJACJakarta HivemindJAsCoJBoss AOP50Compose*S2Container.NETDotSpectДля Java ScriptAjaxpectAspectESPROSES2Container.JavaДля RubyAjaxpectAspectESДля LuaAspectLuaДля Macromedia FlashMXAs2libДля PythonAspyctДля PerlThe Perl Aspect ModuleДля XMLДля С/С++AspectC++The XWeaver ProjectFEatureC++Для DelphiMeAOPДля Common LispAspectXMLAspectLLightweight Python AOPPEAKВсе реализации АОП можно разделить по типу внедрения аспектов вцелевую сборку:1) вовремявыполненияцелевойпрограммы(IoC-контейнеры,Spring.NET [92], Microsoft Unity [132] и т.п.);2) во время инициализации и загрузки целевой программы (RapierLoom.NET [81]);3) на этапе компиляции (PostSharp, Aspect.NET, AspectJ и пр.).В первом случае, АОП-инструмент во время выполнения целевойпрограммы конструирует прокси-класс над целевым [105,18], применяя паттерн“Декоратор”.
Далее объект этого класса подставляется вместо целевого объекта.Таким образом, перехват вызова целевых методов происходит в одноименныхметодах прокси-класса, которые выполняют вызовы действий аспектов иделегируют остальную функциональность агрегированной ссылке на целевойобъект [42] (см. рисунок 4):51РИСУНОК 4. СХЕМА РАБОТЫ КОМПОНОВЩИКА АСПЕКТОВК преимуществам такого динамического внедрения аспектов можно отнестипростоту реализации и применения, так как используются только стандартныеконструкции языка программирования. Кроме того, становится возможнымреконфигурироватьаспектыдинамически,прямововремявыполненияпрограммы. Однако необходимость генерировать низкоуровневый код дляпрокси-класса во время выполнения целевой программы приводит к низкойпроизводительности результирующей сборки.Применить аналогичный подход, но конструировать прокси-классы вовремя запуска целевой программы предлагается во втором случае.
Это повышаетпроизводительность выполнения целевой программы, но теряется возможностьдинамической конфигурации аспектов.52Наконец, статическое внедрение аспектов в целевую сборку происходит наэтапе пост-компиляции (postbuild). Специальная утилита, компоновщик аспектов,инструментирует исходные тексты целевой программы (или её собраннуюсборку) и вставляет в нужные места вызовы к библиотеке с аспектами (см.рисунок 5):РИСУНОК 5.КОМПОНОВКА АСПЕКТОВ ПРИ СТАТИЧЕСКОМ ВНЕДРЕНИИДанный подход позволяет создавать результирующие сборки с наибольшимбыстродействием, перекладывая затраты на внедрение аспектов на времякомпиляции. Также данный подход предоставляет аспектам весь контекст точкивнедрения, начиная от текущего this-объекта, аргументов целевого метода изаканчивая объектом произошедшего исключения.
Недостатком данного подходаявляется невозможность гибкого переключения аспектов во время выполненияпрограммы.2.1 Аспектно-ориентированное программирование для платформы Javaс AspectJВ настоящее время самым популярным [38] АОП-инструментом являетсяAspectJ [53], первые работы по которому относятся к 1997 году. AspectJпредставляетсобойрасширениеязыкаJavaаспектно-ориентированными53конструкциями [51]: аспект, точка внедрения (joinpoint), её спецификация впотоке выполнения программы (pointcut), действие аспекта (advice), расширение(introduction) целевого класса.
Иными словами, программа на AspectJ содержитбазовую часть (base code) с обычными конструкциями класса и интерфейсов дляописания основной функциональности и аспектную (aspect code), котораямоделирует сквозную функциональность. В последних версиях AspectJ появиласьвозможность описывать аспектные конструкции в виде атрибутов Java(@Annotations) [55].Рассмотрим более детально понятие аспекта относительно AspectJ.Аспект — это новая сущность языка программирования, дополняющаясущность класса.1.
Обозначается ключевым словом aspect, аналогично объявлению класса вJava через идентификатор class.2. Может быть создан (instantiate), унаследован (sub aspect), содержатьчлены (state) и методы.3. Содержитправилавнедрения,определяющиекаконбудетскомбинирован с целевым классом.4. Имеет возможность дополнить целевой класс новыми методами,членами и реализацией интерфейса. Эти новые элементы могут быть каквидимы всем классам в целевом проекте (public introduction), так итолько аспекту (private introduction).Аспекты комбинируются с целевыми классами в точках внедрения: вызовкакого-либо метода или конструктора, обращение к его полю (member),в обработчиках исключений и пр.
Спецификация таких точек внедрения можетбыть составлена (designate) из других спецификаций. В действиях аспектаописывается код, который будет вызван перед (before), после (after) или вместо(around) целевого кода в точке внедрения.Рассмотрим пример аспекта на языке AspectJ, взятый из работы [52]. Пустьв базовой части программы определены классы точки (Point) и её “тени”54(Shadow), то есть другой точки, которая находится на заданном смещении (offset)от данной.public class Point {protected int x, y;public Point(int _x, int _y){x = _x;y = _y;}public int getX(){return x;}public int getY(){return y;}public void setX(int _x){x = _x;}public void setY(int _y){y = _y;}}ЛИСТИНГ 3.
КЛАСС «ТОЧКА»class Shadow {public static final int offset = 10;public int x, y;Shadow(int _x, int _y) { x = _x; y = _y; }}ЛИСТИНГ 4. КЛАСС «ТЕНЬ»55Целью аспекта PointShadowProtocol будет связь каждой точки с её “тенью”и передвижение “тени” при смене координат точки:aspect PointShadowProtocol{// Кол-во “теней”, которые связаны с точками этим аспектомprivate int shadowCount = 0;public int getShadowCount() {return PointShadowProtocol.aspectOf().shadowCount;}// Расширение класса Point членом Shadowprivate Shadow Point.shadow;public static void associate(Point p, Shadow s) {p.shadow = s;}//Спецификация различных наборов точек внедренияpointcut createPoint(int x, int y, Point p) : args(x, y) &&call(Point.new(int, int));pointcut settingX(Point p) : target(p) && call(void Point.setX(int));pointcut settingY(Point p) : target(p) && call(void Point.setY(int));// Это действие вызовется после каждого конструктора точкиafter(Point p, int _x, int _y) returning() : createPoint(x, y, p) {Shadow s = new Shadow(_x, _y);//Связываем точку с только что созданной “тенью”associate(p, s);shadowCount++;}}// Изменение координат “тени” после вызова сеттеров Pointafter(Point p) : settingX(p) {Shadow s = p.shadow;s.x = p.getX() + Shadow.offset;}after(Point p) : settingY(p) {Shadow s = p.shadow;s.y = p.getY() + Shadow.offset;}ЛИСТИНГ 5.