Аспектно-ориентированное программирование Java с помощью AspectJ (AOP)
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, и результат будет таким:
Before call sayHello
Hello
After call sayHello
--------
Before call sayHello
Hello
After call sayHello
--------
Before call sayHello
Hello
After call sayHello
John
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
JoinPoint
JoinPoint (точка объединения) является четко определенной точкой в потоке программы.
- Мы хотим выполнить определенный код ("advice") при каждом достижении точки объединения
- Мы не хотим загромождать код явными индикаторами, говорящими: "Это точка объединения",
- То есть не вписываем код сами в это место
- AspectJ предоставляет синтаксис для указания этих JoinPoint "извне" фактического кода.
Отметить их и выполнить определенный код извне.
JoinPoint - это точка в программном потоке "Где происходит что-то определенное", что-то здесь может быть:
- Когда метод вызывается
- Когда выбрасывается исключение
- Когда получен доступ (accessed)
- При инициализации объекта
- При ссылке к объекту
Таким образом JoinPoint очень разнообразен, точка где вы инициализируете объект тоже рассматривается как JoinPoint.
Возвращаемся к примеру HelloWorld, мы определим некоторые JoinPoints:
PointCut
Определение Pointcut включает один слева и один справа, отделенные друг от друга двоеточием.
- На левой стороне включает названия pointcut и параметры pointcut (например, готовые данные когда происходят события)
- На правой сторне содержится сам Pointcut
Пример:
pointcut callSayHello(): call(* HelloAspectJDemo.sayHello());
- Название этого pointcut callSayHello
- У pointcut нет параметров
- Сам pointcut является call (* HelloAspectJDemo.sayHello())
- Pointcut ссылается на любое время, когда вызывается метод HelloAspectJDemo.sayHello()
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.
Правила для 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:
---- (1) ----
Before call Point.setX(int)
---- (2) ----
---- (3) ----
Таким образом здесь есть несколько примечаний:
// '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(..)) ;
Target & args
target: Это объект участвующий в JoinPoint (Точка объединения), объект вызывает method (или объект получает доступ к field).
args: Это параметр.
Посмотрим иллюстрированный пример:
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);
}
}
Результаты запуска примера
---- (1) ----
Before call move(20,30)
Point(10, 200)
---- (2) ----
Point(30,230)
---- (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) ----");
}
}
Результаты запуска примера
---- (1) ----
before move
---- (2) ----
before move
---- (3) ----
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) ----");
}
}
Результаты запуска примера:
---- (1) ----
---- (2) ----
Before Point move
---- (3) ----
Межтиповое объявление (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);
}
}
Результаты запуска примера:
Point moved
- [Point(110, 110)]
Point moved
- [Point(120, 120), Point(120, 120)]
----------------------
Point moved
- [Point(215, 210)]
Point moved
- [Point(230, 220), Point(230, 220)]
Point moved
- [Point(255, 230), Point(255, 230), Point(255, 230)]
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();
}
}
Результаты запуска примера:
Call from org.o7planning.tutorial.aspectj.demo06.SimpleTracingTest line 23
to org.o7planning.tutorial.aspectj.demo06.SimpleTracingTest.testMethod1
Call from org.o7planning.tutorial.aspectj.demo06.SimpleTracingTest line 9
to figures.Point.setX
Call from org.o7planning.tutorial.aspectj.demo06.SimpleTracingTest line 25
to org.o7planning.tutorial.aspectj.demo06.SimpleTracingTest.testMethod2
Call from org.o7planning.tutorial.aspectj.demo06.SimpleTracingTest line 16
to java.lang.String.substring
Call from org.o7planning.tutorial.aspectj.demo06.SimpleTracingTest line 18
to java.io.PrintStream.println
is is text
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:
Join Point at: org.o7planning.tutorial.aspectj.demo07.CFlowDemo --> 10
Join Point at: org.o7planning.tutorial.aspectj.demo07.MyClass --> 5
Join Point at: org.o7planning.tutorial.aspectj.demo07.MyClass --> 7
Join Point at: org.o7planning.tutorial.aspectj.demo07.MyClass --> 12
Join Point at: org.o7planning.tutorial.aspectj.demo07.MyClass --> 14
Join Point at: org.o7planning.tutorial.aspectj.demo07.MyClass --> 17
Join Point at: org.o7planning.tutorial.aspectj.demo07.MyClass --> 9
Join Point at: org.o7planning.tutorial.aspectj.demo07.MyClass --> 17
Join Point at: org.o7planning.tutorial.aspectj.demo07.CFlowDemo --> 12
Join Point at: org.o7planning.tutorial.aspectj.demo07.MyClass --> 5
Join Point at: org.o7planning.tutorial.aspectj.demo07.MyClass --> 7
Join Point at: org.o7planning.tutorial.aspectj.demo07.MyClass --> 12
Join Point at: org.o7planning.tutorial.aspectj.demo07.MyClass --> 14
Join Point at: org.o7planning.tutorial.aspectj.demo07.MyClass --> 17
Join Point at: org.o7planning.tutorial.aspectj.demo07.MyClass --> 9
Join Point at: org.o7planning.tutorial.aspectj.demo07.MyClass --> 17
Cflowbelow
Управление потоком (control flow) это поток выполнения программы внутри определенной точки объединения (JointPoint). cflow() и cflowbelow() созданы чтобы словить другие точки объединения, как параметр и позволяет нам определить управление потоком основываясь на pointcut - эти pointcuts словят все точки объединения в управлении потоком каждой определенной Joinpoint.
cflowbelow() имеет поведение схожее с cflow, но он не ловит точки объединения в его параметрах, и ловит все остальные точки объединения.
Вы можете посмотреть больше в части cflow().
Java Basic
- Настройте java compiler для обработки вашего Annotation (Annotation Processing Tool)
- Программирование на Java для группы с помощью Eclipse и SVN
- Руководство Java WeakReference
- Руководство Java PhantomReference
- Сжатие и декомпрессия в Java
- Настройка Eclipse для использования JDK вместо JRE
- Методы String.format() и printf() в Java
- Синтаксис и новые функции в Java 8
- Регулярные выражения Java
- Руководство Java Multithreading Programming
- Библиотеки Java JDBC Driver для различных типов баз данных
- Руководство Java JDBC
- Получить значения столбцов, автоматически возрастающих при вставлении (Insert) записи, используя JDBC
- Руководство Java Stream
- Руководство Java Functional Interface
- Введение в Raspberry Pi
- Руководство Java Predicate
- Абстрактный класс и Interface в Java
- Модификатор доступа (Access modifiers) в Java
- Руководство Java Enum
- Руководство Java Annotation
- Сравнение и Сортировка в Java
- Руководство Java String, StringBuffer и StringBuilder
- Обработка исключений Java - Java Exception Handling
- Руководство Java Generics
- Манипулирование файлами и каталогами в Java
- Руководство Java BiPredicate
- Руководство Java Consumer
- Руководство Java BiConsumer
- Что мне нужно для начала работы с Java?
- История Java и разница между Oracle JDK и OpenJDK
- Установить Java в Windows
- Установите Java в Ubuntu
- Установите OpenJDK в Ubuntu
- Установить Eclipse
- Установите Eclipse в Ubuntu
- Быстрое изучение Java для начинающих
- История бит и байтов в информатике
- Типы данных в java
- Битовые операции
- Команда if else в Java
- команды switch в Java
- Циклы в Java
- Массивы (Array) в Java
- JDK Javadoc в формате CHM
- Наследование и полиморфизм в Java
- Руководство Java Function
- Руководство Java BiFunction
- Пример Java encoding и decoding с использованием Apache Base64
- Руководство Java Reflection
- Java Удаленный вызов методов - Java RMI
- Руководство Программирование Java Socket
- Какую платформу я должен выбрать для разработки приложений Java Desktop?
- Руководство Java Commons IO
- Руководство Java Commons Email
- Руководство Java Commons Logging
- Понимание Java System.identityHashCode, Object.hashCode и Object.equals
- Руководство Java SoftReference
- Руководство Java Supplier
- Аспектно-ориентированное программирование Java с помощью AspectJ (AOP)
Show More
- Руководства Java Servlet/JSP
- Руководства Java Collections Framework
- Java API для HTML, XML
- Руководства Java IO
- Руководства Java Date Time
- Руководства Spring Boot
- Руководства Maven
- Руководства Gradle
- Руководства Java Web Services
- Руководства Java SWT
- Руководства JavaFX
- Руководства Oracle Java ADF
- Руководства Struts2 Framework
- Руководства Spring Cloud