Spring AOP: в чем разница между JoinPoint и PointCut?
Я изучаю концепции аспектно-ориентированного программирования и Spring AOP. Я не понимаю разницу между Pointcut и Joinpoint - оба они кажутся одинаковыми для меня. Pointcut - это место, где вы применяете ваш совет, а Joinpoint - это место, где мы можем применить наш совет. Тогда какая разница?
Примером pointcut может быть:
@Pointcut("execution(* * getName()")
Что может быть примером Joinpoint?
18 ответов
Точка соединения: точка соединения - это точка- кандидат в программном исполнении приложения, в которой может быть подключен аспект. Эта точка может быть вызванным методом, генерируемым исключением или даже изменяемым полем. Это точки, где код вашего аспекта может быть вставлен в обычный поток вашего приложения, чтобы добавить новое поведение.
Совет: Это объект, который включает вызовы API для системных проблем, представляющих действие, выполняемое в точке соединения, указанной точкой.
Pointcut: Pointcut определяет, в каких точках соединения должен применяться соответствующий Совет. Рекомендации могут применяться в любой точке соединения, поддерживаемой платформой AOP. Конечно, вы не хотите применять все свои аспекты во всех возможных точках соединения. Pointcuts позволяют вам указать, где вы хотите, чтобы ваш совет был применен. Часто вы указываете эти pointcut с использованием явных имен классов и методов или с помощью регулярных выражений, которые определяют соответствующие шаблоны имен классов и методов. Некоторые платформы AOP позволяют создавать динамические контрольные точки, которые определяют, следует ли применять рекомендации на основе решений времени выполнения, таких как значение параметров метода.
Следующее изображение может помочь вам понять Advice, PointCut, Joinpoints.
Объяснение, используя ресторанную аналогию: Источник @Victor
Когда вы выходите в ресторан, вы смотрите на меню и видите несколько вариантов на выбор. Вы можете заказать один или несколько пунктов меню. Но пока вы на самом деле не заказываете их, они просто "возможность пообедать". Как только вы размещаете заказ и официант приносит его к вашему столу, это еда.
Точки соединения - это опции в меню, а Точки - это элементы, которые вы выбираете.
Joinpoint - это возможность в коде для вас применить аспект... просто возможность. Если вы воспользуетесь этой возможностью, выберите одну или несколько точек соединения и примените к ним аспект, у вас появится Pointcut.
Чтобы понять разницу между точкой соединения и точечным вырезом, представьте, что точечные отрезки задают правила плетения, а точки объединения - как ситуации, удовлетворяющие этим правилам.
В приведенном ниже примере,
@Pointcut("execution(* * getName()")
Pointcut определяет правила, говоря, что совет должен применяться к методу getName(), присутствующему в любом классе в любом пакете, а точки соединения будут списком всех методов getName(), присутствующих в классах, чтобы совет можно было применить к этим методам.
(В случае Spring правило будет применяться только к управляемым bean-компонентам, а рекомендации могут применяться только к открытым методам).
Непонятное объяснение тому, кто плохо знаком с концепциями АОП. Это не является исчерпывающим, но должно помочь понять концепции. Если вы уже знакомы с основным жаргоном, вы можете перестать читать сейчас.
Предположим, у вас есть нормальный класс Employee, и вы хотите что-то делать каждый раз, когда эти методы вызываются.
class Employee{
public String getName(int id){....}
private int getID(String name){...}
}
эти методы называются JoinPoints. Нам нужен способ идентифицировать эти методы, чтобы платформа могла найти методы среди всех загруженных им классов. Поэтому мы напишем регулярное выражение, соответствующее сигнатуре этих методов. Хотя это еще не все, как вы увидите ниже, но в основном это регулярное выражение определяет Pointcut. например
* * mypackage.Employee.get*(*)
Первый * для модификатора public / private / protected / default. Второй * для возвращаемого типа метода.
Но тогда вам также нужно сказать еще две вещи:
- Когда должно быть предпринято действие - например, до / после выполнения метода ИЛИ в случае исключения
- Что он должен делать, когда он совпадает (может быть, просто напечатать сообщение)
Комбинация этих двух названа Советом.
Как вы можете себе представить, вы должны написать функцию, чтобы иметь возможность делать #2. Так вот как это может выглядеть для основ.
Примечание: для ясности используйте слово REGEX вместо * * mypackage.Employee.get*(*)
, На самом деле полное выражение входит в определение.
@Before("execution(REGEX)")
public void doBeforeLogging() {....} <-- executed before the matching-method is called
@After("execution(REGEX)")
public void doAfterLogging() {....} <-- executed after the matching-method is called
Как только вы начнете их использовать, вы можете указать множество советов @After/@Before/@Around. Повторяющиеся регулярные выражения в конечном итоге приводят к путанице и сложности в обслуживании. Итак, что мы делаем, мы просто даем имя выражению и используем его везде в классе Aspect.
@Pointcut("execution(REGEX)") <-- Note the introduction of Pointcut keyword
public void allGetterLogging(){} <-- This is usually empty
@Before("allGetterLogging")
public void doBeforeLogging() {....}
@After("allGetterLogging")
public void doAfterLogging() {....}
Кстати, вы также хотели бы обернуть всю эту логику в класс, который называется Aspect, и вы бы написали класс:
@Aspect
public class MyAwesomeAspect{....}
Чтобы все это работало, вы должны сказать Spring, чтобы он анализировал классы для чтения, понимания и принятия мер по ключевым словам @ AOP. Один из способов сделать это - указать следующее в весеннем конфигурационном XML-файле:
<aop:aspectj-autoproxy>
JoinPoints: Это в основном места в реальной бизнес-логике, в которые вы хотите вставить некоторые разные функции, которые необходимы, но не являются частью реальной бизнес-логики. Некоторые примеры JoinPints: вызов метода, метод, возвращающийся нормально, метод, вызывающий исключение, создание экземпляра объекта, обращение к объекту и т. Д...
Pointcuts: Pointcuts - это что-то вроде регулярных выражений, которые используются для определения точек соединения. Pontcuts выражаются с использованием "языка выражений pointcut". Точечные точки - это точки потока выполнения, где необходимо применять сквозную задачу. Есть разница между Joinpoint и Pointcut; Точки соединения являются более общими и представляют собой любой поток управления, в котором мы "можем выбрать" ввести сквозную проблему, в то время как pointcuts идентифицируют такие точки соединения, где "мы хотим" ввести сквозную проблему.
Определения
Согласно документации:
Точка соединения: точка во время выполнения программы, например, при выполнении метода или обработке исключения.
Вы можете рассматривать совместные пункты как события при выполнении программы. Если вы используете Spring AOP, это даже ограничивается вызовом методов. AspectJ обеспечивает большую гибкость.
Но вы никогда не справляетесь со всеми событиями, так как вы не едите всю еду в меню, когда вы идете в ресторан (я вас не знаю, вы могли бы! Но я, конечно, нет). Таким образом, вы делаете выбор событий для обработки и что с ними делать. Здесь идет Pointcuts. Согласно документации,
Pointcut: предикат, который соответствует точкам соединения.
Затем вы связываете, что делать с Pointcut, там идет Совет. Согласно документации,
Рекомендация связана с выражением pointcut и выполняется в любой точке соединения, совпадающей с pointcut.
Код
package com.amanu.example;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
/**
* @author Amanuel Nega on 10/25/16.
*/
class ExampleBussinessClass {
public Object doYourBusiness() {
return new Object();
}
}
@Aspect
class SomeAspect {
@Pointcut("execution(* com.amanu.example.ExampleBussinessClass.doYourBusiness())")
public void somePointCut() {
}//Empty body suffices
@After("somePointCut()")
public void afterSomePointCut() {
//Do what you want to do before the joint point is executed
}
@Before("execution(* *(*))")
public void beforeSomePointCut() {
//Do what you want to do before the joint point is executed
}
}
Объяснение кода
ExampleBusinessClass
когда прокси-ред, наша цель!doYourBusiness()
является возможной совместной точкойSomeAspect
это наш аспект, который пересекается с несколькими проблемами, такие задницуExampleBusinessClass
somePointCut()
это определение точки среза, которая соответствует нашей общей точкеafterSomePointCut()
это совет, который будет выполнен после нашегоsomePointCut
срез, соответствующийdoYourBusiness()
совместная точкаbeforeSomePointCut()
также совет, который соответствует всемpublic
метод выполнения. В отличие отafterSomePointCut
этот использует встроенную декларацию обрезки
Вы можете посмотреть документацию, если не верите мне. надеюсь, это поможет
Сравнивая язык AOP, такой как AspectJ, с языком запросов данных, таким как SQL, вы можете представить точки соединения (т. Е. Все места в вашем коде, где вы можете сплести код аспекта) как таблицу базы данных со многими строками. Точка вырезания похожа на отметку SELECT, которая может выбирать пользовательское подмножество строк / точек соединения. Фактический код, который вы вкладываете в эти выбранные места, называется советом.
Оба относятся к "где" аспектно-ориентированного программирования.
Точка соединения - это отдельное место, где вы можете выполнить код с помощью AOP. Например, "когда метод вызывает исключение".
Pointcut - это набор точек соединения. Например, "когда метод в классе Foo создает исключение".
JoinPoint: Joinpoint - это точки выполнения вашей программы, в которых поток выполнения изменился, например, перехват исключений, вызов другого метода.
PointCut: PointCut - это в основном те точки соединения, в которые вы можете поместить свой совет (или аспект вызова).
Таким образом, в основном PointCuts являются подмножеством JoinPoints.
У AOP весной есть {Советник, Совет, Pointcut, Joinpoint}
Как вы знаете, основная цель aop - это отделение логики сквозного взаимодействия (Aspect) от кода приложения, чтобы реализовать это в Spring, который мы используем (Advice / Advisor)
Pointcut используется для фильтрации, где мы хотим применить этот совет точно, например, "все методы начинаются со вставки", поэтому другие методы будут исключены, поэтому мы имеем в интерфейсе Pointcut {ClassFilter and MethodMatcher}
Таким образом, Advice - это сквозная логическая реализация, а Advisor - это совет плюс PointCut, если вы используете только advice, то пружина отобразит его в Advisor и сделает pointcut TRUE, что означает, что ничего не блокируется. Вот почему, когда вы используете только рекомендации, они применяются ко всем методам целевого класса, потому что вы их не фильтровали.
Но Joinpoint - это место в программе, вы можете думать об этом как об отражении, когда вы получаете доступ к объекту Class, а затем вы можете получить объект Method, затем вы можете вызвать любой метод в этом классе, и вот как работает компилятор, если вы думаете, что это вы можете себе представить Joinpoint.
Точка соединения может быть с полем, конструктором или методом, но в Spring у нас есть точка соединения только с методами, поэтому в Spring у нас есть типы точек соединения (До, После, Броски, Вокруг), все они относятся к местоположениям в классе.
Как я уже упоминал, у вас может быть совет без pointcut (без фильтра), тогда он будет применяться ко всем методам, или у вас может быть советник, который является [advice + pointcut], который будет применяться к определенным методам, но вы не можете получить совет без Точка соединения, такая как pointcut, вы должны указать ее, и поэтому типы подсказок весной точно такие же, как и точка соединения, поэтому, когда вы выбираете рекомендацию, вы неявно выбираете, какая точка соединения.
В заключение, совет - это логика реализации вашего аспекта для целевого класса, этот совет должен иметь точку соединения, как до вызова, после вызова, после броска или вокруг вызова, а затем вы можете отфильтровать, где именно вы хотите применить его, используя pointcut для отфильтруйте методы или не используйте pointcut (без фильтра), чтобы он применялся ко всем методам класса.
Я согласен с mgroves. Точка разреза может рассматриваться как совокупность нескольких точек соединения. Точка соединения указывает конкретное место, где рекомендация может быть реализована, где точка указывает на список всех точек соединения.
Pointcut определяется в реализации класса Aspect. Сечение точки в основном относится к выражению точки среза в рекомендации.
Например,
@Before("execution(* app.purchase2.service.impl.*(..))")
public void includeAddOns(RolesAllowed roles) {
..
}
Вышеуказанное означает, что метод "includeAddOns" вызывается перед вызовом (из-за рекомендации @Before) любых методов (в классах в пакете "app.purchase2.service.impl")
Вся аннотация называется pointcut @Before("execution(* app.purchase2.service.impl.*(..))")
Точка соединения - это фактический вызов метода, который соединил метод в пакете "app.purchase2.service.impl" с методом в классе аспекта "includeAddOns()".
Вы можете получить доступ к свойствам точки соединения с помощью org.aspectj.lang.JoinPoint
учебный класс.
Когда вы идете в ресторан, вы смотрите на меню и видите несколько вариантов на выбор. Вы можете заказать одно или несколько блюд из меню. Но пока вы их на самом деле не закажете, это просто «возможность пообедать». Как только вы делаете заказ, и официант приносит его к вашему столу, это еда.
Точки соединения — это параметры в меню, а точки — это элементы, которые вы выбираете. Точка соединения — это возможность в коде применить аспект... просто возможность. Как только вы воспользуетесь этой возможностью и выберете одну или несколько точек соединения и примените к ним аспект, вы получите pointcut.
JoinPoint: указывает точку (метод) в приложении, где будет выполняться совет.
Pointcut: это комбинация JoinPoints, и она указывает, на каком этапе будет выполняться JoinPoint Advice.
Я думаю, что ключевое отличие можно найти здесь:
В то время как аспекты определяют пересекающиеся типы, система AspectJ не допускает полностью произвольного пересечения. Скорее, аспекты определяют типы, пересекающие принципиальные моменты выполнения программы. Эти принципиальные точки называются точками соединения.
Это означает, что точки соединения — это четко определенные наборы мест в потоке выполнения кода вашего приложения, к которым могут быть применены советы по аспектам (т. е. размещены точки (или более)). Вы не можете просто применить pointcuts волей-неволей в своем коде, используя AspectJ. Формальным определением мест, где можно применять точечные разрезы, являются точки соединения.
Лучший ответ здесь. В чем смысл использования метода @Pointcut в Spring AOP, просто сигнатура pointcut?
Мы используем экспресс-язык pointcut, чтобы указать место, которое мы хотим добавить в код. Если есть только одно место, мы можем определить его непосредственно в аннотации @Before, @After или @Around. Если есть несколько мест, мы можем сначала определить каждое с помощью аннотации @Pointcut (с его фиктивным методом). Затем мы можем сгруппировать их вместе (&& или ||) и использовать в аннотациях @Before, @After или @Around.
Аспект представляет собой пакет советов.
например у нас есть
CoffeeService.buildDrink()
а также
BreadService.buildFood()
. В
AfterSaleApsect.java
, Существуют
surveyAdvice()
а также
couponAdvice()
, которые можно вплести в эти сервисы.
Чтобы описать совет, нам нужно указать как минимум на 3 вещи.
- Когда: joinPoint, сценарий, в котором происходит данное событие (например, выполнение метода, обработка исключений, изменение значений переменных объекта и т. д. В Spring AOP точка соединения всегда является выполнением метода. Ref)
- Кто: pointcut, предварительные условия (выражения) для целей должны совпадать, иначе совет не будет выполнен.
- Что делать.
@Aspect
public Class AfterSaleApsect{
//@When("Who")
//public void What(){
// ...
//}
//@AfterReturning("execution(* com.example.restaurant.service.*.build*())")
@AfterReturning("myPointcut()")
public void surveyAdvice(){
doSurvey();
}
//@AfterReturning("execution(* com.example.restaurant.service.*.build*())")
@AfterReturning("myPointcut()")
public void couponAdvice(){
doCoupon();
}
//Make it reusable
@Pointcut("execution(* com.example.restaurant.service.*.build*())")
public void myPointcut(){}
}
PointCut - это аннотация, вы можете объявить область внутри
()
где будет применяться совет.
вместо этого JoinPoint - это интерфейс, это параметр, используемый для всех пяти советов. В частности, для совета @Around применяется ProceedingJoinPoint (дочерний интерфейс JoinPoint), который предоставляет
.proceed()
метод. Таким образом, вы можете контролировать, запускать программу или нет. Вы также можете изменить его аргументы.
Точка соединения - это место, где мы фактически размещаем советы
но сокращение точек - это набор точек соединения. это означает, что то, как мы строим сквозную логику, называется точечным разрезом