1. Въведение
Днес има множество налични AOP библиотеки и те трябва да могат да отговорят на редица въпроси:
- Съвместим ли е с моето съществуващо или ново приложение?
- Къде мога да приложа AOP?
- Колко бързо ще се интегрира с моето приложение?
- Какви са режийните разходи?
В тази статия ще разгледаме отговорите на тези въпроси и ще представим Spring AOP и AspectJ - двете най-популярни AOP рамки за Java.
2. Концепции за AOP
Преди да започнем, нека направим бърз преглед на високо ниво на термини и основни концепции:
- Аспект - стандартен код / функция, който е разпръснат на множество места в приложението и обикновено се различава от действителната бизнес логика (например управление на транзакции). Всеки аспект се фокусира върху специфична функционалност
- Точка на присъединяване - това е определена точка по време на изпълнение на програми като изпълнение на метод, извикване на конструктор или присвояване на поле
- Съвет - действието, предприето от аспекта в конкретна точка на съединяване
- Pointcut - регулярен израз, който съответства на точка на съединяване. Всеки път, когато която и да е точка на присъединяване съвпада с точка, се изпълнява определен съвет, свързан с тази точка
- Тъкане - процесът на свързване на аспекти с целеви обекти за създаване на препоръчан обект
3. Пролетен AOP и AspectJ
Сега, нека обсъдим Spring AOP и AspectJ по редица оси - като възможности, цели, тъкане, вътрешна структура, точки на съединяване и простота.
3.1. Възможности и цели
Просто казано, Spring AOP и AspectJ имат различни цели.
Spring AOP има за цел да осигури проста реализация на AOP в Spring IoC за решаване на най-често срещаните проблеми, пред които са изправени програмистите. Той не е предназначен като цялостно решение за AOP - той може да се прилага само за зърна, които се управляват от Spring контейнер.
От друга страна, AspectJ е оригиналната AOP технология, която има за цел да предостави цялостно AOP решение. Той е по-здрав, но и значително по-сложен от Spring AOP. Също така си струва да се отбележи, че AspectJ може да се прилага във всички обекти на домейна.
3.2. Тъкане
Както AspectJ, така и Spring AOP използват различния тип тъкане, което влияе върху тяхното поведение по отношение на производителността и лекотата на използване.
AspectJ използва три различни вида тъкане:
- Тъкане по време на компилация: Компилаторът AspectJ взема за вход както изходния код на нашия аспект, така и нашето приложение и създава тъкани файлове от клас като изход
- Тъкане след компилация : Това е известно още като двоично тъкане. Той се използва за тъкане на съществуващи файлове с класове и JAR файлове с нашите аспекти
- Тъкане по време на зареждане : Това е точно като предишното двоично тъкане, с тази разлика, че тъкането се отлага, докато зареждащият клас зарежда файловете на класа в JVM
За по-задълбочена информация за самия AspectJ, преминете към тази статия.
Тъй като AspectJ използва време за компилиране и време за натоварване на клас, Spring AOP използва тъкане по време на изпълнение .
При тъкане по време на изпълнение, аспектите се тъкат по време на изпълнението на приложението, използвайки прокси на целевия обект - използвайки или JDK динамичен прокси или CGLIB прокси (които са разгледани в следващата точка):

3.3. Вътрешна структура и приложение
Spring AOP е базирана на прокси AOP рамка. Това означава, че за да се приложат аспекти към целевите обекти, той ще създаде прокси на този обект. Това се постига по един от двата начина:
- JDK динамичен прокси - предпочитаният начин за Spring AOP. Винаги, когато целевият обект реализира дори един интерфейс, тогава ще се използва динамичен прокси JDK
- CGLIB прокси - ако целевият обект не реализира интерфейс, тогава може да се използва прокси CGLIB
Можем да научим повече за механизмите за проксиране на Spring AOP от официалните документи.
AspectJ, от друга страна, не прави нищо по време на изпълнение, тъй като класовете се компилират директно с аспекти.
И така за разлика от Spring AOP, той не изисква никакви дизайнерски модели. За да вплете аспектите в кода, той въвежда своя компилатор, известен като AspectJ compiler (ajc), чрез който ние компилираме нашата програма и след това я стартира чрез предоставяне на малка (<100K) среда за изпълнение.
3.4. Точки на съединяване
В раздел 3.3 показахме, че Spring AOP се основава на прокси модели. Поради това той трябва да подкласира целевия клас Java и съответно да приложи междусекторни проблеми.
Но идва с ограничение. Не можем да приложим кръстосани проблеми (или аспекти) в класове, които са „окончателни“, тъй като не могат да бъдат заменени и по този начин това би довело до изключение по време на изпълнение.
Същото се отнася за статичните и крайните методи. Пролетни аспекти не могат да бъдат приложени към тях, защото те не могат да бъдат заменени. Следователно Spring AOP поради тези ограничения поддържа само точки на присъединяване на изпълнението на метода.
AspectJ обаче впръсква общите въпроси директно в действителния код преди изпълнението. За разлика от Spring AOP, той не изисква да подкласира целевия обект и по този начин поддържа и много други точки на присъединяване. По-долу е обобщението на поддържаните точки на съединение:
Точка на присъединяване | Поддържа се пролетен AOP | Поддържа се AspectJ |
---|---|---|
Извикване на метод | Не | Да |
Изпълнение на метода | Да | Да |
Извикване на конструктор | Не | Да |
Изпълнение на конструктора | Не | Да |
Изпълнение на статичен инициализатор | Не | Да |
Инициализация на обект | Не | Да |
Полеви справки | Не | Да |
Полево задание | Не | Да |
Изпълнение на манипулатора | Не | Да |
Изпълнение на съвети | Не | Да |
Също така си струва да се отбележи, че в Spring AOP аспектите не се прилагат към метода, извикан в рамките на същия клас.
Това очевидно е, защото когато извикаме метод в същия клас, тогава не извикваме метода на проксито, който Spring AOP предоставя. Ако се нуждаем от тази функционалност, тогава трябва да дефинираме отделен метод в различни боб или да използваме AspectJ.
3.5. Простота
Spring AOP очевидно е по-прост, тъй като не въвежда допълнителен компилатор или тъкач между нашия процес на изграждане. Той използва тъкане по време на изпълнение и следователно се интегрира безпроблемно с обичайния ни процес на изграждане. Въпреки че изглежда просто, работи само с боб, който се управлява от Spring.
Въпреки това, за да използваме AspectJ, от нас се изисква да представим компилатора AspectJ (ajc) и да пакетираме всички наши библиотеки (освен ако не преминем към тъкане след компилация или зареждане).
Това, разбира се, е по-сложно от предишното - защото въвежда AspectJ Java Tools (които включват компилатор (ajc), дебъгер (ajdb), генератор на документация (ajdoc), браузър на структурата на програмата (ajbrowser)), който ние трябва да се интегрира или с нашата IDE, или с инструмента за изграждане.
3.6. производителност
Що се отнася до производителността, тъкането по време на компилация е много по-бързо от тъкането по време на изпълнение . Spring AOP е базирана на прокси, така че има създаване на прокси в момента на стартиране на приложението. Освен това има още няколко извиквания на метод за всеки аспект, което се отразява негативно на производителността.
От друга страна, AspectJ преплита аспектите в основния код преди изпълнението на приложението и по този начин няма допълнителни режийни разходи, за разлика от Spring AOP.
Поради тези причини бенчмарковете предполагат, че AspectJ е почти около 8 до 35 пъти по-бърз от Spring AOP.
4. Обобщение
Тази бърза таблица обобщава основните разлики между Spring AOP и AspectJ:
Пролетен AOP | АспектJ |
---|---|
Внедрено в чиста Java | Реализирано с помощта на разширения на езика за програмиране Java |
Няма нужда от отделен процес на компилация | Нуждае се от компилатор AspectJ (ajc), освен ако не е настроен LTW |
Налично е само тъкане по време на работа | Тъкането по време на работа не е налично. Поддържа тъкане по време на компилация, след компилация и зареждане |
По-малко мощен - поддържа само тъкане на ниво метод | По-мощен - може да тъче полета, методи, конструктори, статични инициализатори, краен клас / методи и т.н. ... |
Може да се приложи само на зърна, управлявани от Spring контейнер | Може да се внедри във всички обект на домейн |
Поддържа само точки за изпълнение на метод | Поддържа всички точки |
Прокситата се създават от целеви обекти и върху тях се прилагат аспекти | Аспектите са вплетени директно в код преди изпълнението на приложението (преди изпълнението) |
Много по-бавно от AspectJ | По-добро представяне |
Лесно за научаване и прилагане | Сравнително по-сложен от Spring AOP |
5. Избор на правилната рамка
Ако анализираме всички аргументи, направени в този раздел, ще започнем да разбираме, че изобщо не е, че една рамка е по-добра от друга.
Най-просто казано, изборът силно зависи от нашите изисквания:
- Framework: Ако приложението не използва Spring framework, тогава нямаме друга възможност, освен да откажем идеята за използване на Spring AOP, тъй като не може да управлява нищо, което е извън обсега на Spring контейнера. Ако обаче нашето приложение е създадено изцяло с помощта на Spring framework, тогава можем да използваме Spring AOP, тъй като е лесно да се учим и прилагаме
- Гъвкавост: Предвид ограничената поддръжка на точки на съединяване, Spring AOP не е цялостно AOP решение, но решава най-често срещаните проблеми, пред които са изправени програмистите. Въпреки че, ако искаме да разровим по-дълбоко и да използваме AOP до максималните му възможности и искаме подкрепата от широк спектър от налични точки на съединяване, тогава AspectJ е изборът
- Изпълнение: Ако използваме ограничени аспекти, тогава има тривиални разлики в производителността. Но понякога има случаи, когато приложение има повече от десетки хиляди аспекти. Не бихме искали да използваме време на тъкане в такива случаи, така че би било по-добре да се спрем на AspectJ. Известно е, че AspectJ е 8 до 35 пъти по-бърз от Spring AOP
- Най-доброто от двете: И двете рамки са напълно съвместими помежду си. Винаги можем да се възползваме от Spring AOP, когато е възможно и все пак да използваме AspectJ, за да получим поддръжка на точки на присъединяване, които не се поддържат от предишния
6. Заключение
В тази статия анализирахме Spring AOP и AspectJ в няколко ключови области.
Сравнихме двата подхода към AOP както по отношение на гъвкавостта, така и по отношение на това колко лесно ще се съчетаят с нашето приложение.