Aspect-oriented programming

from Wikipedia, the free encyclopedia

Aspect-oriented programming ( AOP ) is a programming paradigm for object-oriented programming in order to use generic functionalities across several classes ( cross-cutting concern ). Logical aspects of an application program are separated from the actual business logic. Typical application examples are transaction management , auditability and logging behavior .

The concept of AOP was developed by Gregor Kiczales and his team at Xerox PARC . In 2001, the first AOP language AspectJ was also presented there.

motivation

In principle, software has to fulfill certain tasks / requirements. These requirements can be roughly divided into two areas:

  1. The so-called core-level concerns (concern the logical "core" of the application) or functional requirements. These are requirements for the software that can usually be easily encapsulated in individual functions. An example would be the calculation of a value.
  2. The system-level concerns (affect the entire system) or technical boundary conditions. These requirements cannot simply be encapsulated because they have to be implemented in many places. A prime example of this is logging , the recording of the program flow in log files. Calling up the logger is not necessary for the actual functionality, but it still has to be integrated into the source code. Another example would be the transaction of accesses to a resource such as B. a database.

These two parts are interwoven. The core-level concerns can be referred to as components, and the system-level concerns are the aspects. Core-level concerns are usually implemented as modules or objects . Before aspect-oriented programming, there was no elegant solution for the aspects.

The problem of interwoven requirements is also referred to as cross-cutting concerns , because they “cut” across all logical layers of the system. AOP is the tool to also physically separate the logically independent concerns. The aim is to generate code that is easier to maintain and reusable .

In this context, however, system-level concerns are not to be equated with purely technical concerns. Technical issues such as B. the implementation of a separate, specialist authorization system for users can certainly have an aspect character.

background

In the history of the development of programming languages , new programming concepts and high-level languages ​​that implement them have been developed again and again, starting with programming in assembler , which replaced direct programming in binary code , through procedural and functional programming, to today's object-oriented languages. The purpose is to make the developers work easier and thus to achieve better efficiency in the development of the software. One of the underlying principles that was applied to all new programming concepts was that of encapsulating functionality.

  • Assembly languages encapsulate hardware-dependent binary commands for main memory and register access in short, generalized character strings , thus relieving the software developer of the need to deal with the detailed structure of the entire computer hardware .
  • Procedural languages allow simple functions, such as sorting a list of names, to be encapsulated within a procedure . This eliminates the need for line numbers and linked jump instructions and the multiple development of the same function at different points in the program code.
  • Object-oriented programming languages allow the encapsulation of conceptually related functions and variables in independent modules (classes) with clearly defined interfaces, which increases the reusability of the individual modules and frees the software developer from having to deal with the internal implementation of the classes he uses.

Enabling extended functionality is not the goal of this development, because every high-level language is mapped to machine code after compilation.

In particular, the encapsulation of functionality facilitates the development of software by increasing the maintainability and reusability of existing program codes. As software becomes more and more complex and extensive over time, making development more time-consuming and expensive, these two goals became more and more important and are now central elements in the development of new programming concepts and languages.

AOP (aspect-oriented programming or aspect-oriented programming) is a programming concept that deals with the problem of so-called cross-cutting concerns .

The cost-effective and timely development and maintenance of high-quality software is the primary goal of software engineering . To achieve this goal, software that is as modular as possible with the lowest possible complexity of the modules is necessary.

In a conventional system, which also includes the object-oriented approaches, core functionalities, English core concerns , can be neatly separated into modules according to the rules of the art. However, there are concerns (concerns, concerns, requirements) such as error handling, performance and security in every system that cross cut the core functionality and therefore cannot be clearly assigned to a software module. As a result, fragments of such cross cutting concerns (cross cutting core functionalities (overarching requirements) - lack of cohesion ) are not assigned and are scattered throughout the code in an unencapsulated manner. These cross-cutting core functionalities prevent proper modularization in conventional software systems and impair maintenance, comprehensibility, reusability and (traceability). In conventional programming languages, the system decomposition is responsible for this , which allows only one dimension - the list of functions. This phenomenon is also called dominant decomposition . In other words, a naturally multidimensional problem must be solved one-dimensionally.

Derivation from previous paradigms

In procedural programming, code execution is relatively linear. By following the symbols, each individual program step can be traced directly, even when looking at a subsystem. Example in C :

void function (void * c)
{
    Component_repaint(c);
}

The function Component_repaint()is clear. Regardless of whether the pointer has cthe dynamic type Componentor a derived type, the same function is always Component_repaint(Component*)called ( static typing ).

In object-oriented programming, the traceability is reduced by the polymorphism . Example in Java :

void function (Component c)
{
    c.repaint();
}

It is not clear which repaint()method is being executed, it depends on the actual type of object that is creferenced by. A Componenttype derived from could repaint()define its own method by overriding the method Component inherited from repaint().

In aspect-oriented programming, the traceability is further reduced by using pointcuts . A pointcut contains code to be executed for a join point , a join point is a precisely defined call event. Advices can be activated here for almost any point in the call chain . In extreme cases it is even possible to prevent the calling of the methods function()or repaint()themselves. So one could imagine an aspect that defines an advice for the join point “call the method function()” that explicitly prohibits the further processing of this function call . You could also specify in advice that another method should be used on the object instead of the method . The information about what should happen next cannot initially be read off at the scene of the event itself. repaint()

Comparisons

To better understand the concepts of pointcuts , join points, and advices, see comparisons with the older paradigms below

  • Structured Query Language ( SQL )
    Imagine a SELECT statement that can select all methods in all classes of a system. In this context
    - a pointcut of the WHERE clause, which restricts the number of selected methods
    - a join point corresponds to a specific search result in the sense of a data record from a database - only that here no data records are selected from a database, but methods in a system
    - an advice is then the method in one aspect that is to be carried out before, after or instead of the selected method.
  • Other programming paradigms
    While in procedural programming the traceability is given by a source text fragment and in object-oriented programming with additional knowledge of the runtime
    types , traceability in aspect-oriented programming requires knowledge of all aspects, the point cuts for the join points of the Define code fragment.
    Orthogonal means here that the properties of methods are defined “perpendicular” to the normal programming direction. The actual code execution is not only defined by the call and type hierarchy, but also "perpendicular" (orthogonally) to it by the aspects.

analogy

The principle can be visualized as follows: a program, regardless of whether it is procedural or object-oriented, follows a program flow chart , i. H. the program flow is defined at each point by linear sequences of instructions ( code blocks ) and jumps between them (e.g. method calls). One aspect here would be as much as a template that is placed over this original plan and makes various changes or additions to the flow chart. Changes to the template leave the original plan untouched, the template can be exchanged at any time, combined with others or removed again.

Technical consideration

In an object-oriented runtime environment, aspect-oriented programming could be made possible by changeable jump vectors . It can be seen as a kind of “patching” of functions provided for in the programming paradigm.

An object C is enabled to monitor interactions between two objects A and B without changes or extensions to A and B being necessary. Of course, a change in A or B or both is actually necessary. AspectJ creates these changes automatically, the process for doing this is called weaving , since said changes are "woven" into the original code before compiling.

Areas of application

The aspect-oriented programming is able to completely replace the event- driven programming (event handling) previously used in object-oriented programming . Event-driven programming is used to notify an object X of changes to an object Y. The object Y does not need to know the object X. The previous solution is explained here using the example of a window in Java (java.awt.Frame). Events that occur specifically for windows and about which another part of the program is to be notified include closing, activating and deactivating. An interface java.awt.event.WindowListener defines different methods for this and must be implemented by the objects that want to be notified of changes to the window. Objects that want to be notified must register with the respective other object.

The aspect-oriented programming can make the definition of such interfaces superfluous. An aspect X defines the code events to be monitored precisely, called point-cut, for the object Y to be monitored, composed of join points (entire method, method call, method return, distinguishable into method return with return value and method return with exception), and defines the advice for the various point cuts, i.e. the code to be executed. The execution of code in X through changes to an object Y can therefore take place without additional interfaces, methods and registration mechanisms.

Aspect-oriented programming can be used in the development of frameworks (libraries) to e.g. B. to implement properties such as persistence or synchronizability. The transfer mechanism then remains hidden from the library user. Hiding the transfer mechanism makes the code clearer in this case, since the methods are not overloaded with framework code.

Another area of ​​application is software testing, where the introduction of new attributes in classes without changing their source texts (inter-type declarations) represents new and interesting possibilities for developing white box tests, e.g. B. to trace private attributes.

Joinpoint vs. Joinpoint shadow

A distinction must be made between join points and so-called join point shadows. A join point shadow is the static occurrence of a potential join point. Whether this shadow (e.g. a method call in the source code) actually becomes a join point is only decided at runtime depending on the corresponding pointcut (or pointcut designator).

A pointcut defines a set of joinpoint shadows that it cuts out of the underlying program. If a join point shadow is entered while the program is running and its defining point cut can be fulfilled, the “join point shadow” becomes the “join point”.

example

The following example explains the basic idea of ​​aspect-oriented programming. The programming language used is AspectJ , which extends Java to include aspect orientation.

Introductory example

A standard task in software development will serve as an introductory example: tracing information into a file. The procedure without aspect-oriented programming consists of creating a logger and calling a corresponding method there that saves the actual information in the log file:

public void eineMethode() {
    logger.trace("Betrete \"eineMethode\"");

    // Abarbeitung der Methode
    m = a + 2;

    logger.trace("Verlasse \"eineMethode\"");
}

At the beginning of the method, a message is sent to the logger that the method is being entered. Then the actual logic of the method follows. Finally, the exit from the method is logged.

In a typical application, such method calls to the logger are available in many methods and classes - they are scattered throughout the application and are by no means modular. The logger must

  • made known to each object, and
  • cannot easily be exchanged at a central point - at least not without declaring it in the system public static, which equates to a global variable and thus a dubious design.

This also makes it clear what is meant by semantically and physically independent program sections. In the above method, two actually independent tasks are mixed up. This is, on the one hand, the logging and, on the other hand, the actual logic of the method, which consists of storing the result of an addition in the member variable m .

The aspect-oriented programming now also allows tasks such as tracing to be modularized. Suppose you want to log the entry and exit of each method in the class as shown above. Compared to conventional programming, such an instruction can be formulated directly as an aspect in the AOP :

public aspect Tracing {
    pointcut traceCall():
        call(* AOPDemo.*(..));

    before(): traceCall() {
        System.out.println("Betrete \"" + thisJoinPoint + "\"");
    }

    after(): traceCall() {
        System.out.println("Verlasse \"" + thisJoinPoint + "\"");
    }

}

The aspect specifies that all methods of the AOPDemo class are to be included regardless of their signature . The tasks are separated in this way and the original method can be written in abbreviated form:

public void eineMethode() {
    // Abarbeitung der Methode
    m = a + 2;
}

Further example

In addition, aspect-oriented programming enables the original program sequence to be redirected. Security aspects can, for example, replace the original program sequence in order to prevent unauthorized access to protected program parts. Caching aspects increase the speed of execution of programs and are used to reduce the need to call up complex program parts such as database or file system access. The following example demonstrates the rerouting of method calls or the exchange of program parts as interception around advice:

public aspect Caching {

    pointcut cacheCall():
        call(* AOPDemo.*(..));

    private Map cache = new Map();

    around(): cacheCall(Joinpoint joinPointContext) {

       // Prüfen, ob Rückgabewert für aktuelle Aufruf-Argumente schon im Cache abgelegt wurde
       Object args = joinPointContext.getArguments();
       boolean isCallCached = cache.containsKey(args);

       if (isCallCached) {
             // Umleitung und Austausch des ursprünglichen Methodenaufrufs, gesicherten Rückgabewert aus Cache verwenden
             Object cachedReturnValue = cache.get(args);
             return cachedReturnValue;
       }
       else {
             // Weiterleitung an ursprüngliche Methode und neuen Rückgabewert im Cache sichern
             Object newReturnValue = joinPointContext.proceed();
             cache.put(args, newReturnValue);
             return newReturnValue;
       }
    }
}

Terms

The example already includes the most important concepts, if not all. In this section the missing ones are added and assigned to the terms used in the AOP.

For this purpose, the example is expanded to include the following code sequence and the previous sequence is shown graphically:

public void quellMethode() {
    eineMethode();
}

Schematic representation of the use of an aspect

The aspect comes into play even before one eineMethode()enters. The reason for this is the join point right in front of it. These join points are given implicitly. That is, they are present before every method. The pattern that selects those join points from all existing join points that are interesting for an aspect is called the pointcut . In fact, the pointcuts are patterns that also allow wildcards . In order to determine when which code is to be executed within the aspect, advices come into play. In the introductory example these are before and after , in the further example around . These advices, among others, are given implicitly.

Programming with aspects also makes it possible to change the behavior of classes in and with aspects. Aspects can add fields and methods to classes. Here, too, it is possible to use wildcards for several classes at the same time. In a language like Java, these inter-type declarations violate the rule that all fields and methods of a class can be found in one file or the inheritance hierarchy of the class, since aspects of this do not belong.

Typical tasks

AOP is particularly suitable for programming so-called cross-cutting concerns . Examples include logging , error handling , persistence , data validation and IT security .

Profiling APIs, such as those contained in Java , work in a similar way to AOP. They are used to determine non-performing codes. For this purpose, time measurements for the processing of all methods are made by a so-called profiler. The actual profiler can be informed by the virtual machine when a method is entered and exited. A profiler can therefore also be implemented with aspect-oriented programming.

Similar approaches

Aspects have their origin in object-oriented programming and, at least in their intention, are comparable to meta-object protocols, such as those found in the Common Lisp Object System , for example . Furthermore, aspects are related to concepts such as subject-oriented programming , mixins , classboxes or the concept of delegation , as can be found in the programming language Self . The so-called traits represent a similar or even equivalent approach .

Remarks

The advantage of aspect orientation is the logical and physical separation of the semantics (the component) from the technical detail (aspect). The disadvantage of aspect-oriented programming is the overhead that arises after weaving in the generated program. This generally leads to a loss of performance . Furthermore, aspect-oriented programming reduces the traceability of program behavior, since the places where an aspect is responsible are not directly recognizable in the code concerned. This makes debugging much more difficult, but this disadvantage can be neutralized or at least reduced with the support of an IDE , as debugging is just as multidimensional as developing the code.

Another disadvantage is that when using this technique, undesirable and difficult to understand interactions between individual aspects can occur.

Aspects and components can be defined in different programming languages.

See also

literature

  • Lars Wunderlich: AOP: Aspect-oriented programming in practice. Developers.press, Frankfurt am Main 2005, ISBN 3-935042-74-4 .
  • Oliver Böhm: Aspect-oriented programming with AspectJ 5: Getting started with AspectJ and AOP. Dpunkt Verlag, Heidelberg 2006, ISBN 3-89864-330-1 .
  • Renaud Pawlak, Lionel Seinturier, Jean-Philippe Retaille: Foundations of AOP for J2EE Development (Foundation). Apress, Berkeley CA 2005, ISBN 1-59059-507-6 .
  • Ralf Westphal: Aspect-oriented programming with .NET. In: dotnetpro Ulm 22.2007,10. ISSN  1610-1553

Web links

Individual evidence

  1. ^ Interception Around Advice