Что такое AOP
Можно сказать, что AOP (ориентированное на аспект программирование, ориентированное на аспект)-это дополнение и улучшение ООП (объектно-ориентированное программирование). OOP вводит такие понятия, как инкапсуляция, наследование и полиморфизм, чтобы установить иерархию объекта для имитации коллекции общественного поведения. Когда нам нужно ввести общественное поведение в рассеянные объекты, ООП кажется бессильным. То есть ООП позволяет вам определять отношения сверху донизу, но не подходит для определения отношений слева направо. Например, функция регистрации. Код журнала часто рассеяется горизонтально по всем уровням объектов без какого -либо отношения к основной функциональности объекта, которому он рассеян. То же самое относится и к другим типам кода, таким как безопасность, обработка исключений и прозрачность. Этот вид нерелевантного кода, разбросанный повсюду, называется кодом перекрестного обрезания. В дизайне ООП это вызывает много дублирования кода, что не способствует повторному использованию каждого модуля.
Технология AOP, напротив, использует методику, называемую «перекрестным», для рассечения внутренней части инкапсулированного объекта и инкапсуляции общего поведения, которые влияют на многочисленные классы в модуль многократного использования, и назвать его «аспект», то есть так называемый «аспект», просто вкладывает в себя логический Сокращение связи между модулями и способствуя будущей рабочей работоспособности и обслуживаемости. AOP представляет горизонтальные отношения. Если «объект» является полым цилиндром, инкапсулирующим свойства и поведение объекта; Затем метод программирования, ориентированный на аспект, похож на острый лезвие, разрезая эти полые цилиндры для получения внутренней информации. Вырезанная секция-так называемое «лицо». Затем он восстановил эти вырезанные секции своими умными руками, не оставляя никаких следов.
Используя технологию «перекрестного», AOP делит программную систему на две части: основная проблема и перекрестная озабоченность. Основным процессом обработки бизнеса является основной целью, и часть, которая имеет к нему мало общего, является поперечное внимание. Одной из характеристик перекрестных проблем является то, что они часто возникают в нескольких основных проблемах и в основном похожи везде. Например, аутентификация разрешения, ведение журнала и обработка транзакций. Роль AOP заключается в разделении различных проблем в системе и отдельных основных проблемах от перекрестных проблем. Как сказал Адам Маги, старший архитектор решения в Avanade, основная идея AOP состоит в том, чтобы «отделить бизнес -логику в приложении от общих служб, которые поддерживают ее».
Технология для реализации AOP в основном разделена на две категории: одна из них заключается в использовании динамической прокси -технологии и использовании метода перехвата сообщений для украшения сообщения для замены выполнения исходного поведения объекта; Другим является использование статического метода ткачества для введения конкретного синтаксиса для создания «грани», чтобы компилятор мог сплетать код, связанный с «лицами» во время компиляции.
AOP сценарии использования
AOP используется для инкапсуляции проблем с перекрестными вырезами, которые можно использовать в следующих сценариях:
Разрешения на аутентификацию
Кэширование кэширования
Контекст прохождения контента
Обработка ошибок
Ленивая загрузка
Отладка
ведение журнала, отслеживание, профилирование и мониторинг
Оптимизация производительности
Постоянство настойчивость
Объединение ресурсов
Синхронизация
Транзакции
AOP, связанные с концепциями
Аспект: модульность фокуса, которая может дополнительно перекрестно вырезать несколько объектов. Управление транзакциями является хорошим примером перекрестных проблем в приложениях J2EE. Аспект реализуется с использованием консультанта или перехвата Spring.
JoinPoint: четкая точка во время выполнения программы, такая как вызов метода или конкретное исключение.
Совет: Действия, выполняемые структурой AOP в определенной точке соединения. Различные типы уведомлений включают в себя «вокруг», «до» и «бросает» уведомления. Типы уведомлений обсуждаются ниже. Многие фреймворки AOP, в том числе Spring, используют перехватчики в качестве моделей уведомлений для поддержания цепочки перехвата «круглый». Четыре совета определяются весной: Beforeadvice, After Advice, Throwadvice и DynamicIntroductionAdvice
Pointcut: указывает набор точек соединения, к которым будет запускается уведомление. Структура AOP должна позволить разработчикам указать точки входа: например, с использованием регулярных выражений. Spring определяет интерфейс Pointcut, который используется для сочетания MethodMatcher и ClassFilter, который можно четко понять с помощью имени. MethodMatcher используется для проверки того, можно ли использовать метод целевого класса для применения этого уведомления, в то время как ClassFilter используется для проверки того, следует ли применяться PointCut к целевому классу.
Введение: добавьте метод или поле в класс, который уведомляется. Spring позволяет вводить новые интерфейсы в любой уведомленный объект. Например, вы можете упростить кэширование, используя введение, которое позволяет любому объекту реализовать Ismodified Interface. Чтобы использовать введение в Spring, вы можете использовать DelegatingIntroductionInterceptor для реализации уведомлений и использовать DefaultIntroductionAdvisor для настройки интерфейса для реализации консультаций и классов прокси.
Целевой объект: объект, содержащий точку соединения. Также известен как уведомленный или прокси -объект. Поожо
AOP Proxy: объект, созданный Framework AOP, содержащий уведомления. Весной прокси AOP может быть динамическим прокси или прокси -сервером CGLIB.
Плетение: собирайте для создания уведомленного объекта. Это можно сделать во время компиляции (например, с использованием компилятора AspectJ) или во время выполнения. Весна, как и другие рамки Pure Java AOP, завершает ткачество во время выполнения.
Весенние компоненты AOP
В следующей классной диаграмме перечислены основные компоненты AOP весной
Как использовать Spring AOP
Spring AOP может использоваться в файлах конфигурации или в способах программирования.
Конфигурация может быть выполнена через XML -файл, и есть около четырех способов:
1. Настройка ProxyFactoryBean, явно установите консультантов, советы, цель и т. Д.
2. Настройте AutoProxycreator. Таким образом, определенный фасоль все еще используется, как и раньше, но то, что вы получаете из контейнера, на самом деле является прокси -объектом.
3. Настройка через <AOP: config>
4. Настройка через <AOP: AspectJ-autoproxy> и используйте аннотации AspectJ для определения уведомлений и точек входа
Вы также можете использовать ProxyFactory непосредственно для программного использования Spring AOP. С помощью методов, предоставленных ProxyFactory, вы можете установить целевые объекты, консультанты и другие связанные конфигурации и, наконец, получить объект Proxy через метод getProxy ().
Конкретными примерами использования могут быть Google. опущен здесь
Поколение объекта Spring AOP Proxy
Spring предоставляет два способа создания прокси -объектов: JDKProxy и Cglib. Конкретный метод генерации определяется AOPProxyFactory на основе конфигурации объекта AdvisedSupport. Политика по умолчанию состоит в том, чтобы использовать технологию динамического прокси JDK, если целевой класс является интерфейсом, в противном случае используйте CGLIB для генерации прокси. Давайте изучим, как Spring использует JDK для генерации прокси -объектов. Специфический код генерации помещается в класс Jdkdynamicaopproxy, и соответствующий код добавляется напрямую:
/** * <ol> * <li> Получить интерфейс, который будет реализован классом Proxy. В дополнение к конфигурации в консультантом объекте, также будет добавлен SpringProxy, рекомендуется (opaque = false) * <li> Проверьте, существует ли интерфейс, который определяет равные или хэшкод в интерфейсе, полученном выше * <li> Вызов Proxy.newproxyinstance для создания объекта Proxy * </ ol>/ public getproxy (classulder klessuler) {classulder) {iploader) {iploader). (logger.isdebugenabled ()) {logger.debug («Создание динамического прокси -сервера JDK: целевой источник - +this.advised.getTargetSource ()); } Class [] proxiedInterfaces = aopproxyutils.completeproxiedInterfaces (this.advised); FindDefinedEqualsAndhashCodemethods (проксиединтерфейсы); return proxy.newProxyInstance (ClassLoader, ProxiedInterfaces, это); } Тогда это на самом деле очень ясно. Я уже ясно написал комментарии и больше не буду повторять их.
Следующий вопрос заключается в том, что прокси -объект генерируется, как переплетается поверхность среза?
Мы знаем, что InvocationHandler является ядром динамического прокси -сервера JDK, и методы вызовы сгенерированных прокси -объектов будут делегированы методу vocationhandler.invoke (). Через подпись Jdkdynamicaopproxy мы видим, что этот класс на самом деле реализует vocationhandler. Давайте посмотрим, как Spring AOP вплетается в раздел, анализируя метод indoke (), реализованный в этом классе.
publicObject invoke (объект прокси, метод метода, объект [] args) throwStrowable {methodInvocation vocation = null; Object OldProxy = null; логический setProxyContext = false; Targetsource targetsource = this.advised.targetSource; Класс TargetClass = null; Объект Target = null; try {// eqauls () метод, целевой объект не реализует этот метод, если (! this.equalsDefined && aoputils.isequalsmethod (method)) {return (equals (args [0])? boolean.true: boolean.false); } // метод hashcode (), целевой объект не реализует этот метод if (! this.hashcodedefined && aoputils.ishashcodemethod (method)) {return newinteger (hashcode ()); } // Консультант интерфейс или метод, определяемый в его родительском интерфейсе, непосредственно отражает вызов и не использует уведомление if (! This.advised.opaque && method.getDeclaringClass (). IsInterface () && method.getDeclaringClass (). Isassignablefrom (Advected.class)) {/ / /Service vocations onproxcycycrom onfervyfrom (revence.class)). Aoputils.invokejoinpointusingreflection (this.advised, метод, args); } Объект retval = null; if (this.advised.exposeproxy) {// Сделайте вызов доступным. OldProxy = aopContext.SetCurrentProxy (прокси); setProxyContext = true; } // Получить класс целевого объекта Target = targetSource.getTarget (); if (target! = null) {targetClass = target.getClass (); } // Получить список перехватчиков, который может быть применен к этой цепочке списка методов = this.Adved.getInterceptorsAndInmicInterceptionAdvice (метод, TargetClass); // Если нет уведомлений, которое может быть применено к этому методу (Interceptor), этот метод вызова прямого отражения. INVOKE (Target, args) if (chain.isempty ()) {retval = aoputils.invokejoinpointusingreflection (Target, Method, arg); } else {// Создать MethodInvocation vocation = newReflectiveMethodinvocation (прокси, цель, метод, аргус, цепь, цепь); retval = vocation.proceed (); } // Массаж возврата при необходимости. if (retval! = null && retval == target && method.getReturnType (). ISinstance (proxy) &&! rawtargetAccess.class.isassignablefrom (method.getDeclaringClass ())) {// Специальный случай: он возвращал «этот» и возвращается тип метода //. Notethat, мы не можем помочь, если цель установит // ссылка на себя непревзойденным возвращенным объектом. retval = прокси; } вернуть возврат; } наконец {if (target! = null &&! targetsource.isstatic ()) {// Должно быть, поступил из TargetSource. TargetSource.ReleaseTarget (Target); } if (setProxyContext) {// восстановить старый прокси. Aopcontext.setCurrentProxy (OldProxy); }}} Основной процесс может быть кратко описан как: получение цепочки уведомлений, которая может быть применена к этому методу (цепочка перехвата). Если есть, примените уведомление и выполните JoinPoint; Если нет, непосредственно отражает JoinPoint. Ключ здесь заключается в том, как получается цепочка уведомлений и как она выполняется. Давайте проанализируем это один за другим.
Прежде всего, из приведенного выше кода мы видим, что цепочка уведомлений получена с помощью метода revened.getInterceptorsAndInmicInterceptionAdvice (). Давайте посмотрим на реализацию этого метода:
Общедоступный список <object> getInterceptorsAndInmicInterceptionAdvice (Метод метода, класс TargetClass) {methodCacheKeyCachekey = new MethodCachekey (Method); Список <object> cached = this.methodcache.get (cachekey); if (cached == null) {cached = this.advisorchainfactory.getInterceptorsAndInmicInterceptionAdvice (this, method, targetClass); this.methodcache.put (cachekey, cached); } returncached; } Видно, что фактическая работа по приобретению фактически выполняется AdvisorChainFactory. getInterceptorsAndnamicInterceptionAdvice () метод, и полученные результаты будут кэшированы.
Давайте проанализируем реализацию этого метода ниже:
/*** Получите список консультантов из предоставленной конфигурации экземпляра конфигурации и пройдите этих советников. Если это введение, а затем определите, может ли этот консультант быть применен к целевому классу TargetClass. Если это Pointcutadvisor, определите *, может ли этот советник быть применен к методу целевого метода. Консультант, который соответствует условиям, преобразуется в список перехватчиков через Advisoradaptor. */ publicList getInterceptorsAndInmicIntermenteCeptionAdvice (консультант config, methodmethod, class targetclass) {// Это немного сложно ... сначала мы должны обрабатывать представления, //, но нам нужно сохранить порядок в конечном списке. Список receptorlist = new ArrayList (config.getAdvisors (). Length); // Проверьте, является ли введение в Boolean hasIntroductions = hasmatchingIntroductions (config, targetClass); // Фактически, серия консультантов зарегистрирована здесь, чтобы преобразовать консультант в реестр AdviserAdapterRegistry MethodInterceptor = GlobalAdvisorAdapterRegistry.getInstance (); Advisor [] Advisors = config.getAdvisors (); for (int i = 0; i <Advisors.length; i ++) {Advisor Advisor = Advisors [i]; if (Advisor ancessionof pointcutadvisor) {// Добавить его условно. Pointcutadvisor pointcutadvisor = (pointcutadvisor) консультант; if (config.isprefiltered () || pointcutadvisor.getpointcut (). getClassFilter (). Matches (TargetClass)) {// todo: позиции этих двух методов могут быть заменены в этом месте // преобразовать консультанта в MethodInterceptor [] receptors = Registry.getinterceptors (AdvisorSor); // Проверьте, может ли точка текущего советника соответствовать текущему методу метода MTHATCHER MM = POONTCUTADVISOR.GETPOINTCUT (). GetMethodMatcher (); if (methodmatchers.matches (mm, method, targetclass, hasintroductions)) {if (mm.isruntime ()) {// Создание экземпляра NewObject в методе getInterceptors () // не является проблемой, которую мы обычно создавали кэш -цепь. for (intj = 0; j <recepertors.length; j ++) {receptorlist.add (new InterceptorandDynamicMethodMatcher (Interceptors [j], MM)); }} else {receptorlist.addall (arrays.aslist (receptors)); }}}} else if (Advisor ancessulationOf InvelocmentAdvisor) {invidentaDvisor ia = (введение введите) Advisor; if (config.isprefiltered () || ia.getClassFilter (). Matches (targetClass)) {receptor [] receptors = Registry.getInterceptors (Advisor); receptorlist.addall (Arrays.aslist (Interceptors)); }} else {receptor [] receptors = Registry.getInterceptors (Advisor); receptorlist.addall (Arrays.aslist (Interceptors)); }} return receptorlist; } После выполнения этого метода все консультанты, настроенные в рекомендации, которые могут быть применены к точкам соединения или целевым классам, преобразуются в MethodInterceptor.
Далее, давайте посмотрим, как работает полученная цепочка перехватчиков.
if (chain.isempty ()) {retval = aoputils.invokejoinpointusingreflection (target, method, args); } else {// Создать MethodInvocation vocation = newReflectiveMethodinvocation (прокси, цель, метод, аргус, цепь, цепь); retval = vocation.proceed (); } Из этого кода мы видим, что если полученная цепь перехватчика пуста, целевой метод будет называться непосредственно отраженным. В противном случае будет создан метод включения, его метод процесса будет вызван, и выполнение цепочки перехватчика будет запустить. Давайте посмотрим на конкретный код
Public Object Doving () бросает Throwable {// Мы начинаем с индекса -1 и приращения рано. if (this.currentInterceptorIndex == this.InterceptorsAndDynamicMethodMatchers.size ()- 1) {// Если receptor завершается, выполняет joinpoint return invokejoinpoint (); } Object InterceptorOrInterceptionAdvice = this.InterceptorSandDynamicMethodMatchers.get (++ this.currentInterceptorIndex); // Если вы хотите динамически сопоставить JoinPoint if (InterceptororInterceptionAdvice экземпляр InterceptorandDynamicMethodMatcher) {// Оценить динамический сопоставление методов здесь: Статическая часть уже будет // оценена и обнаружена. InterceptorandDynamicMethodMatcher dm = (receptorandDynamicMethodMatcher) receptorOrInterceptionAdvice; // Dynamic Match: соответствуют ли параметры времени выполнения условия соответствия if (dm.methodmatcher.matches (this.method, this.targetclass, this.arguments)) {// выполнить текущий интерфейс returndm.interceptor.invoke (this); } else {// Когда динамическое сопоставление не удается, пропустите текущий интерфейс и вызовите следующую процедуру возврата перехвата (); }} else {// Это перехватчик, поэтому мы просто вызываем его: PointCutwill были оценены статически до того, как этот объект был построен. // Выполнить текущий интерфейс return (((methodinterceptor) receptororInterceptionAdvice) .invoke (this); }}Код также относительно прост, поэтому я не буду вдаваться в подробности здесь.
Выше всего содержание этой статьи. Я надеюсь, что это будет полезно для каждого обучения, и я надеюсь, что все будут поддерживать Wulin.com больше.