bject-oriented programming (OOP) brought about the concept of encapsulation, inheritance, and polymorphism in order to create a hierarchy of objects that models a common set of behaviors. So, a particular set of objects is modeled to depict a particular pattern of behavior. But OOP does not explain how to handle a common behavior that extends across unrelated objects. Hence, the same set of code (i.e., redundant code) is scattered throughout the system.
Take the case of logging, for example. Logging code is scattered horizontally across multiple object hierarchies most of the time, and it has nothing to do with the functionalities the object hierarchies represent. In other words, OOP best depicts the top-down (vertical) object relationship but it falls short in handling left-to-right (horizontal) object relationship. Aspect-oriented programming (AOP) facilitates the latter by referring horizontal object relationships as crosscutting concerns and separating them from core functionalities.
The AOP technique helps you add design and run-time behavior to an object model in a non-obtrusive manner by using static and dynamic crosscutting. By using AOP, you can write code for a crosscutting functionality such as logging and then apply it declaratively (via annotations or XML declaration) to already existing code. Also, you can inject the code into plain old Java objects (POJOs) for third-party software for which you don’t have either the source code or the license to modify it. In this way, AOP provides for a flexible and loosely coupled architecture.
Logging as an Aspect
Logging has a lot of characteristics that make it a prime candidate for implementation as an aspect. The following are two of the notable characteristics:
- Logging code is often duplicated across an application, leading to a lot of redundant code across multiple components in the application. Even if the logging logic is abstracted to a separate module so that different components have a single method call, that single method call is duplicated in multiple places.
- Logging logic does not provide any business functionality; it's not related to the domain of a business application.
Spreading the logging across multiple components introduces some complexity to the code. Figure 1 illustrates this complexity. The business objects on the left encapsulate the business functionality. Not only do they perform business tasks, they also take care of logging functionality (and other such crosscutting concerns, such security, transaction, caching, etc.).
|Figure 1. Complexity of Spreading the Logging Across Multiple Components|
AOP makes it possible to modularize these crosscutting services and then apply them declaratively to the components that they should affect. This allows the other core business components to focus on their main tasks and forget about any system services with which they might be involved. Think of an aspect as a blanket that covers many components of an application (see Figure 2). The core functionalities of the application lie with the various components, and you apply the aspects to them declaratively without them knowing those AOP identifies the places in code where the aspects are to be injected; these places are called pointcuts. Aspects are injected into the pointcuts during compile-time or runtime, depending on the AOP framework you use. In fact, AOP allows the introduction of new functionalities into objects without the objects knowing about them. This very effective concept provides flexibility, scalability, and maintainability (among other benefits) to the system.
functionalities really exist.
|Figure 2. Logging Module Provides a Blanket to Other Services|
The example in this article uses Spring as the AOP framework.