This lesson explains the parts of AspectJ's aspects. By reading this lesson you will have an overview of what's in an aspect and you will be exposed to the new terminology introduced by AspectJ.
Here's an example of an aspect definition in AspectJ:
1 aspect FaultHandler { 2 3 private boolean Server.disabled = false; 4 5 private void reportFault() { 6 System.out.println("Failure! Please fix it."); 7 } 8 9 public static void fixServer(Server s) { 10 s.disabled = false; 11 } 12 13 pointcut services(Server s): target(s) && call(public * *(..)); 14 15 before(Server s): services(s) { 16 if (s.disabled) throw new DisabledException(); 17 } 18 19 after(Server s) throwing (FaultException e): services(s) { 20 s.disabled = true; 21 reportFault(); 22 } 23 }
The FaultHandler
consists of one inter-type
field on Server
(line 03), two methods (lines
05-07 and 09-11), one pointcut definition (line 13), and two pieces
of advice (lines 15-17 and 19-22).
This covers the basics of what aspects can contain. In general, aspects consist of an association of other program entities, ordinary variables and methods, pointcut definitions, inter-type declarations, and advice, where advice may be before, after or around advice. The remainder of this lesson focuses on those crosscut-related constructs.
AspectJ's pointcut definitions give names to pointcuts. Pointcuts themselves pick out join points, i.e. interesting points in the execution of a program. These join points can be method or constructor invocations and executions, the handling of exceptions, field assignments and accesses, etc. Take, for example, the pointcut definition in line 13:
pointcut services(Server s): target(s) && call(public * *(..))
This pointcut, named services
, picks out those
points in the execution of the program when
Server
objects have their public methods called.
It also allows anyone using the services
pointcut to access the Server
object whose
method is being called.
The idea behind this pointcut in the
FaultHandler
aspect is that
fault-handling-related behavior must be triggered on the calls to
public methods. For example, the server may be unable to proceed
with the request because of some fault. The calls of those methods
are, therefore, interesting events for this aspect, in the sense
that certain fault-related things will happen when these events
occur.
Part of the context in which the events occur is exposed by the
formal parameters of the pointcut. In this case, that consists of
objects of type Server
. That formal parameter
is then being used on the right hand side of the declaration in
order to identify which events the pointcut refers to. In this
case, a pointcut picking out join points where a Server is the
target of some operation (target(s)) is being composed
(&&
, meaning and) with a pointcut
picking out call join points (call(...)). The calls are identified
by signatures that can include wild cards. In this case, there are
wild cards in the return type position (first *), in the name
position (second *) and in the argument list position (..); the
only concrete information is given by the qualifier
public
.
Pointcuts pick out arbitrarily large numbers of join points of a program. But they pick out only a small number of kinds of join points. Those kinds of join points correspond to some of the most important concepts in Java. Here is an incomplete list: method call, method execution, exception handling, instantiation, constructor execution, and field access. Each kind of join point can be picked out by its own specialized pointcut that you will learn about in other parts of this guide.
A piece of advice brings together a pointcut and a body of code to define aspect implementation that runs at join points picked out by the pointcut. For example, the advice in lines 15-17 specifies that the following piece of code
{ if (s.disabled) throw new DisabledException(); }
is executed when instances of the Server
class
have their public methods called, as specified by the pointcut
services
. More specifically, it runs when those
calls are made, just before the corresponding methods are executed.
The advice in lines 19-22 defines another piece of implementation that is executed on the same pointcut:
{ s.disabled = true; reportFault(); }
But this second method executes after those operations throw
exception of type FaultException
.
There are two other variations of after advice: upon successful return and upon return, either successful or with an exception. There is also a third kind of advice called around. You will see those in other parts of this guide.