Introduction to Aspect-Oriented Programming Martin Giese Chalmers University of Technology

advertisement
Introduction to
Aspect-Oriented Programming
Martin Giese
Chalmers University of Technology
Göteborg, Sweden
AOP Course 2003 – p.1/44
AspectJ Quick Tour
AOP Course 2003 – p.2/44
Reminder: Join Points
A join point is a well-defined point in the execution of a program.
Examples:
• a method/constructor call
• execution of a method/constructor implementation
• read/write access to a field
•
..
.
Program flow can enter and leave a join point.
AOP Course 2003 – p.3/44
Reminder: Pointcuts
A pointcut is the static designation of some set of join points for every
execution of the program.
Examples:
• all calls to public methods of the Point class
• every execution of a constructor with one int argument
• every write access to a public field
•
..
.
AOP Course 2003 – p.4/44
Code Example: Figure Editor
Figure
*
+makePoint(..)
+makeLine(..)
FigureElement
+moveBy(int,int)
Display
+update()
Point
+getX()
+getY()
+setX(int)
+setY(int)
+moveBy(int,int)
Line
2
+getP1()
+getP2()
+setP1(Point)
+setP2(Point)
+moveBy(int,int)
AOP Course 2003 – p.5/44
Code Example (cont.)
class Line implements FigureElement {
private Point p1, p2;
Point getP1() { return p1; }
Point getP2() { return p2; }
void setP1(Point p1) { this.p1 = p1; }
void setP2(Point p2) { this.p2 = p2; }
void moveBy(int dx, int dy) { p1.moveBy(dx,dy); p2.moveBy(dx,dy); }
}
class Point implements FigureElement {
private int x = 0, y = 0;
int getX() { return x; }
int getY() { return y; }
void setX(int x) { this.x = x; }
void setY(int y) { this.y = y; }
void moveBy(int dx, int dy) { x += dx; y += dy; }
}
AOP Course 2003 – p.6/44
Pointcuts in AspectJ
Primitive pointcuts:
call(void Point.setX(int))
each join point that is a call to a method that has the signature
void Point.setX(int)
Also for interface signatures:
call(void FigureElement.moveBy(int,int))
Each call to the moveBy(int,int) method in a class that
implements FigureElement
More later. . .
AOP Course 2003 – p.7/44
Composition of Pointcuts
Pointcuts can be joined using boolean operators &&,||,!.
call(void Point.setX(int)) ||
call(void Point.setY(int))
calls to the setX and setY methods of Point.
Question: what does this select?
call(void Line.setP1(Point)) &&
call(void Line.setP2(Point))
AOP Course 2003 – p.8/44
Join points from many types
Join points from different types possible:
call(void FigureElement.moveBy(int,int)) ||
call(void Point.setX(int))
||
call(void Point.setY(int))
||
call(void Line.setP1(Point))
||
call(void Line.setP2(Point))
Any call to a state-changing method in the given
FigureElement classes
AOP Course 2003 – p.9/44
Named Pointcuts
Pointcuts can be declared to give them a name:
pointcut stateChange() :
call(void FigureElement.moveBy(int,int)) ||
call(void Point.setX(int))
||
call(void Point.setY(int))
||
call(void Line.setP1(Point))
||
call(void Line.setP2(Point));
➠ Analogous to method declaration or typedef in C.
After declaration, stateChange() can be used
wherever a pointcut is expected.
AOP Course 2003 – p.10/44
Wildcards
Method signatures can contain wildcards:
call(void java.io.PrintStream.println(*))
any PrintStream method named println returning void and taking
exactly one argument of any type.
call(public * Figure.*(..))
any public method in Figure.
call(public * Line.set*(..))
any method in Line with a name starting with set.
AOP Course 2003 – p.11/44
Example
The pointcut from before, using wildcards:
pointcut stateChange() :
call(void FigureElement.moveBy(int,int)) ||
call(* Point.set*(*))
||
call(* Line.set*(*));
AOP Course 2003 – p.12/44
Advice in AspectJ
Advice can be attached to join points:
before(): stateChange() {
System.out.println("about to change state");
}
after() returning: stateChange() {
System.out.println("just successfully changed state");
}
AOP Course 2003 – p.13/44
Aspects in AspectJ
public aspect DisplayUpdating {
pointcut stateChange() :
call(void FigureElement.moveBy(int,int)) ||
call(* Point.set*(*)) || call(* Line.set*(*));
after() returning : stateChange() {
Display.update();
}
}
➠ After every state changing call, update the display.
AOP Course 2003 – p.14/44
Compilation
No partial compilation in AspectJ!
➠ Always provide all class and aspect source files.
ajc Main.java Display.java Figure.java FigureElement.java \
Line.java Point.java DisplayUpdating.java
or
ajc -argfile files.lst
run using:
java Main
AOP Course 2003 – p.15/44
AspectJ Details
AOP Course 2003 – p.16/44
Type Patterns
Used to denote a set of types.
• int
• Line
• *
• java.util.Map*
• java..*Factory*
• java.io.OutputStream+
• Foo+ && !Foo
• Foo+ && !(java..Bar*[])
AOP Course 2003 – p.17/44
Method Patterns
Used to denote a set of methods in one or more classes.
Method declaration:
public final void write(int x) throws IOException
Method pattern:
public final void Writer.write(int) throws IOException
Wildcards possible everywhere. . .
• void *.write(int)
• void Foo+.set*(int)
AOP Course 2003 – p.18/44
Method Patterns (cont.)
• * Foo.write(*)
• * Foo.write(..)
• * Foo.write(..,int)
• * *.*(..)
• public Foo.*(..)
• !public *.*(..)
• * *.*(..) throws java.io.IOException
• * *.*(..) throws !java.io.IOException
• * *.*(..) throws (!java.io.IOException)
AOP Course 2003 – p.19/44
Constructor and Field Patterns
Select a set of constructors:
Like method patterns, with name new and no return type:
• Line.new(int)
• public *.new(..)
•
..
.
Field Patterns:
• int Line.x
• public !final * FigureElement+.*
•
..
.
AOP Course 2003 – p.20/44
Primitive Pointcuts
• call(MethodPattern)
• call(ConstructorPattern)
• execution(MethodPattern)
• execution(ConstructorPattern)
• get(FieldPattern)
• set(FieldPattern)
• handler(TypePattern)
AOP Course 2003 – p.21/44
Restricting the Scope
Static Scope:
• within(TypePattern)
• withincode(MethodPattern)
• withincode(ConstructorPattern)
Dynamic Scope:
• cflow(Pointcut)
• cflowbelow(Pointcut)
AOP Course 2003 – p.22/44
Examples
Match constructor calls from outside factory:
call(FigureElement+.new()) && !within(Figure)
Match state changing calls that are not due to
other state changing calls:
stateChange() && !cflowbelow(stateChange())
Match state changes that are not due to some method in Figure:
stateChange() && !cflow(execution(* Figure.*(..)))
AOP Course 2003 – p.23/44
Example: cflow
caller
point 1
moveBy
a line
moveBy
point 2
moveBy
AOP Course 2003 – p.24/44
Pointcuts with Parameters
One often needs information about the context of a join point.
➠ use pointcuts with parameters.
Example:
pointcut stateChange(FigureElement figElt) :
target(figElt) &&
( call(void FigureElement.moveBy(int,int)) ||
call(* Point.set*(*))
||
call(* Line.set*(*)) );
after(FigureElement fe) : stateChange(fe) {...}
AOP Course 2003 – p.25/44
Parameters in pointcut declaration
pointcut stateChange(FigureElement figElt) :
target(figElt) &&
( call(void FigureElement.moveBy(int,int)) ||
call(* Point.set*(*))
||
call(* Line.set*(*)) );
• figElt declared in ‘header’, together with name.
• bound by the target pointcut
target alone matches any non-static call, field access, etc. if the target type
matches the declared parameter type.
AOP Course 2003 – p.26/44
Parameters in advice declaration
after(FigureElement fe) : stateChange(fe) {
. . . code can use fe. . .
}
after(FigureElement fe) : target(fe) && ... {
. . . code can use fe. . .
}
• fe declared in ‘header’
• bound by the pointcut
➠
values move from right to left over the colon.
AOP Course 2003 – p.27/44
Some more Pointcuts
• target(Id)
• target(Type)
• this(Type or Id)
• args(Type or Id. . . )
• if(boolean expression)
AOP Course 2003 – p.28/44
Example: Diagonal Moves
Define a pointcut for moves with equal dx and dy.
pointcut diagMove() :
call(void FigureElement.moveBy(int,int)) &&
args(dx,dx);
AOP Course 2003 – p.29/44
Example: Diagonal Moves
Define a pointcut for moves with equal dx and dy.
pointcut diagMove(int dx) :
call(void FigureElement.moveBy(int,int)) &&
args(dx,dx);
AOP Course 2003 – p.30/44
Example: Diagonal Moves
Define a pointcut for moves with equal dx and dy.
pointcut diagMove(int dx,int dy) :
call(void FigureElement.moveBy(int,int)) &&
args(dx,dy) &&
if(dx==dy);
AOP Course 2003 – p.31/44
Example: Diagonal Moves
Define a pointcut for moves with equal dx and dy.
pointcut diagHelp(int dx,int dy) :
call(void FigureElement.moveBy(int,int)) &&
args(dx,dy) &&
if(dx==dy);
pointcut diagMove(int dxy) : diagHelp(dxy,int);
AOP Course 2003 – p.32/44
About Conditionals
AspectJ specification:
The boolean expression used can only access static members,
variables exposed by the enclosing pointcut or advice, (and
thisJoinPoint forms).
But still. . . static methods may be called, which may have side effects!
➠ left to right evaluation order of pointcuts.
Exercise:
What about join points of static functions called in if?
AOP Course 2003 – p.33/44
Advice in AspectJ
‘Before’ advice:
before(formal parameters) : Pointcut {
. . . advice body. . .
}
The advice body gets executed every time just before the
program flow enters a join point matched by the pointcut.
The formal parameters receive values from the pointcut.
AOP Course 2003 – p.34/44
After Advice
‘After’ advice:
after(formal parameters) returning : Pointcut {...}
The advice body gets executed every time just after the
program flow exits a join point matched by the pointcut
by returning normally.
Capture return value:
after(...) returning (int ret): Pointcut {...}
AOP Course 2003 – p.35/44
After Advice (cont.)
Advice after throwing an exception:
after(formal parameters) throwing : Pointcut {...}
Capture thrown exception:
after(...) throwing (Exception e): Pointcut {...}
Match normal and abrupt return:
after(...) : Pointcut {...}
AOP Course 2003 – p.36/44
Around Advice
Run advice instead of original code:
Type around(. . . ) : . . . {
...
proceed(. . . );
...
}
• run advice body instead of original call, field access, method body, etc.
• use proceed to use the original join point, if needed.
AOP Course 2003 – p.37/44
Example: Caching
Cache values from an expensive function call.
int around(int x) : call(int Expensive.f(int)) && args(x) {
if (cache.contains(x)) {
return cache.get(x);
} else {
int result = proceed(x);
cache.put(x,result);
return result;
}
}
AOP Course 2003 – p.38/44
thisJoinPoint
For tracing or logging join points, matched methods might have very
different signatures.
➠ difficult to pass all useful information through parameters.
Special variable thisJoinPoint available in advice.
• thisJoinPoint.toString()
• thisJoinPoint.getTarget()
• thisJoinPoint.getArgs()
thisJoinPoint object expensive to construct.
thisJoinPointStaticPart is statically constructed.
AOP Course 2003 – p.39/44
Aspects in AspectJ
Similar to class declarations, but
• Can also contain pointcut and advice declarations,
• System and not user controls instantiation,
(An aspect gets instantiated the first time, some advice in it
needs to be executed.)
• Aspects can extend only abstract aspects,
(They can extend classes and implement interfaces)
• Classes cannot extend aspects.
AOP Course 2003 – p.40/44
Caching Aspect
package se.chalmers.cs.caching;
import se.chalmers.cs.calculations.Expensive;
public aspect CacheExpensiveFunction {
private IntegerCache cache = new IntegerCache();
int around(int x) : call(int Expensive.f(int)) && args(x) {
if (cache.contains(x)) {
return cache.get(x);
} else {
int result = proceed(x);
cache.put(x,result);
return result;
}
}
}
AOP Course 2003 – p.41/44
Tracing Aspect (first try)
package tracing;
public aspect TraceAllCalls {
pointcut pointsToTrace() :
call(* *.*(..)) ;
before() : pointsToTrace() {
System.err.println("Enter " + thisJoinPoint);
}
after() : pointsToTrace() {
System.err.println("Exit " + thisJoinPoint);
}
}
AOP Course 2003 – p.42/44
Tracing Aspect
package tracing;
public aspect TraceAllCalls {
pointcut pointsToTrace() :
call(* *.*(..)) && !within(TraceAllCalls);
before() : pointsToTrace() {
System.err.println("Enter " + thisJoinPoint);
}
after() : pointsToTrace() {
System.err.println("Exit " + thisJoinPoint);
}
}
AOP Course 2003 – p.43/44
Conclusion
You should now know about. . .
• AspectJ’s main kinds of primitive pointcuts
• named pointcuts
• pointcuts with parameters
• different kinds of advice
• thisJoinPoint
• syntax for aspects
Tomorrow, you will learn about inter-type declarations
and other advanced stuff.
AOP Course 2003 – p.44/44
Download