.
Older programming methodologies—including Procedural Programming and Object-oriented Programming —similarly focus on separation and encapsulation of ''concerns'' (or any area of interest of focus) into single entities. For example, procedures, packages, classes, and methods all help programmers encapsulate concerns into single entities. But although these methodologies can successfully encapsulate many software concerns, some concerns defy such easy encapsulation. Software engineers call these ''crosscutting concerns'', because they exist in many parts of the program.
Logging offers the prototypical example of a crosscutting concern, because a logging strategy necessarily affects every single logged part of the system. Logging thereby ''crosscuts'' all logged classes, methods, and procedures.
Typically, an implementation of an AOP language seeks to encapsulate these types of crosscutting concerns through the introduction of a new construct called an Aspect . An aspect can alter the behavior of the Base Code (the non-aspect part of a program) by applying Advice (additional behavior) over a quantification of Join Point s (points in the structure or execution of a program), called a Pointcut (a logical description of a set of join points).
In many AOP languages, method executions and field references all exemplify join points. A pointcut may consist, for example, of all references to a particular set of fields.
Aspect-Oriented Programming has at its core the enabling of a better separation of concerns, by allowing the programmer to create ''cross-cutting concerns'' as first-class program modules. (Cross-cutting concerns are defined as those parts, or aspects, of the program that in standard design mechanisms end up ''scattered'' across multiple program modules, and ''tangled'' with other modules.)
For example, consider a banking application with a conceptually very simple method for transferring an amount from one account to another:
void transfer(Account fromAccount, Account toAccount, int amount) {
if (fromAccount.getBalance() < amount) {
throw new InsufficientFundsException();
}
fromAccount.withdraw(amount);
toAccount.deposit(amount);
}
(the examples appear in a Java -like syntax, since at the time of writing, an overwhelming majority of AOP-related research and work takes place in Java or in Java-variants.)
However, in a real-world banking application, this transfer method seems far from adequate. We must include security checks to verify that the current user has the authorization to perform this operation. We must enclose the operation in a Database Transaction in order to prevent accidental data loss. We must log the operation to the system log. And so on. A very simplified version with all those new concerns would look somewhat like this:
void transfer(Account fromAccount, Account toAccount, int amount) {
if (!getCurrentUser().canPerform(OP_TRANSFER)) {
throw new SecurityException();
}
if (amount < 0) {
throw new NegativeTransferException();
}
if (fromAccount.getBalance() < amount) {
throw new InsufficientFundsException();
}
Transaction tx = database.newTransaction();
try {
fromAccount.withdraw(amount);
toAcount.deposit(amount);
tx.commit();
systemLog.logOperation(OP_TRANSFER, fromAccount, toAccount, amount);
}
catch(Exception e) {
tx.rollback();
}
}
The code has lost its elegance and simplicity because the various new concerns have become ''tangled'' with the basic functionality (sometimes called the ''business logic concern''). The transactions, security, logging, etc. all exemplify ''cross-cutting concerns''.
Also consider what happens if we suddenly need to change (for example) the security considerations for the application. In the program's current version, security-related operations appear ''scattered'' across numerous methods, and such a change would require a major effort.
Therefore, we find that unlike the core concerns of the system, the cross-cutting concerns do not get properly encapsulated in their own modules. This increases the system complexity and makes maintenance considerably more difficult.
AOP attempts to solve this problem by allowing the programmer to develop cross-cutting concerns as full stand-alone modules called ''aspects''. In most AOP languages, an aspect comprises one or more pieces of ''advice'' (code snippets - like methods) and a list of ''join points'' (points in the main program into which the advice should be ''woven''). For example, a security module can include an advice that performs a security check, with instructions to weave this code snippet into the beginning of methods a(), b() and c() of some class. Powerful mechanisms deploy to enable a broad specification of join points, so that developers need not enumerate weaving-destinations manually. These mechanisms are commonly known as ''pointcut specification languages''.
Fundamentally, the way an aspect interacts with the base program is defined by the (JPM) that the aspect is written in. A JPM defines three things:
- Where the aspect can apply. These are often called '' Join Point s''.
- A way to specify (or ''quantify'') multiple join points. These are often called '' Pointcut s''. Pointcuts are effectively a query over all the join points of a program to select a small sub-set of them.
- A means of affecting behavior at the join points. In AspectJ , this is often called '' Advice ''.
AspectJ has two JPMs: pointcuts and advice, and inter-type declarations. Other aspect languages have different JPMs.
- The join points in this JPM are well-defined points along the execution of a program. This can include: method execution, the instantiation of an object, and the throwing of an exception. Note that these join points are ''dynamic'' in nature and can only be discovered at runtime. Hence, the pointcuts and advice JPM in AspectJ is known as a ''dynamic join point model''.
- Pointcuts are specified by a query over the program. One such pointcut looks like this:
- ---.set---(..) ) && this(Point);
:This pointcut specifies all joinpoints corresponding to the ''execution'' of any method starting with set when the currently executing object is of type Point.
- Advice is specified in a way that is similar to a method. However, advice is never explicitly invoked. It is only invoked when the pointcut attached to it is evaluated to true. Here is an example of this:
after() : set() {
Display.update();
}
:It says that ''after'' the ''set()'' pointcut evaluates to ''true'' execute the command(s) specified in the body of the advice.
The second JPM in AspectJ is known as ''inter-type declarations''. This is a mechanism that allows an aspect to add extra declarations to an existing class or object. This concept is known as Open Classes . An inter-type declaration looks like this:
aspect VisitAspect {
Point.acceptVisitor(Visitor v) {
v.visit(this);
}
}
:This code snippet adds the acceptVisitor method to the Point class.
- The join points are all non-anonymous types in the program.
- The pointcuts are the names of classes or interfaces.
- The means of affecting change at the pointcuts are by adding body declarations to the type.
There are other kinds of JPMs. All aspect languages can be defined in terms of their JPM. For example a hypothetical aspect language for UML may have the following JPM:
- Join points are all model elements.
- Pointcuts are some boolean expression combining the model elements.
- The means of affect at these points are a visualization of all the matched join points.
''Weaving'' - injecting the advice presented in aspects into the specified join-points associated with each advice - provides the final challenge of any AOP solution.
In the original introduction of AOP, Kiczales and his team listed the following possibilities for weaving:
- a source Preprocessor (similar to that in the original implementations of C++ )
- a post-processor that patches binary files
- an AOP-aware compiler that generates woven binary files
- load-time weaving (for example, in the case of Java, weaving the relevant advice as each class gets loaded into the Java Virtual Machine (JVM))
- run-time weaving (trap each join point at runtime, and execute all relevant advice)
The first two options complicate the development process, whereas the last two options may slow down the program's execution. The last option (run-time weaving) also requires a special aspect-aware execution environment. In the world of Java, this implies a special JVM or other supporting framework.
AspectJ currently uses a dedicated compiler solution. The compiler generates standard Java binary class files, which any standard JVM can execute. Load-time weaving will be added in an upcoming release as the result of the merger of AspectJ and AspectWerkz.
All of the listed weaving solutions (except the last) imply changing the code at some point; the code generated for a given Java class by the compiler (after processing and/or loading) does not equate to what a standard Java compiler would have generated, since it now contains woven pieces of advice code. Many view this as a major drawback of AOP, because it complicates both the programmer's understanding of the program execution model and the use of any standard, existing tools, such as debuggers (see also " Problems ", below).
Cohen and Gil have produced a novel alternative: they present the notion of deploy-time weaving . This basically implies post-processing, but rather than patching the generated code, they suggest ''subclassing'' existing classes so that the modifications are introduced by method-overriding. The existing classes remain untouched, even at runtime, and all existing tools (debuggers, profilers, etc.) can be used during development. A similar approach has already proven itself in the implementation of many J2EE application servers, such as IBM 's WebSphere .
AspectJ is an aspect-oriented extension to the Java programming language.
Aspects emerged out of Object-oriented Programming and have functionality similar to Meta-object Protocol s. Aspects relate closely to programming concepts like Subjects , Mixin s, and Delegation . Other ways of using aspect-oriented programming paradigms include Composition Filters and the hyperslices approach.
Mathematically, aspects form a s in their signature. Thus one could view AOP as a powerful, ''logical'' extension, rather than as an independent paradigm. Friedrich Steimann, for example, has proposed such a view.
But AOP proponents promote it as an external package shippable along with some application. For example, if a program itself has no support for security, an AOP package can serve as a modular extension to the application, providing security.
Debug ging can become one of the greatest problems for AOP. While at the syntactic level AOP program code appears separate, at run-time it is not. Concern-weaving can become Unpredictable if it is not specified which aspect should dominate. Designers have considered alternative ways to achieve separation of code, such as C# 's partial types. However, such approaches lack a quantification mechanism enabling programmers to reach several join points of the code with one declarative statement.
Another problem for AOP is the unintentional capture of joinpoints through wildcards. For example, suppose we specify a pointcut with associated advice as a wildcard on all methods that have a certain pattern to their spelling. A programmer who creates a new method may unwittingly choose a name to which the advice will - incorrectly - apply. Similarly, renaming a method can completely change its semantics. Must all programmers who modify the codebase over its lifetime learn a complex set of project-specific naming conventions in order to avoid such difficulties? An AOP-aware development environment can make the applicability of advice more visible, but it is an open question how such concerns will play out over the lifecycle of aspect-oriented code.
- For Cobol :
Write your own preprocessing system.
- For More Info (real-world implementations):
- --- AOSD.net
>
|