Cодержание
- 1- Введение
- 2- Требования перед началом
- 3- Классы участвующие в примере
- 4- Создать AspectJ Project
- 5- Первый пример с AspectJ
- 6- Базовые понятия в AspectJ
- 7- Пример базового AspectJ
-
- 7.1- Правила для class, method, * и ..
- 7.2- Target & args
- 7.3- Оператор && ||
- 7.4- Field в AspectJ
- 7.5- Межтиповое объявление (Inter-type declarations)
- 7.6- Tracking
- 7.7- Cflow
- 7.8- Cflowbelow
Руководство Java Aspect Oriented Programming с AspectJ (AOP)
View more Tutorials:
- 1- Введение
- 2- Требования перед началом
- 3- Классы участвующие в примере
- 4- Создать AspectJ Project
- 5- Первый пример с AspectJ
- 6- Базовые понятия в AspectJ
- 7- Пример базового AspectJ
-
- 7.1- Правила для class, method, * и ..
- 7.2- Target & args
- 7.3- Оператор && ||
- 7.4- Field в AspectJ
- 7.5- Межтиповое объявление (Inter-type declarations)
- 7.6- Tracking
- 7.7- Cflow
- 7.8- Cflowbelow
-
....
-
1- Введение
-
Данная статья основана на:
-
-
Eclipse 4.4 (LUNA)
-
AspectJ 1.8.2
-
-
2- Требования перед началом
-
Вам необходимо установить инструмент разработки AspectJ в Eclipse, вы можете ознакомиться с инструкциями по ссылке:
-
3- Классы участвующие в примере
-
В данной статье я использую некоторые классы, которые участвуют в иллюстрированном примере AspectJ.
-
- Box
- FigureElement
- Group
- Line
- Point
- ShapeFigureElement
- SlotfulPoint
-
Источник этих классов взяты из:
-
-
Box.java
package figures; import java.awt.Rectangle; import java.awt.Shape; public class Box extends ShapeFigureElement { private Point _p0; private Point _p1; private Point _p2; private Point _p3; public Box(int x0, int y0, int width, int height) { _p0 = new Point(x0, y0); _p1 = new Point(x0 + width, y0); _p2 = new Point(x0 + width, y0 + height); _p3 = new Point(x0, y0 + height); } public Point getP0() { return _p0; } public Point getP1() { return _p1; } public Point getP2() { return _p2; } public Point getP3() { return _p3; } @Override public void move(int dx, int dy) { _p0.move(dx, dy); _p1.move(dx, dy); _p2.move(dx, dy); _p3.move(dx, dy); } public void checkBoxness() { if ((_p0.getX() == _p3.getX()) && (_p1.getX() == _p2.getX()) && (_p0.getY() == _p1.getY()) && (_p2.getY() == _p3.getY())) return; throw new IllegalStateException("This is not a square."); } @Override public String toString() { return "Box(" + _p0 + ", " + _p1 + ", " + _p2 + ", " + _p3 + ")"; } @Override public Shape getShape() { return new Rectangle(getP1().getX(), getP1().getY(), getP3().getX() - getP1().getX(), getP3().getY() - getP1().getY()); } }
-
FigureElement.java
package figures; import java.awt.*; import java.awt.geom.*; public interface FigureElement { public static final Rectangle MAX_BOUNDS = new Rectangle(0, 0, 500, 500); public abstract void move(int dx, int dy); public abstract Rectangle getBounds(); public abstract boolean contains(Point2D p); public abstract void paint(Graphics2D g2); }
-
Group.java
package figures; import java.awt.Graphics2D; import java.awt.Rectangle; import java.awt.geom.Point2D; import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; public class Group implements FigureElement { private Collection _members; private String _identifier; public Group(FigureElement first) { this._members = new ArrayList(); add(first); } public void add(FigureElement fe) { _members.add(fe); } public Iterator members() { return _members.iterator(); } public void move(int dx, int dy) { for (Iterator i = _members.iterator(); i.hasNext();) { FigureElement fe = (FigureElement) i.next(); fe.move(dx, dy); } } public void setIdentifier(String identifier) { _identifier = identifier; } @Override public String toString() { if (_identifier != null) { return _identifier; } StringBuffer buf = new StringBuffer("Group("); for (Iterator i = _members.iterator(); i.hasNext();) { buf.append(i.next().toString()); if (i.hasNext()) { buf.append(", "); } } buf.append(")"); return buf.toString(); } public Rectangle getBounds() { Rectangle previous = null; for (Iterator i = _members.iterator(); i.hasNext();) { FigureElement fe = (FigureElement) i.next(); Rectangle rect = fe.getBounds(); if (previous != null) { previous = previous.union(rect); } else { previous = rect; } } return previous; } public boolean contains(Point2D p) { for (Iterator i = _members.iterator(); i.hasNext();) { FigureElement fe = (FigureElement) i.next(); if (fe.contains(p)) return true; } return false; } public void paint(Graphics2D g2) { for (Iterator i = _members.iterator(); i.hasNext();) { FigureElement fe = (FigureElement) i.next(); fe.paint(g2); } } public int size() { return _members.size(); } }
-
Line.java
package figures; import java.awt.*; import java.awt.geom.*; public class Line extends ShapeFigureElement { private Point _p1; private Point _p2; public Line(Point p1, Point p2) { _p1 = p1; _p2 = p2; } public Point getP1() { return _p1; } public Point getP2() { return _p2; } @Override public void move(int dx, int dy) { _p1.move(dx, dy); _p2.move(dx, dy); } @Override public String toString() { return "Line(" + _p1 + ", " + _p2 + ")"; } /** * Used to determine if this line {@link contains(Point2D)} a point. */ final static int THRESHHOLD = 5; /** * Returns <code>true</code> if the point segment distance is less than * {@link THRESHHOLD}. */ @Override public boolean contains(Point2D p) { return getLine2D().ptLineDist(p) < THRESHHOLD; } private Line2D getLine2D() { return new Line2D.Float((float) getP1().getX(), (float) getP1().getY(), (float) getP2().getX(), (float) getP2().getY()); } public Shape getShape() { return getLine2D(); } }
-
Point.java
package figures; import java.awt.*; import java.awt.geom.*; public class Point extends ShapeFigureElement { private int _x; private int _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; } @Override public void move(int dx, int dy) { _x += dx; _y += dy; } @Override public String toString() { return "Point(" + _x + ", " + _y + ")"; } /** The height of displayed {@link Point}s. */ private final static int HEIGHT = 10; /** The width of displayed {@link Point}s. -- same as {@link HEIGHT}. */ private final static int WIDTH = Point.HEIGHT; @Override public Shape getShape() { return new Ellipse2D.Float((float) getX() - Point.WIDTH / 2, (float) getY() - Point.HEIGHT / 2, (float) Point.HEIGHT, (float) Point.WIDTH); } }
-
ShapeFigureElement.java
package figures; import java.awt.*; import java.awt.geom.*; public abstract class ShapeFigureElement implements FigureElement { @Override public abstract void move(int dx, int dy); public abstract Shape getShape(); @Override public Rectangle getBounds() { return getShape().getBounds(); } @Override public boolean contains(Point2D p) { return getShape().contains(p); } public Color getLineColor() { return Color.black; } public Color getFillColor() { return Color.red; } @Override public final void paint(Graphics2D g2) { Shape shape = getShape(); g2.setPaint(getFillColor()); g2.fill(shape); g2.setPaint(getLineColor()); g2.draw(shape); } }
-
SlothfulPoint.java
package figures; import java.awt.*; import java.awt.geom.*; /** * This class makes mistakes to be caught by invariant checkers. */ public class SlothfulPoint extends ShapeFigureElement { private int _x; private int _y; public SlothfulPoint(int x, int y) { } public int getX() { return _x; } public int getY() { return _y; } public void setX(int x) { } public void setY(int y) { } @Override public void move(int dx, int dy) { System.out.println("Slothful moving"); } @Override public String toString() { return "SlothfulPoint"; } @Override public Shape getShape() { return new Ellipse2D.Float((float) _x, (float) _y, 1.0f, 1.0f); } }
-
4- Создать AspectJ Project
-
Для начала создайте обычный проект с названием AspectJTutorial.
-
-
Кликните правой кнопкой мыши на Project и выберите Configure/Convert to AspectJ Project.
-
-
Convert завершен:
-
-
5- Первый пример с AspectJ
-
Для начала, мы используем первый пример, прежде чем начинать с понятиями:
-
Создайте класс HelloAspectJDemo:
-
HelloAspectJDemo.java
package org.o7planning.tutorial.aspectj.helloaspectj; public class HelloAspectJDemo { public static void sayHello() { System.out.println("Hello"); } public static void greeting() { String name = new String("John"); sayHello(); System.out.print(name); } public static void main(String[] args) { sayHello(); System.out.println("--------"); sayHello(); System.out.println("--------"); greeting(); } }
-
На класс выше не стоит обращать внимания, однако проблема заключается в том, что если вы хотите, чтобы программа делала что-то прямо перед или после вызова метода sayHello(), например, печать объявления на экране. Традиционно вы можете добавить команду, печатающую объявление прямо на экране перед или после вызова метода sayHello().
-
-
AspectJ - это своего рода аспектное программирование. Он предоставляет вам другое решение для решения этой проблемы, но AspectJ может сделать еще больше. Помните, что это просто пример HelloWorld.
-
- File/New/Other..
-
-
-
Создан файл с названием HelloAspectJ.aj, и его структура очень похожа на класс.
-
Предыдущие версии AspectJ используют аннотацию (annotation) для описания. В последних версиях используется файл * .aj. В этой статье я пропускаю использование аннотации, поскольку это не так ясно, как использование файла .aj. Кроме того, синтаксис файла * aj похож на класс, и eclipse будет уведомлять вас о ваших грамматических ошибках.
-
-
Редактирование кода HelloAspectJ.aj:
-
HelloAspectJ.aj
package org.o7planning.tutorial.aspectj.helloaspectj; public aspect HelloAspectJ { // Define a Pointcut is // collection of JoinPoint call sayHello of class HelloAspectJDemo. pointcut callSayHello(): call(* HelloAspectJDemo.sayHello()); before() : callSayHello() { System.out.println("Before call sayHello"); } after() : callSayHello() { System.out.println("After call sayHello"); } }
-
AspectJ имеет некоторые отличия от типичного класса, в котором он добавляет много ключевых слов. Его имя файла имеет хвост * .aj вместо * .java. Некоторые ключевые слова для AspectJ:
-
- aspect pointcut privileged call execution
- initialization preinitialization handler get set
- staticinitialization target args within withincode
- cflow cflowbelow annotation before after around
- proceed throwing returning adviceexecution declare
- parents warning error soft precedence thisJoinPoint
- thisJoinPointStaticPart thisEnclosingJoinPointStaticPart
- issingleton perthis pertarget percflow percflowbelow
- pertypewithin lock unlock thisAspectInstance
-
-
Вернемся к примеру HelloWorld. Теперь мы запустим класс HelloAspectJDemo, и результат будет таким:
-
-
AspectJ очень силен. Например, в приведенном выше примере исправление кода на HelloAspectJ.aj может заставить его работать с каждым классом, вызывающим метод sayHello ().
-
// Define a pointcut is a Collection of JoinPoint // call sayHello() of HelloAspectJDemo pointcut callSayHello(): call(* HelloAspectJDemo.sayHello()); // Change to: // This means that everywhere (class, AspectJ) called sayHello() pointcut callSayHello(): call(* *.sayHello());
-
6- Базовые понятия в AspectJ
-
В AspectJ вам нужно различать несколько понятий:
-
- Advice
- Pointcut
- JoinPoint
-
-
6.1- JoinPoint
-
JoinPoint (точка объединения) является четко определенной точкой в потоке программы.
-
- Мы хотим выполнить определенный код ("advice") при каждом достижении точки объединения
- Мы не хотим загромождать код явными индикаторами, говорящими: "Это точка объединения",
- То есть не вписываем код сами в это место
- AspectJ предоставляет синтаксис для указания этих JoinPoint "извне" фактического кода.
Отметить их и выполнить определенный код извне.
-
JoinPoint - это точка в программном потоке "Где происходит что-то определенное", что-то здесь может быть:
-
- Когда метод вызывается
- Когда выбрасывается исключение
- Когда получен доступ (accessed)
- При инициализации объекта
- При ссылке к объекту
-
Таким образом JoinPoint очень разнообразен, точка где вы инициализируете объект тоже рассматривается как JoinPoint.
-
Возвращаемся к примеру HelloWorld, мы определим некоторые JoinPoints:
-
-
6.2- PointCut
-
Определение Pointcut включает один слева и один справа, отделенные друг от друга двоеточием.
-
- На левой стороне включает названия pointcut и параметры pointcut (например, готовые данные когда происходят события)
- На правой сторне содержится сам Pointcut
-
Пример:
-
pointcut callSayHello(): call(* HelloAspectJDemo.sayHello());
-
- Название этого pointcut callSayHello
- У pointcut нет параметров
- Сам pointcut является call (* HelloAspectJDemo.sayHello())
- Pointcut ссылается на любое время, когда вызывается метод HelloAspectJDemo.sayHello()
-
-
6.3- Advice
-
Возвращаемся к примеру HelloWorld, У нас есть 2 advice (совет)
-
- before()
- after()
-
-
Advice (совет) определяет поведение. Код Advice запускается в каждой точке объединения (join point) в Pointcut. То, как работает код, зависит от вида Advice (совета).
-
AspectJ поддерживает три вида Advice. Виды Advice определяют, как он взаимодействует с JoinPoint (точками объединения), которые он определяет. Таким образом, AspectJ делится на до (before), после (after) запуска JoinPoint, и вокруг (around) (на месте или «рядом») JoinPoint.
-
Во то время как "before Advice" относительно не имеет проблем, с "after Advice" могут быть 3 ситуации: после того, как выполнение JoinPoint завершается нормально, после того как выбрасывается исключение или после того, как оно делает одно из двух. AspectJ позволяет "after Advice" для любой из этих ситуаций.
-
Чтобы легче было понять, посмотрим несколько примеров Advice:
-
HelloAspectJ2.aj
package org.o7planning.tutorial.aspectj.helloaspectj; public aspect HelloAspectJ2 { pointcut callSayHello(): call(* HelloAspectJDemo.sayHello()); // Advice "after returning". after() returning (Object retObj): callSayHello() { System.out.println("Returned normally with " + retObj); } // Advice "after throwing". after() throwing (Exception e): callSayHello() { System.out.println("Threw an exception: " + e); } // Advice "after returning" + "after throwing". after() : callSayHello() { System.out.println("Returned or threw an Exception"); } }
-
Вид Advice " after returning" может не беспокоиться о возвращаемом значении (метода), поэтому мы можем записать.
-
// Advice "after returning". // care about the returning value of method after() returning (Object retObj): callSayHello() { System.out.println("Returned normally with " + retObj); } // Advice "after returning" not care about the returning value of method after() returning(): callSayHello() { System.out.println("Returned normally"); } // or // Advice "after returning" not care about the returning value of method after() returning : callSayHello() { System.out.println("Returned normally"); }
-
-
7- Пример базового AspectJ
-
Прежде чем перейти к повышенным деталям, мы рассмотрим базовые примеры и правила в AspectJ, если вы не поймете эти правила, вы не сможете понять AspectJ.
-
-
7.1- Правила для class, method, * и ..
-
В AspectJ если вы хотите упомянуть класс, метод в объявлении Pointcut вам нужно написать его полное название. Например:
-
- figures.Point
- figures.Point.setX(int)
-
Если класс и AspectJ находятся в одном пакете, вы можете написать вкратце. Например:
-
- Point
- Point.setX(int)
-
Давайте посмотрим на следующую иллюстрацию: AspectJ01.aj и class Point находятся в двух разных пакетах.
-
-
AspectJ01.aj
package org.o7planning.tutorial.aspectj.demo01; public aspect AspectJ01 { // Class Point and AspectJ is not the same package // so must specify the package (Required). // This pointcut definition of JoinPoints // only within the class ClassTest01 // This ClassTest01 and AspectJ same package, // so can be ignored package in within(..). pointcut callSetX() : call(void figures.Point.setX(int)) && within (ClassTest01) ; // Advice before() : callSetX() { System.out.println("Before call Point.setX(int)"); } }
-
ClassTest01.java
package org.o7planning.tutorial.aspectj.demo01; import figures.Point; public class ClassTest01 { public static void main(String[] args) { Point point = new Point(10, 200); System.out.println("---- (1) ----"); point.setX(20); System.out.println("---- (2) ----"); point.setY(100); System.out.println("---- (3) ----"); } }
-
Результат запуска class ClassTest01:
-
-
Таким образом здесь есть несколько примечаний:
-
// 'within' used to limit the scope of the pointcut // in the case below: // Only Containing join point inside class ClassTest01. within (ClassTest01) // If you using import import figures.Point; ..... // Then Can write shorter code: pointcut callSetX() : call(void Point.setX(int)) && within (ClassTest01) ;
-
Звездочка (*) в AspectJ
-
// Collection of JoinPoints call Point.setX(int), any package name, // and method return void pointcut callSetX() : call(void *.Point.setX(int)) ; // Collection of JoinPoints call Point.setX(int), any package name, // and method return any pointcut callSetX() : call(* *.Point.setX(int)) ; // Collection of JoinPoints call public static method setX(int) of class with package name is 'sample' // and class name have suffix Point, // and setX(int) return int pointcut callSetX() : call(public static int sample.*Point.setX(int)) ; // Using (..) to describe the method has 0 or more parameters. pointcut callSetX() : call(public static int sample.*Point.setX(..)) ;
-
7.2- Target & args
-
target: Это объект участвующий в JoinPoint (Точка объединения), объект вызывает method (или объект получает доступ к field).
args: Это параметр.
Посмотрим иллюстрированный пример:
-
AspectJ02.aj
package org.o7planning.tutorial.aspectj.demo02; // Ready import Point class. import figures.Point; public aspect AspectJ02 { // Using target: define object on which the method is called // Using args: define args on the method is called // Using within: to restrict JoinPoint within ClassTest02 pointcut callMove(Point point, int dx, int dy) : call(* figures.Point.move(int,int)) && args(dx,dy) && target(point) && within(ClassTest02) ; before(Point point, int dx, int dy) : callMove(point, dx, dy ) { System.out.println("Before call move(" + dx + "," + dy + ")"); System.out.println(point.toString()); } }
-
ClassTest02.java
package org.o7planning.tutorial.aspectj.demo02; import figures.Point; public class ClassTest02 { public static void main(String[] args) { Point point = new Point(10, 200); System.out.println("---- (1) ----"); point.move(20, 30); System.out.println("---- (2) ----"); System.out.println(point.toString()); System.out.println("---- (3) ----"); point.setX(100); } }
-
-
Результаты запуска примера
-
-
7.3- Оператор && ||
-
AspectJ03.aj
package org.o7planning.tutorial.aspectj.demo03; // Note: Must import FigureElement & Point import figures.FigureElement; import figures.Point; public aspect AspectJ03 { // pointcut: Include move actions pointcut moveAction() : ( call(void FigureElement.move(int,int)) || call(void Point.setX(int)) || call(void Point.setY(int)) ) && within (ClassTest03); before() : moveAction() { System.out.println("before move"); } }
-
ClassTest03.java
package org.o7planning.tutorial.aspectj.demo03; import figures.FigureElement; import figures.Line; import figures.Point; public class ClassTest03 { public static void main(String[] args) { Point point = new Point(10, 200); System.out.println("---- (1) ----"); point.setX(20 ); System.out.println("---- (2) ----"); FigureElement line= new Line(new Point(1,1), new Point(10,10)); line.move(10, 10); System.out.println("---- (3) ----"); } }
-
Результаты запуска примера
-
-
7.4- Field в AspectJ
-
FieldInAspectJ.aj
package org.o7planning.tutorial.aspectj.demo04; import java.io.PrintStream; public aspect FieldInAspectJ { // Field in AspectJ. PrintStream logStream = System.err; pointcut move() : call(* figures.Point.move(int,int)) && within(FieldInAspectJTest); before(): move() { logStream.println("Before Point move"); } }
-
FieldInAspectJTest.java
package org.o7planning.tutorial.aspectj.demo04; import figures.Point; public class FieldInAspectJTest { public static void main(String[] args) { Point point = new Point(10, 200); System.err.println("---- (1) ----"); point.setX(20); System.err.println("---- (2) ----"); point.move(10, 10); System.err.println("---- (3) ----"); } }
-
Результаты запуска примера:
-
-
7.5- Межтиповое объявление (Inter-type declarations)
-
PointObserving.aj
package org.o7planning.tutorial.aspectj.demo05; import java.util.ArrayList; import java.util.List; import figures.Point; public aspect PointObserving { // Class Point have no field: observers // However, it can declare here. // observers: Store the change point position. private List<Point> Point.observers = new ArrayList<Point>(); pointcut moveAction(Point point) : call(void Point.move(int,int) ) && target(point) && within(PointObservingTest); after(Point point) : moveAction(point) { System.out.println("Point moved"); // add new position point.observers.add(point); // Print the location of the point went through. System.out.println(" - "+point.observers); } public static void addObserver(Point p) { // p.observers.add(s); } public static void removeObserver(Point p) { // p.observers.remove(s); } }
-
PointObservingTest.java
package org.o7planning.tutorial.aspectj.demo05; import figures.Point; public class PointObservingTest { public static void main(String[] args) { Point point1 = new Point(100, 100); // First move point1.move(10, 10); // Second move point1.move(10, 10); System.out.println("----------------------"); Point point2 = new Point(200, 200); // First move point2.move(15, 10); // Second move point2.move(15, 10); // Third Move point2.move(25, 10); } }
-
Результаты запуска примера:
-
-
7.6- Tracking
-
Tracking: То есть отслеживание(Какие методы были вызваны и в каком порядке, или определенные происшествия ...)
-
Мы создадим Aspect, который определяет pointcut содержащий участвующие pointcut где выполняются методы, и создаем так же Advice чтобы определить код, который будет выполнен в том месте.
-
SimpleTracing.aj
package org.o7planning.tutorial.aspectj.demo06; import org.aspectj.lang.Signature; public aspect SimpleTracing { // Collection of JoinPoint call any method // And within SimpleTracingTest pointcut tracedCall() : call (* *(..)) // && !within(SimpleTracing) && within(SimpleTracingTest) ; before() : tracedCall() { Signature sig = thisJoinPointStaticPart.getSignature(); String line = "" + thisJoinPointStaticPart.getSourceLocation().getLine(); String sourceName = thisJoinPointStaticPart.getSourceLocation() .getWithinType().getCanonicalName(); // System.out.println("Call from " + sourceName + " line " + line + "\n to " + sig.getDeclaringTypeName() + "." + sig.getName() +"\n"); } }
-
SimpleTracingTest.java
package org.o7planning.tutorial.aspectj.demo06; import figures.Point; public class SimpleTracingTest { private static void testMethod1() { Point point = new Point(100, 100); point.setX(100); } private static void testMethod2() { String text = "This is text"; String s = text.substring(2); System.out.println(s); } public static void main(String[] args) { testMethod1(); testMethod2(); } }
-
Результаты запуска примера:
-
-
7.7- Cflow
-
Управление потоком (control flow) это поток выполнения программы внутри определнной точки объединения (JointPoint). cflow() и cflowbelow() созданы чтобы словить другие точки объединения как параметр и позволяет нам определить управление потоком на основании pointcut - эти pointcuts словят вся точки объединения в управлении потоком каждой определенной Joinpoint.
-
cflow() фиксирует все точки объединения (join point) как call, execution, set и get field, error handlers в управлении потоком определенного JointPont.
-
Изображение ниже содержит JointPoint вызывая method MyClass.callA().
-
-
Используя cflow(..):
-
-
-
Смотрите детальный пример:
-
-
CflowAspectJ.aj
package org.o7planning.tutorial.aspectj.demo07; public aspect CflowAspectJ { pointcut call_cflow_callA() : cflow( call( * MyClass.callA() ) ) && within(CFlowDemo || MyClass); before() : call_cflow_callA() { System.out.println( "Join Point at: " + thisJoinPointStaticPart.getSourceLocation().getWithinType().getCanonicalName() + " --> " + thisJoinPointStaticPart.getSourceLocation().getLine()); } }
-
MyClass.java
package org.o7planning.tutorial.aspectj.demo07; public class MyClass { public void callA() { callB(); callC(); } public void callB() { callC(); } public void callC() { } }
-
CFlowDemo.java
package org.o7planning.tutorial.aspectj.demo07; public class CFlowDemo { public static void main(String[] args) { MyClass myClass= new MyClass(); myClass.callA(); myClass.callA(); } }
-
Результат запуска class CFlowDemo:
-
-
7.8- Cflowbelow
-
Управление потоком (control flow) это поток выполнения программы внутри определенной точки объединения (JointPoint). cflow() и cflowbelow() созданы чтобы словить другие точки объединения, как параметр и позволяет нам определить управление потоком основываясь на pointcut - эти pointcuts словят все точки объединения в управлении потоком каждой определенной Joinpoint.
-
cflowbelow() имеет поведение схожее с cflow, но он не ловит точки объединения в его параметрах, и ловит все остальные точки объединения.
-
Вы можете посмотреть больше в части cflow().
-
-