diff options
author | Alexander Kriegisch <Alexander@Kriegisch.name> | 2021-06-29 13:18:25 +0700 |
---|---|---|
committer | Alexander Kriegisch <Alexander@Kriegisch.name> | 2024-01-06 10:09:11 +0100 |
commit | ebbc41255384e85db03c4eb6aae4e6464803d0a9 (patch) | |
tree | 4d90f6d206ec43bef21eb601161785c4502d358e /docs/progGuideDB/gettingstarted.adoc | |
parent | 0ba9f25b0e5deb638f6e7472141f4edc4450c99b (diff) | |
download | aspectj-ebbc41255384e85db03c4eb6aae4e6464803d0a9.tar.gz aspectj-ebbc41255384e85db03c4eb6aae4e6464803d0a9.zip |
Add initial set of AsciiDoc files, converted from HTML/XML
Some originals have been deleted already. Others, especially the user
guides, still exist in both formats because they have not been
proof-read and probably lots of links do not function as expected. But I
want to see what the files look like directly on GitHun.
Signed-off-by: Alexander Kriegisch <Alexander@Kriegisch.name>
Diffstat (limited to 'docs/progGuideDB/gettingstarted.adoc')
-rw-r--r-- | docs/progGuideDB/gettingstarted.adoc | 952 |
1 files changed, 952 insertions, 0 deletions
diff --git a/docs/progGuideDB/gettingstarted.adoc b/docs/progGuideDB/gettingstarted.adoc new file mode 100644 index 000000000..0930d2e44 --- /dev/null +++ b/docs/progGuideDB/gettingstarted.adoc @@ -0,0 +1,952 @@ +[[starting]] +== Getting Started with AspectJ + +[[starting-intro]] +=== Introduction + +Many software developers are attracted to the idea of aspect-oriented +programming (AOP) but unsure about how to begin using the technology. +They recognize the concept of crosscutting concerns, and know that they +have had problems with the implementation of such concerns in the past. +But there are many questions about how to adopt AOP into the development +process. Common questions include: + +* Can I use aspects in my existing code? +* What kinds of benefits can I expect to get from using aspects? +* How do I find aspects in my programs? +* How steep is the learning curve for AOP? +* What are the risks of using this new technology? + +This chapter addresses these questions in the context of AspectJ: a +general-purpose aspect-oriented extension to Java. A series of abridged +examples illustrate the kinds of aspects programmers may want to +implement using AspectJ and the benefits associated with doing so. +Readers who would like to understand the examples in more detail, or who +want to learn how to program examples like these, can find more complete +examples and supporting material linked from the https://www.eclipse.org/aspectj/:[AspectJ web site]. + +A significant risk in adopting any new technology is going too far too +fast. Concern about this risk causes many organizations to be +conservative about adopting new technology. To address this issue, the +examples in this chapter are grouped into three broad categories, with +aspects that are easier to adopt into existing development projects +coming earlier in this chapter. The next section, +xref:#starting-aspectj[Introduction to AspectJ], we present the core of +AspectJ's features, and in xref:#starting-development[Development +Aspects], we present aspects that facilitate tasks such as debugging, +testing and performance tuning of applications. And, in the section +following, xref:#starting-production[Production Aspects], we present +aspects that implement crosscutting functionality common in Java +applications. We will defer discussing a third category of aspects, +reusable aspects, until xref:#language[???]. + +These categories are informal, and this ordering is not the only way to +adopt AspectJ. Some developers may want to use a production aspect right +away. But our experience with current AspectJ users suggests that this +is one ordering that allows developers to get experience with (and +benefit from) AOP technology quickly, while also minimizing risk. + +[[starting-aspectj]] +=== Introduction to AspectJ + +This section presents a brief introduction to the features of AspectJ +used later in this chapter. These features are at the core of the +language, but this is by no means a complete overview of AspectJ. + +The features are presented using a simple figure editor system. A +`Figure` consists of a number of `FigureElements`, which can be either +`Point`s or `Line`s. The `Figure` class provides factory services. There +is also a `Display`. Most example programs later in this chapter are +based on this system as well. + +image:figureUML.gif[ UML for the `FigureEditor` example ] + +The motivation for AspectJ (and likewise for aspect-oriented +programming) is the realization that there are issues or concerns that +are not well captured by traditional programming methodologies. Consider +the problem of enforcing a security policy in some application. By its +nature, security cuts across many of the natural units of modularity of +the application. Moreover, the security policy must be uniformly applied +to any additions as the application evolves. And the security policy +that is being applied might itself evolve. Capturing concerns like a +security policy in a disciplined way is difficult and error-prone in a +traditional programming language. + +Concerns like security cut across the natural units of modularity. For +object-oriented programming languages, the natural unit of modularity is +the class. But in object-oriented programming languages, crosscutting +concerns are not easily turned into classes precisely because they cut +across classes, and so these aren't reusable, they can't be refined or +inherited, they are spread through out the program in an undisciplined +way, in short, they are difficult to work with. + +Aspect-oriented programming is a way of modularizing crosscutting +concerns much like object-oriented programming is a way of modularizing +common concerns. AspectJ is an implementation of aspect-oriented +programming for Java. + +AspectJ adds to Java just one new concept, a join point -- and that's +really just a name for an existing Java concept. It adds to Java only a +few new constructs: pointcuts, advice, inter-type declarations and +aspects. Pointcuts and advice dynamically affect program flow, +inter-type declarations statically affects a program's class hierarchy, +and aspects encapsulate these new constructs. + +A _join point_ is a well-defined point in the program flow. A _pointcut_ +picks out certain join points and values at those points. A piece of +_advice_ is code that is executed when a join point is reached. These +are the dynamic parts of AspectJ. + +AspectJ also has different kinds of _inter-type declarations_ that allow +the programmer to modify a program's static structure, namely, the +members of its classes and the relationship between classes. + +AspectJ's _aspect_ are the unit of modularity for crosscutting concerns. +They behave somewhat like Java classes, but may also include pointcuts, +advice and inter-type declarations. + +In the sections immediately following, we are first going to look at +join points and how they compose into pointcuts. Then we will look at +advice, the code which is run when a pointcut is reached. We will see +how to combine pointcuts and advice into aspects, AspectJ's reusable, +inheritable unit of modularity. Lastly, we will look at how to use +inter-type declarations to deal with crosscutting concerns of a +program's class structure. + +==== The Dynamic Join Point Model + +A critical element in the design of any aspect-oriented language is the +join point model. The join point model provides the common frame of +reference that makes it possible to define the dynamic structure of +crosscutting concerns. This chapter describes AspectJ's dynamic join +points, in which join points are certain well-defined points in the +execution of the program. + +AspectJ provides for many kinds of join points, but this chapter +discusses only one of them: method call join points. A method call join +point encompasses the actions of an object receiving a method call. It +includes all the actions that comprise a method call, starting after all +arguments are evaluated up to and including return (either normally or +by throwing an exception). + +Each method call at runtime is a different join point, even if it comes +from the same call expression in the program. Many other join points may +run while a method call join point is executing -- all the join points +that happen while executing the method body, and in those methods called +from the body. We say that these join points execute in the _dynamic +context_ of the original call join point. + +[[pointcuts-starting]] +==== Pointcuts + +In AspectJ, _pointcuts_ pick out certain join points in the program +flow. For example, the pointcut + +.... +call(void Point.setX(int)) +.... + +picks out each join point that is a call to a method that has the +signature `void Point.setX(int)` - that is, `Point`'s void `setX` method +with a single `int` parameter. + +A pointcut can be built out of other pointcuts with and, or, and not +(spelled `&&`, `||`, and `!`). For example: + +.... +call(void Point.setX(int)) || +call(void Point.setY(int)) +.... + +picks out each join point that is either a call to `setX` or a call to +`setY`. + +Pointcuts can identify join points from many different types - in other +words, they can crosscut types. For example, + +.... +call(void FigureElement.setXY(int,int)) || +call(void Point.setX(int)) || +call(void Point.setY(int)) || +call(void Line.setP1(Point)) || +call(void Line.setP2(Point)); +.... + +picks out each join point that is a call to one of five methods (the +first of which is an interface method, by the way). + +In our example system, this pointcut captures all the join points when a +`FigureElement` moves. While this is a useful way to specify this +crosscutting concern, it is a bit of a mouthful. So AspectJ allows +programmers to define their own named pointcuts with the `pointcut` +form. So the following declares a new, named pointcut: + +.... +pointcut move(): + call(void FigureElement.setXY(int,int)) || + call(void Point.setX(int)) || + call(void Point.setY(int)) || + call(void Line.setP1(Point)) || + call(void Line.setP2(Point)); +.... + +and whenever this definition is visible, the programmer can simply use +`move()` to capture this complicated pointcut. + +The previous pointcuts are all based on explicit enumeration of a set of +method signatures. We sometimes call this _name-based_ crosscutting. +AspectJ also provides mechanisms that enable specifying a pointcut in +terms of properties of methods other than their exact name. We call this +_property-based_ crosscutting. The simplest of these involve using +wildcards in certain fields of the method signature. For example, the +pointcut + +.... +call(void Figure.make*(..)) +.... + +picks out each join point that's a call to a void method defined on +`Figure` whose the name begins with "`make`" regardless of the method's +parameters. In our system, this picks out calls to the factory methods +`makePoint` and `makeLine`. The pointcut + +.... +call(public * Figure.* (..)) +.... + +picks out each call to `Figure`'s public methods. + +But wildcards aren't the only properties AspectJ supports. Another +pointcut, `cflow`, identifies join points based on whether they occur in +the dynamic context of other join points. So + +.... +cflow(move()) +.... + +picks out each join point that occurs in the dynamic context of the join +points picked out by `move()`, our named pointcut defined above. So this +picks out each join points that occurrs between when a move method is +called and when it returns (either normally or by throwing an +exception). + +[[advice-starting]] +==== Advice + +So pointcuts pick out join points. But they don't _do_ anything apart +from picking out join points. To actually implement crosscutting +behavior, we use advice. Advice brings together a pointcut (to pick out +join points) and a body of code (to run at each of those join points). + +AspectJ has several different kinds of advice. _Before advice_ runs as a +join point is reached, before the program proceeds with the join point. +For example, before advice on a method call join point runs before the +actual method starts running, just after the arguments to the method +call are evaluated. + +.... +before(): move() { + System.out.println("about to move"); +} +.... + +_After advice_ on a particular join point runs after the program +proceeds with that join point. For example, after advice on a method +call join point runs after the method body has run, just before before +control is returned to the caller. Because Java programs can leave a +join point 'normally' or by throwing an exception, there are three kinds +of after advice: `after returning`, `after + throwing`, and plain `after` (which runs after returning _or_ +throwing, like Java's `finally`). + +.... +after() returning: move() { + System.out.println("just successfully moved"); +} +.... + +_Around advice_ on a join point runs as the join point is reached, and +has explicit control over whether the program proceeds with the join +point. Around advice is not discussed in this section. + +===== Exposing Context in Pointcuts + +Pointcuts not only pick out join points, they can also expose part of +the execution context at their join points. Values exposed by a pointcut +can be used in the body of advice declarations. + +An advice declaration has a parameter list (like a method) that gives +names to all the pieces of context that it uses. For example, the after +advice + +.... +after(FigureElement fe, int x, int y) returning: + ...SomePointcut... { + ...SomeBody... +} +.... + +uses three pieces of exposed context, a `FigureElement` named fe, and +two `int`s named x and y. + +The body of the advice uses the names just like method parameters, so + +.... +after(FigureElement fe, int x, int y) returning: + ...SomePointcut... { + System.out.println(fe + " moved to (" + x + ", " + y + ")"); +} +.... + +The advice's pointcut publishes the values for the advice's arguments. +The three primitive pointcuts `this`, `target` and `args` are used to +publish these values. So now we can write the complete piece of advice: + +.... +after(FigureElement fe, int x, int y) returning: + call(void FigureElement.setXY(int, int)) + && target(fe) + && args(x, y) { + System.out.println(fe + " moved to (" + x + ", " + y + ")"); +} +.... + +The pointcut exposes three values from calls to `setXY`: the target +`FigureElement` -- which it publishes as `fe`, so it becomes the first +argument to the after advice -- and the two int arguments -- which it +publishes as `x` and `y`, so they become the second and third argument +to the after advice. + +So the advice prints the figure element that was moved and its new `x` +and `y` coordinates after each `setXY` method call. + +A named pointcut may have parameters like a piece of advice. When the +named pointcut is used (by advice, or in another named pointcut), it +publishes its context by name just like the `this`, `target` and `args` +pointcut. So another way to write the above advice is + +.... +pointcut setXY(FigureElement fe, int x, int y): + call(void FigureElement.setXY(int, int)) + && target(fe) + && args(x, y); + +after(FigureElement fe, int x, int y) returning: setXY(fe, x, y) { + System.out.println(fe + " moved to (" + x + ", " + y + ")."); +} +.... + +==== Inter-type declarations + +Inter-type declarations in AspectJ are declarations that cut across +classes and their hierarchies. They may declare members that cut across +multiple classes, or change the inheritance relationship between +classes. Unlike advice, which operates primarily dynamically, +introduction operates statically, at compile-time. + +Consider the problem of expressing a capability shared by some existing +classes that are already part of a class hierarchy, i.e. they already +extend a class. In Java, one creates an interface that captures this new +capability, and then adds to _each affected class_ a method that +implements this interface. + +AspectJ can express the concern in one place, by using inter-type +declarations. The aspect declares the methods and fields that are +necessary to implement the new capability, and associates the methods +and fields to the existing classes. + +Suppose we want to have `Screen` objects observe changes to `Point` +objects, where `Point` is an existing class. We can implement this by +writing an aspect declaring that the class Point `Point` has an instance +field, `observers`, that keeps track of the `Screen` objects that are +observing `Point`s. + +.... +aspect PointObserving { + private Vector Point.observers = new Vector(); + ... +} +.... + +The `observers` field is private, so only `PointObserving` can see it. +So observers are added or removed with the static methods `addObserver` +and `removeObserver` on the aspect. + +.... +aspect PointObserving { + private Vector Point.observers = new Vector(); + + public static void addObserver(Point p, Screen s) { + p.observers.add(s); + } + public static void removeObserver(Point p, Screen s) { + p.observers.remove(s); + } + ... +} +.... + +Along with this, we can define a pointcut `changes` that defines what we +want to observe, and the after advice defines what we want to do when we +observe a change. + +.... +aspect PointObserving { + private Vector Point.observers = new Vector(); + + public static void addObserver(Point p, Screen s) { + p.observers.add(s); + } + public static void removeObserver(Point p, Screen s) { + p.observers.remove(s); + } + + pointcut changes(Point p): target(p) && call(void Point.set*(int)); + + after(Point p): changes(p) { + Iterator iter = p.observers.iterator(); + while ( iter.hasNext() ) { + updateObserver(p, (Screen)iter.next()); + } + } + + static void updateObserver(Point p, Screen s) { + s.display(p); + } +} +.... + +Note that neither `Screen`'s nor `Point`'s code has to be modified, and +that all the changes needed to support this new capability are local to +this aspect. + +==== Aspects + +Aspects wrap up pointcuts, advice, and inter-type declarations in a a +modular unit of crosscutting implementation. It is defined very much +like a class, and can have methods, fields, and initializers in addition +to the crosscutting members. Because only aspects may include these +crosscutting members, the declaration of these effects is localized. + +Like classes, aspects may be instantiated, but AspectJ controls how that +instantiation happens -- so you can't use Java's `new` form to build new +aspect instances. By default, each aspect is a singleton, so one aspect +instance is created. This means that advice may use non-static fields of +the aspect, if it needs to keep state around: + +.... +aspect Logging { + OutputStream logStream = System.err; + + before(): move() { + logStream.println("about to move"); + } +} +.... + +Aspects may also have more complicated rules for instantiation, but +these will be described in a later chapter. + +[[starting-development]] +=== Development Aspects + +The next two sections present the use of aspects in increasingly +sophisticated ways. Development aspects are easily removed from +production builds. Production aspects are intended to be used in both +development and in production, but tend to affect only a few classes. + +This section presents examples of aspects that can be used during +development of Java applications. These aspects facilitate debugging, +testing and performance tuning work. The aspects define behavior that +ranges from simple tracing, to profiling, to testing of internal +consistency within the application. Using AspectJ makes it possible to +cleanly modularize this kind of functionality, thereby making it +possible to easily enable and disable the functionality when desired. + +==== Tracing + +This first example shows how to increase the visibility of the internal +workings of a program. It is a simple tracing aspect that prints a +message at specified method calls. In our figure editor example, one +such aspect might simply trace whenever points are drawn. + +.... +aspect SimpleTracing { + pointcut tracedCall(): + call(void FigureElement.draw(GraphicsContext)); + + before(): tracedCall() { + System.out.println("Entering: " + thisJoinPoint); + } +} +.... + +This code makes use of the `thisJoinPoint` special variable. Within all +advice bodies this variable is bound to an object that describes the +current join point. The effect of this code is to print a line like the +following every time a figure element receives a `draw` method call: + +.... +Entering: call(void FigureElement.draw(GraphicsContext)) +.... + +To understand the benefit of coding this with AspectJ consider changing +the set of method calls that are traced. With AspectJ, this just +requires editing the definition of the `tracedCalls` pointcut and +recompiling. The individual methods that are traced do not need to be +edited. + +When debugging, programmers often invest considerable effort in figuring +out a good set of trace points to use when looking for a particular kind +of problem. When debugging is complete or appears to be complete it is +frustrating to have to lose that investment by deleting trace statements +from the code. The alternative of just commenting them out makes the +code look bad, and can cause trace statements for one kind of debugging +to get confused with trace statements for another kind of debugging. + +With AspectJ it is easy to both preserve the work of designing a good +set of trace points and disable the tracing when it isn t being used. +This is done by writing an aspect specifically for that tracing mode, +and removing that aspect from the compilation when it is not needed. + +This ability to concisely implement and reuse debugging configurations +that have proven useful in the past is a direct result of AspectJ +modularizing a crosscutting design element the set of methods that are +appropriate to trace when looking for a given kind of information. + +==== Profiling and Logging + +Our second example shows you how to do some very specific profiling. +Although many sophisticated profiling tools are available, and these can +gather a variety of information and display the results in useful ways, +you may sometimes want to profile or log some very specific behavior. In +these cases, it is often possible to write a simple aspect similar to +the ones above to do the job. + +For example, the following aspect counts the number of calls to the +`rotate` method on a `Line` and the number of calls to the `set*` +methods of a `Point` that happen within the control flow of those calls +to `rotate`: + +.... +aspect SetsInRotateCounting { + int rotateCount = 0; + int setCount = 0; + + before(): call(void Line.rotate(double)) { + rotateCount++; + } + + before(): call(void Point.set*(int)) + && cflow(call(void Line.rotate(double))) { + setCount++; + } +} +.... + +In effect, this aspect allows the programmer to ask very specific +questions like + +____ +How many times is the + +rotate + +method defined on + +Line + +objects called? +____ + +and + +____ +How many times are methods defined on + +Point + +objects whose name begins with " + +set + +" called in fulfilling those rotate calls? +____ + +questions it may be difficult to express using standard profiling or +logging tools. + +[[pre-and-post-conditions]] +==== Pre- and Post-Conditions + +Many programmers use the "Design by Contract" style popularized by +Bertand Meyer in Object-Oriented Software Construction, 2/e. In this +style of programming, explicit pre-conditions test that callers of a +method call it properly and explicit post-conditions test that methods +properly do the work they are supposed to. + +AspectJ makes it possible to implement pre- and post-condition testing +in modular form. For example, this code + +.... +aspect PointBoundsChecking { + + pointcut setX(int x): + (call(void FigureElement.setXY(int, int)) && args(x, *)) + || (call(void Point.setX(int)) && args(x)); + + pointcut setY(int y): + (call(void FigureElement.setXY(int, int)) && args(*, y)) + || (call(void Point.setY(int)) && args(y)); + + before(int x): setX(x) { + if ( x < MIN_X || x > MAX_X ) + throw new IllegalArgumentException("x is out of bounds."); + } + + before(int y): setY(y) { + if ( y < MIN_Y || y > MAX_Y ) + throw new IllegalArgumentException("y is out of bounds."); + } +} +.... + +implements the bounds checking aspect of pre-condition testing for +operations that move points. Notice that the `setX` pointcut refers to +all the operations that can set a Point's `x` coordinate; this includes +the `setX` method, as well as half of the `setXY` method. In this sense +the `setX` pointcut can be seen as involving very fine-grained +crosscutting - it names the the `setX` method and half of the `setXY` +method. + +Even though pre- and post-condition testing aspects can often be used +only during testing, in some cases developers may wish to include them +in the production build as well. Again, because AspectJ makes it +possible to modularize these crosscutting concerns cleanly, it gives +developers good control over this decision. + +==== Contract Enforcement + +The property-based crosscutting mechanisms can be very useful in +defining more sophisticated contract enforcement. One very powerful use +of these mechanisms is to identify method calls that, in a correct +program, should not exist. For example, the following aspect enforces +the constraint that only the well-known factory methods can add an +element to the registry of figure elements. Enforcing this constraint +ensures that no figure element is added to the registry more than once. + +.... +aspect RegistrationProtection { + + pointcut register(): call(void Registry.register(FigureElement)); + + pointcut canRegister(): withincode(static * FigureElement.make*(..)); + + before(): register() && !canRegister() { + throw new IllegalAccessException("Illegal call " + thisJoinPoint); + } +} +.... + +This aspect uses the withincode primitive pointcut to denote all join +points that occur within the body of the factory methods on +`FigureElement` (the methods with names that begin with "`make`"). This +is a property-based pointcut because it identifies join points based not +on their signature, but rather on the property that they occur +specifically within the code of another method. The before advice +declaration effectively says signal an error for any calls to register +that are not within the factory methods. + +This advice throws a runtime exception at certain join points, but +AspectJ can do better. Using the `declare error` form, we can have the +_compiler_ signal the error. + +.... +aspect RegistrationProtection { + + pointcut register(): call(void Registry.register(FigureElement)); + pointcut canRegister(): withincode(static * FigureElement.make*(..)); + + declare error: register() && !canRegister(): "Illegal call" +} +.... + +When using this aspect, it is impossible for the compiler to compile +programs with these illegal calls. This early detection is not always +possible. In this case, since we depend only on static information (the +`withincode` pointcut picks out join points totally based on their code, +and the `call` pointcut here picks out join points statically). Other +enforcement, such as the precondition enforcement, above, does require +dynamic information such as the runtime value of parameters. + +==== Configuration Management + +Configuration management for aspects can be handled using a variety of +make-file like techniques. To work with optional aspects, the programmer +can simply define their make files to either include the aspect in the +call to the AspectJ compiler or not, as desired. + +Developers who want to be certain that no aspects are included in the +production build can do so by configuring their make files so that they +use a traditional Java compiler for production builds. To make it easy +to write such make files, the AspectJ compiler has a command-line +interface that is consistent with ordinary Java compilers. + +[[starting-production]] +=== Production Aspects + +This section presents examples of aspects that are inherently intended +to be included in the production builds of an application. Production +aspects tend to add functionality to an application rather than merely +adding more visibility of the internals of a program. Again, we begin +with name-based aspects and follow with property-based aspects. +Name-based production aspects tend to affect only a small number of +methods. For this reason, they are a good next step for projects +adopting AspectJ. But even though they tend to be small and simple, they +can often have a significant effect in terms of making the program +easier to understand and maintain. + +==== Change Monitoring + +The first example production aspect shows how one might implement some +simple functionality where it is problematic to try and do it +explicitly. It supports the code that refreshes the display. The role of +the aspect is to maintain a dirty bit indicating whether or not an +object has moved since the last time the display was refreshed. + +Implementing this functionality as an aspect is straightforward. The +`testAndClear` method is called by the display code to find out whether +a figure element has moved recently. This method returns the current +state of the dirty flag and resets it to false. The pointcut `move` +captures all the method calls that can move a figure element. The after +advice on `move` sets the dirty flag whenever an object moves. + +.... +aspect MoveTracking { + private static boolean dirty = false; + + public static boolean testAndClear() { + boolean result = dirty; + dirty = false; + return result; + } + + pointcut move(): + call(void FigureElement.setXY(int, int)) || + call(void Line.setP1(Point)) || + call(void Line.setP2(Point)) || + call(void Point.setX(int)) || + call(void Point.setY(int)); + + after() returning: move() { + dirty = true; + } +} +.... + +Even this simple example serves to illustrate some of the important +benefits of using AspectJ in production code. Consider implementing this +functionality with ordinary Java: there would likely be a helper class +that contained the `dirty` flag, the `testAndClear` method, as well as a +`setFlag` method. Each of the methods that could move a figure element +would include a call to the `setFlag` method. Those calls, or rather the +concept that those calls should happen at each move operation, are the +crosscutting concern in this case. + +The AspectJ implementation has several advantages over the standard +implementation: + +_The structure of the crosscutting concern is captured explicitly._ The +moves pointcut clearly states all the methods involved, so the +programmer reading the code sees not just individual calls to `setFlag`, +but instead sees the real structure of the code. The IDE support +included with AspectJ automatically reminds the programmer that this +aspect advises each of the methods involved. The IDE support also +provides commands to jump to the advice from the method and vice-versa. + +_Evolution is easier._ If, for example, the aspect needs to be revised +to record not just that some figure element moved, but rather to record +exactly which figure elements moved, the change would be entirely local +to the aspect. The pointcut would be updated to expose the object being +moved, and the advice would be updated to record that object. The paper +An Overview of AspectJ (available linked off of the AspectJ web site -- +http://eclipse.org/aspectj[]), presented at ECOOP 2001, presents a +detailed discussion of various ways this aspect could be expected to +evolve. + +_The functionality is easy to plug in and out._ Just as with development +aspects, production aspects may need to be removed from the system, +either because the functionality is no longer needed at all, or because +it is not needed in certain configurations of a system. Because the +functionality is modularized in a single aspect this is easy to do. + +_The implementation is more stable._ If, for example, the programmer +adds a subclass of `Line` that overrides the existing methods, this +advice in this aspect will still apply. In the ordinary Java +implementation the programmer would have to remember to add the call to +`setFlag` in the new overriding method. This benefit is often even more +compelling for property-based aspects (see the section +xref:#starting-production-consistentBehavior[Providing Consistent +Behavior]). + +==== Context Passing + +The crosscutting structure of context passing can be a significant +source of complexity in Java programs. Consider implementing +functionality that would allow a client of the figure editor (a program +client rather than a human) to set the color of any figure elements that +are created. Typically this requires passing a color, or a color +factory, from the client, down through the calls that lead to the figure +element factory. All programmers are familiar with the inconvenience of +adding a first argument to a number of methods just to pass this kind of +context information. + +Using AspectJ, this kind of context passing can be implemented in a +modular way. The following code adds after advice that runs only when +the factory methods of `Figure` are called in the control flow of a +method on a `ColorControllingClient`. + +.... +aspect ColorControl { + pointcut CCClientCflow(ColorControllingClient client): + cflow(call(* * (..)) && target(client)); + + pointcut make(): call(FigureElement Figure.make*(..)); + + after (ColorControllingClient c) returning (FigureElement fe): + make() && CCClientCflow(c) { + fe.setColor(c.colorFor(fe)); + } +} +.... + +This aspect affects only a small number of methods, but note that the +non-AOP implementation of this functionality might require editing many +more methods, specifically, all the methods in the control flow from the +client to the factory. This is a benefit common to many property-based +aspects while the aspect is short and affects only a modest number of +benefits, the complexity the aspect saves is potentially much larger. + +[[starting-production-consistentBehavior]] +==== Providing Consistent Behavior + +This example shows how a property-based aspect can be used to provide +consistent handling of functionality across a large set of operations. +This aspect ensures that all public methods of the `com.bigboxco` +package log any Errors they throw to their caller (in Java, an Error is +like an Exception, but it indicates that something really bad and +usually unrecoverable has happened). The `publicMethodCall` pointcut +captures the public method calls of the package, and the after advice +runs whenever one of those calls throws an Error. The advice logs that +Error and then the throw resumes. + +.... +aspect PublicErrorLogging { + Log log = new Log(); + + pointcut publicMethodCall(): + call(public * com.bigboxco.*.*(..)); + + after() throwing (Error e): publicMethodCall() { + log.write(e); + } +} +.... + +In some cases this aspect can log an exception twice. This happens if +code inside the `com.bigboxco` package itself calls a public method of +the package. In that case this code will log the error at both the +outermost call into the `com.bigboxco` package and the re-entrant call. +The `cflow` primitive pointcut can be used in a nice way to exclude +these re-entrant calls: + +.... +after() throwing (Error e): + publicMethodCall() && !cflow(publicMethodCall()) { + log.write(e); +} +.... + +The following aspect is taken from work on the AspectJ compiler. The +aspect advises about 35 methods in the `JavaParser` class. The +individual methods handle each of the different kinds of elements that +must be parsed. They have names like `parseMethodDec`, `parseThrows`, +and `parseExpr`. + +.... +aspect ContextFilling { + pointcut parse(JavaParser jp): + call(* JavaParser.parse*(..)) + && target(jp) + && !call(Stmt parseVarDec(boolean)); // var decs + // are tricky + + around(JavaParser jp) returns ASTObject: parse(jp) { + Token beginToken = jp.peekToken(); + ASTObject ret = proceed(jp); + if (ret != null) jp.addContext(ret, beginToken); + return ret; + } +} +.... + +This example exhibits a property found in many aspects with large +property-based pointcuts. In addition to a general property based +pattern `call(* JavaParser.parse*(..))` it includes an exception to the +pattern `!call(Stmt + parseVarDec(boolean))`. The exclusion of `parseVarDec` happens +because the parsing of variable declarations in Java is too complex to +fit with the clean pattern of the other `parse*` methods. Even with the +explicit exclusion this aspect is a clear expression of a clean +crosscutting modularity. Namely that all `parse*` methods that return +`ASTObjects`, except for `parseVarDec` share a common behavior for +establishing the parse context of their result. + +The process of writing an aspect with a large property-based pointcut, +and of developing the appropriate exceptions can clarify the structure +of the system. This is especially true, as in this case, when +refactoring existing code to use aspects. When we first looked at the +code for this aspect, we were able to use the IDE support provided in +AJDE for JBuilder to see what methods the aspect was advising compared +to our manual coding. We quickly discovered that there were a dozen +places where the aspect advice was in effect but we had not manually +inserted the required functionality. Two of these were bugs in our prior +non-AOP implementation of the parser. The other ten were needless +performance optimizations. So, here, refactoring the code to express the +crosscutting structure of the aspect explicitly made the code more +concise and eliminated latent bugs. + +[[starting-conclusion]] +=== Conclusion + +AspectJ is a simple and practical aspect-oriented extension to Java. +With just a few new constructs, AspectJ provides support for modular +implementation of a range of crosscutting concerns. + +Adoption of AspectJ into an existing Java development project can be a +straightforward and incremental task. One path is to begin by using only +development aspects, going on to using production aspects and then +reusable aspects after building up experience with AspectJ. Adoption can +follow other paths as well. For example, some developers will benefit +from using production aspects right away. Others may be able to write +clean reusable aspects almost right away. + +AspectJ enables both name-based and property based crosscutting. Aspects +that use name-based crosscutting tend to affect a small number of other +classes. But despite their small scale, they can often eliminate +significant complexity compared to an ordinary Java implementation. +Aspects that use property-based crosscutting can have small or large +scale. + +Using AspectJ results in clean well-modularized implementations of +crosscutting concerns. When written as an AspectJ aspect the structure +of a crosscutting concern is explicit and easy to understand. Aspects +are also highly modular, making it possible to develop plug-and-play +implementations of crosscutting functionality. + +AspectJ provides more functionality than was covered by this short +introduction. The next chapter, xref:#language[???], covers in detail +more of the features of the AspectJ language. The following chapter, +xref:#examples[???], then presents some carefully chosen examples that +show you how AspectJ might be used. We recommend that you read the next +two chapters carefully before deciding to adopt AspectJ into a project. |