Discovering AOP

This chapter covers
■ Understanding crosscutting concerns
■ Modularizing crosscutting concerns using AOP
■ Understanding AOP languages

Reflect back on your last project, and compare it with a project you worked on a few
years back. What’s the difference? One word: complexity. Today’s software systems are
complex, and all indications point to even faster growth in software complexity in
the coming years. What can a software developer do to manage complexity?
If complexity is the problem, modularization is the solution. By breaking the
problem into more manageable pieces, you have a better shot at implementing
each piece. When you’re faced with complex software requirements, you’re likely
to break those into multiple parts such as business functionality, data access, and
presentation logic. We call each of these functionalities concerns of the system. In a
banking system, you may be concerned with customer management, account management, and loan management. You may also have an implementation of data
access and the web layer. We call these core concerns because they form the core
functionality of the system. Other concerns, such as security, logging, resource
pooling, caching, performance monitoring, concurrency control, and transaction
management, cut across—or crosscut—many other modules. We call these functionalities crosscutting concerns.
For core concerns, object-oriented programming (OOP), the dominant methodology employed today, does a good job. You can immediately see a class such as
LoanManagementService implementing business logic and AccountRepository implementing data access. But what about crosscutting concerns? Wouldn’t it be nice if you
could implement a module that you identify as Security, Auditing, or PerformanceMonitor? You can’t do that with OOP alone. Instead, OOP forces you to fuse the implementation of these functionalities in many modules. This is where aspect-oriented
programming (AOP) helps.
AOP is a methodology that provides separation of crosscutting concerns by introducing a new unit of modularization—an aspect. Each aspect focuses on a specific
crosscutting functionality. The core classes are no longer burdened with crosscutting
concerns. An aspect weaver composes the final system by combining the core classes
and crosscutting aspects through a process called weaving. Thus, AOP helps to create
applications that are easier to design, implement, and maintain.
In this chapter, we’ll examine the fundamentals of AOP, the problems it addresses,
and why you need to know about it. In the rest of the book, we’ll examine AspectJ,
which is a specific implementation of AOP. Let’s start by discussing how you manage
various concerns without AOP, which will help you understand why you need AOP.

1.1 Life without AOP

How do you implement crosscutting concerns using OOP alone? Typically, you add the
code needed for each crosscutting concern in each module, as shown in figure 1.1.
This figure shows how different modules in a system implement both core concerns and crosscutting concerns. Let’s illustrate the same idea through a code snippet.
Consider the skeleton implementation of a representative class that encapsulates
some business logic in a conventional way, shown in listing 1.1. A system consists of
many such classes.


Although the details will vary, the listing shows a common problem many developers
face: a conceptual separation exists between multiple concerns at design time, but
implementation tangles them together. Such an implementation also breaks the Single
Responsibility Principle (SRP)1
by making the class responsible for implementing core
and crosscutting concerns. If you need to change the invocation of the code related to
crosscutting concerns, you must change each class that includes such an invocation.
Doing so breaks the Open/Close principle2
—open for extension, but closed for modifications. The overall consequence is a higher cost of implementing features and fixing bugs.
With conventional implementations, core and crosscutting concerns are tangled in
each module. Furthermore, each crosscutting concern is scattered in many modules.
The presence of code tangling and code scattering is a tell-tale sign of the conventional implementation of crosscutting concerns.3
Let’s examine them in detail.

1.1.1 Code tangling

Code tangling is caused when a module is implemented to handle multiple concerns
simultaneously. Developers often consider concerns such as business logic, performance, synchronization, logging, security, and so forth when implementing a module.

This leads to the simultaneous presence of elements from each concern’s implementation and results in code tangling. Figure 1.2 illustrates code tangling in a module.
Another way to look at code tangling is to use the notion of a multidimensional
concern space. Imagine that you’re projecting the application requirements onto a
multidimensional concern space, with each concern forming a dimension. Here, all
the concerns are mutually independent and therefore can evolve without affecting
the rest. For example, changing the security requirement from one kind of authorization scheme to another shouldn’t affect the business logic. But as you see in figure 1.3,
a multidimensional concern space collapses into a one-dimensional implementation space.
Because the implementation space is one-dimensional, its focus is usually the
implementation of the core concern that takes the role of the dominant dimension; other concerns then tangle the core concern. Although you may naturally separate the individual requirements into mutually independent concerns during the
design phase, OOP alone doesn’t let you retain the separation in the implementation phase.
We’ve looked at the first symptom of crosscutting concerns when implemented
using traditional techniques; now, let’s move on to the next.

1.1.1 Code scattering

Code scattering is caused when a single functionality is implemented in multiple modules. Because crosscutting concerns, by definition, are spread over many modules,
related implementations are also scattered over all those modules. For example, in a
system using a database, performance concerns may affect all the modules accessing
the database.
Figure 1.4 shows how a banking system implements security using conventional
techniques. Even when using a well-designed security module that offers an abstract
API and hides the details, each client—the accounting module, the ATM module, and
the database module—still needs the code to invoke the security API to check permission. The code for checking permission is scattered across multiple modules, and
there is no single place to identify the concern. The overall effect is an undesired tangling between the modules to be secured and the security module.

Code tangling and code scattering together impact software design and development
in many ways: poor traceability, lower productivity, lower code reuse, poor quality, and
difficult evolution. All of these problems lead us to search for better approaches to
architecture, design, and implementation. Aspect-oriented programming is one viable
solution. In the next section, we’ll introduce you to AOP. Later in this chapter, we’ll
examine alternatives to AOP as well.

1.2 Modularizing with AOP

In OOP, the core concerns can be loosely coupled through interfaces, but there is no
easy way to do the same for crosscutting concerns. This is because a concern is implemented in two parts: the server-side piece and the client-side piece. OOP modularizes
the server part quite well in classes and interfaces. But when the concern is of a crosscutting nature, the client part (consisting of the requests to the server) is spread over
all the clients.

NOTE:We use the terms server and client here in the classic OOP sense to mean the
objects that are providing a certain set of services and the objects using
those services. Don’t confuse them with networking servers and clients.

As an example, let’s take another look at the typical implementation of a crosscutting
concern in OOP, shown in figure 1.4. The security module provides its services
through an interface. The use of an interface loosens the coupling between the clients and the implementations of the interface. Clients that use the security services
through the interface are oblivious to the exact implementation they’re using; any
changes to the implementation don’t require changes to the clients themselves. Likewise, replacing one security implementation with another is just a matter of instantiating the right kind of implementation. The result is that you can replace one security
implementation with another with little or no change to the individual client modules. But this arrangement still requires that each client have the embedded code to
call the API. Such calls must be included in all the modules requiring security and are
tangled with their core logic.
Using AOP, none of the core modules contain calls to the security API. Figure 1.5
shows the AOP implementation of the same security functionality shown in figure 1.4.
The security concern—implementation and invocations—now resides entirely inside
the security module and the security aspect. For now, don’t worry about the way in
which AOP achieves this; we’ll explain in the next section.
The fundamental change that AOP brings is the preservation of the mutual independence of the individual concerns. Implementations can be easily mapped back to
the corresponding concerns, resulting in a system that is simpler to understand, easier
to implement, and more adaptable to changes.

1.3 Anatomy of an AOP language

The AOP methodology is just that—a methodology. In order to be of any use in the
real world, it must be implemented, or realized. Each realization of AOP involves specifying a language or a framework and associated tools. Like any other programming
methodology, an AOP implementation consists of two parts:
■ The language specification describes the language constructs and syntax to
express implementation of the core and crosscutting concerns.
■ The language implementation verifies the code’s adherence to the language specification and translates the code into an executable form.

1.3.1 The AOP language specification

Any implementation of AOP must specify a language to implement the individual
concerns and a language to implement the weaving rules. Note that an AOP system
may offer a homogeneous language that doesn’t distinguish between the two parts.
This is likely to be the case in future AOP languages. Let’s take a closer look at these
two parts.
IMPLEMENTATION OF CONCERNS
As in other methodologies, the concerns of a system are implemented into modules
that contain the data and behavior needed to provide their services. A module that
implements the core part of the caching concern maintains a collection of cached
objects, manages the validity of the cached objects, and ensures bounded memory
consumption. To implement both the core and crosscutting concerns, we normally
use standard languages such as C, C++, and Java.
WEAVING RULES SPECIFICATION
Weaving rules specify how to combine the implemented concerns in order to form the
final system. After you implement the core part of the caching concern in a module
(perhaps through a third-party class library), you must introduce caching into the system. The weaving rule in this case specifies the data that needs to be cached, the information that forms the key into the cache storage, and so forth. The system then uses
these rules to obtain and update cache from the specified operations.
The power of AOP comes from the economical way of expressing the weaving
rules. For instance, to modularize tracing concerns in listing 1.1, you can add a few
lines of code to specify that all the public operations in the system should be logged.
Here is a weaving specification for the tracing aspect:
■ Rule 1: Create a logger object.
■ Rule 2: Log the beginning of each public operation.
■ Rule 3: Log the completion of each public operation.
This is much more succinct than modifying each public operation to add logging
code. Because the tracing concern is modularized away from the class, it may focus
only on the core concern, as follows:

Compare this class with the one in listing 1.1: all the code to perform tracing—the
ancillary concerns from the class’s point of view—have been removed. When you
apply the same process to other crosscutting concerns, only the core business logic
remains in the class. As you’ll see in the next section, an AOP implementation combines the classes and aspects to produce a woven executable.
Weaving rules can be general or specific in the ways they interact with the core
modules. In the previous logging example, the weaving rules don’t need to mention
any specific classes or methods in the system. On the other end of the spectrum, a
weaving rule may specify that a business rule should be applied only to specific methods, such as the credit() and debit() operations in the Account class or the ones
that carry the @ReadOnly annotation. The specificity of the weaving rules determines
the level of coupling between the aspect and core logic.
The language used to specify weaving rules can be a natural extension of that language or something entirely different. For example, an AOP implementation using Java
as the base language might introduce new extensions that blend well with the base language, or it could use a separate XML-based language to express weaving rules.

1.3.2 The AOP language implementation

The AOP language implementation performs two logical steps: It first combines the
individual concerns using the weaving rules, and then it converts the resulting information into executable code. AOP implementation thus requires the use of a processor—weaver—to perform these steps.
An AOP system can implement the weaver in various ways. A simple approach uses
source-to-source translation. Here, the weaver processes source code for individual
classes and aspects to produce woven source code. The aspect compiler then feeds
this woven code to the base language compiler to produce the final executable code.
This was the implementation technique used in early implementations of AspectJ.
The approach suffers from several drawbacks because the executable code can’t be
easily traced back to the original source code. For example, stack traces indicate line
numbers in woven source code.
Another approach first compiles the source code using the base language compiler. Then, the resulting files are fed to the aspect compiler, which weaves those files.
Figure 1.6 shows a schematic of a compiler-based AOP language implementation.
An AOP system may also be able to push the weaving process close to execution of
the system. If the implementation of AOP is Java-based, a special class loader or a virtual

machine (VM) agent can perform the weaving. Such an implementation first loads the
byte code for the aspects, weaves them into the classes as they’re being loaded, and supplies those woven versions of the classes to the underlying VM.
Yet another implementation could use automatically created proxies. In this case,
each object that needs weaving is wrapped inside a proxy. Such an implementation
typically works well in conjunction with another framework that controls the creation
of objects. In this way, the framework can wrap each created object in a proxy.
So far, we’ve looked at the mechanics of an AOP system. Now, let’s examine AOP’s
fundamental concepts.

1.4 Fundamental concepts in AOP

By now, it should be clear that AOP systems help in modularizing crosscutting concerns. But so do many other technologies, such as byte-code manipulation tools,
direct use of the proxy design pattern, and meta-programming. How do you differentiate AOP from these options? To find out, we need to distill the core characteristics of
AOP systems into a generic model. If a system fits that model, it’s an AOP system.
To implement a crosscutting concern, an AOP system may include many of the following concepts:
■ Identifiable points in the execution of the system —The system exposes points during
the execution of the system. These may include execution of methods, creation
of objects, or throwing of exceptions. Such identifiable points in the system are
called join points. Note that join points are present in all systems—even those
that don’t use AOP—because they’re points during execution of a system. AOP
merely identifies and categorizes these points.
■ A construct for selecting join points —Implementing a crosscutting concern
requires selecting a specific set of join points. For example, the tracing aspect
discussed earlier needs to select only the public methods in the system. The
pointcut construct selects any join point that satisfies the criteria. This is similar
to an SQL query selecting rows in database (we’ll compare AOP with databases
in section 1.5.2). A pointcut may use another pointcut to form a complex selection. Pointcuts also collect context at the selected points. For example, a pointcut may collect method arguments as context. The concept of join points and
the pointcut construct together form an AOP system’s join point model. We’ll
study AspectJ’s join point model in chapter 3.
■ A construct to alter program behavior —After a pointcut selects join points, you
must augment those join points with additional or alternative behavior. The
advice construct in AOP provides a facility to do so. An advice adds behavior
before, after, or around the selected join points. Before advice executes before
the join point, whereas after advice executes after it. Around advice surrounds
the join point execution and may execute it zero or more times. Advice is a
form of dynamic crosscutting because it affects the execution of the system. We’ll
study AspectJ’s dynamic crosscutting implementation in chapter 4.
■ Constructs to alter static structure of the system —Sometimes, to implement crosscutting functionality effectively, you must alter the static structure of the system.
For example, when implementing tracing, you may need to introduce the logger field into each traced class; inter-type declaration constructs make such modifications possible. In some situations, you may need to detect certain conditions,
typically the existence of particular join points, before the execution of the system; weave-time declaration constructs allow such possibilities. Collectively, all
these mechanisms are referred to as static crosscutting, given their effect on the
static structure, as opposed to dynamic behavior changes to the execution of
the system. We’ll study AspectJ’s static crosscutting support in chapter 5.
■ A module to express all crosscutting constructs —Because the end goal of AOP is to
have a module that embeds crosscutting logic, you need a place to express that
logic. The aspect construct provides such a place. An aspect contains pointcuts,
advice, and static crosscutting constructs. It may be related to other aspects in a
similar way to how a class relates to other classes. Aspects become a part of the
system and use the system (for example, classes in it) to get their work done.
We’ll examine AspectJ’s implementation of aspect in chapter 6.
Figure 1.7 shows all these players and their relationships to each other in an AOP system.
Each AOP system may implement a subset of the model. For example, Spring AOP
(discussed in chapter 9) doesn’t implement weave-time declarations due to its emphasis on its runtime nature. On the other hand, the join point model is so central to
AOP that every AOP system must support it—everything else revolves around the joinpoint model.
When you encounter a solution that modularizes crosscutting concerns, try to map
it onto the generic AOP model. If you can, then that solution is indeed an AOP system.
Otherwise, it’s an alternative approach for solving the problem of crosscutting concerns.

1.5 AOP by analogy

When you’re learning a new technology, it sometimes helps to compare it with existing technologies. In this section, we’ll attempt to help you understand AOP by
comparing it with Cascading Style Sheets (CSS), database programming, and eventoriented systems. The purpose of this section is to help those familiar with at least one
of these technologies to understand AOP by analogy.

1.5.1 Cascading Style Sheets (CSS)

CSS is a widely supported mechanism to separate content from presentation in HTML
pages. Without CSS, formatting information is fused with content (causing tangling),
and similar content elements have presentational information spread into multiple
places (causing scattering). CSS helps the situation by letting the main document focus
on content by separating the formatting information into a document called a stylesheet.
A core concept in CSS is a selector that selects document elements matching a certain specification. For example, the body p selector can select paragraphs inside the
body element. You can then associate presentational information with a selector and,
for example, set the background color of such elements to blue using the body p
{background: blue;} element.
AOP acts on classes in the same way that CSS acts on documents. AOP lets you separate crosscutting logic from the main-line logic. AOP’s pointcuts have the same selection role as CSS selectors. Whereas CSS selectors select structural elements in a
document, pointcuts select program elements. Similarly, the blocks describing the formatting information are analogous to AOP advice in functionality.
Often, the selection mechanism requires more information than merely using the
inherent characteristics of a structure such as body p. It’s common practice to supplement content elements with additional metadata through the class attribute. For
example, you can mark an HTML paragraph element as menu by using the tag

1.5.2 Database systems

Database systems offer “dynamic crosscutting” targeted toward data access, whereas
AOP offers a similar mechanism toward general programming. It offers two good analogies to AOP concepts: SQL with pointcuts and triggers with advice.
SQL AND POINTCUTS
A join point is like a row in a database, whereas a pointcut is like an SQL query. An SQL
query selects rows according to a specified criterion such as “rows in accounts table,
where the balance is greater than 50”. It provides access to the content of the selected
rows. Similarly, a pointcut is a query over program execution that selects join points
according to a specified criterion such as “method execution in the Account class,
where the method name starts with ‘set’”. It also provides access to the join point context (objects available at the join point, such as method arguments).
TRIGGERS AND ADVICE
Database programming often uses triggers to respond to changes made in data. For
example, you can use a trigger to audit changes in certain tables. The following snippet calls the logInventoryIncrease() procedure when inventory increases:

The static condition, such as the name of the table and the modified column, as well
as the dynamic condition, such as the difference in the column value, are analogous
to AOP’s pointcut concept. Both describe a selection criterion to “trigger” certain
actions. The stored procedure specified in the trigger is analogous to AOP’s advice.
Database triggers and AOP’s advice both modify the normal program execution to
carry additional or alternative actions. But there are some obvious differences. Database triggers are useful only for database operations. AOP has a more general
approach that can be used for many other purposes. But note that AOP doesn’t necessarily obviate the need for database triggers, for reasons such as performance and
bringing uniformity to multiple applications accessing the same tables.
Similar to database triggers, event-oriented programming includes the notion of
responding to events.

1.5.3 Event-oriented programming

Event-oriented programming is essentially the observer design pattern (we’ll discuss it
as an alternative to AOP in section 1.7.3). Each interested code site notifies the observers by firing events, and the observers respond by taking appropriate action, which
may be crosscutting in nature.
In AOP, the program is woven with logic to fire virtual events and to respond to the
events with an action that corresponds to the crosscutting concern it’s implementing.
But note this important difference: Unlike in event-based programming, there is no
explicit code for the creation and firing of events in the subject classes. Executing part
of the program constitutes the virtual-event generation. Also, event systems tend to be
more coarse-grained than an AOP solution implements.
Note that you can effectively combine event-oriented programming with AOP. Essentially, you can modularize the crosscutting concern of firing events into an aspect. With
such an implementation, you avoid tangling the core code with the event-firing logic.
Now that you have a good understanding of AOP, let’s turn our attention to a bit of
history and the current status of AOP implementations.

AspectJ in action相关推荐

  1. AspectJ in Action(2)

    1.8.1 Costs of AOP Some of the costs associated with AOP are the usual suspects associated with any ...

  2. AspectJ in Action 第2版 中文目录

    本人用(金山快译个人版1.0)翻译, 在此感谢金山软件公司免费提供翻译软件. 机器翻译, 人工修正,不通之处请指正. 内容     序 xix     序文 xxiii     第一版 xxv 的序文 ...

  3. proxy aspectj_使用AspectJ,Javassist和Java Proxy进行代码注入的实用介绍

    proxy aspectj 静态地或在运行时将代码片段注入已编译的类和方法中的功能可能会很有帮助. 这尤其适用于在没有源代码的第三方库中或在无法使用调试器或探查器的环境中对问题进行故障排除. 代码注入 ...

  4. 使用AspectJ和Spring简化了AOP

    我最近开始研究面向方面的编程(AOP),至少可以说使我兴奋. 当然我很熟悉它,因为我看到它在Spring中用于事务管理,但是我从未深入研究它. 在本文中,我想展示通过AspectJ可以快速掌握AOP和 ...

  5. 使用AspectJ,Javassist和Java Proxy进行代码注入的实用介绍

    静态地或在运行时将代码片段注入已编译的类和方法中的功能可能会很有帮助. 这尤其适用于在没有源代码的第三方库中或在无法使用调试器或探查器的环境中对问题进行故障排除. 代码注入对于处理涉及整个应用程序的问 ...

  6. 用AspectJ做的一个回合格斗小游戏

    由于Spring2的AOP部分作了比较大的调整,很多地方的使用引入了AspectJ中的内容,为了完成<深入Spring 2:轻量级J2EE开发框架原理与实践>中Spring AOP应用一章 ...

  7. aspectJ动态编入问题

    我最近在做aop的内容.但是碰到了一点问题.希望能够得到大家的帮助. 我使用aop的方式是要求动态的weave in任何一个我指定的class中的方法(weave in性能测试的代码). 而weave ...

  8. spring aop 申明了切面类之后,如何申明切入点呢?

    2019独角兽企业重金招聘Python工程师标准>>> 8.2.3 Declaring a pointcut Recall that pointcuts determine join ...

  9. Spring - Java/J2EE Application Framework 应用框架 第 5 章 Spring AOP: Spring之面向方面编程G

    第 5 章 Spring AOP: Spring之面向方面编程 5.1. 概念 面向方面编程 (AOP) 提供从另一个角度来考虑程序结构以完善面向对象编程(OOP). 面向对象将应用程序分解成 各个层 ...

最新文章

  1. MySQL 5.6通过Keepalived+互为主从实现高可用架构
  2. 机器学习基础专题:样本选择
  3. mysql数据库且字 语句是什么,MySQL(数据库)基本操作
  4. [转]Global exception handling in Web API 2.1 and NLog
  5. 实现技术3次作业 谢筱 1101220759
  6. python字符串迭代_Python字符串迭代/函数
  7. 信号与系统Matlab实验1
  8. 电力线通信技术的发展
  9. 揭秘小红书的种草套路
  10. Linux学习系列 --awk命令学习
  11. 第十五讲:达索系统锂电池行业解决方案在线直播 | 达索系统百世慧
  12. C# Socket实现两台电脑通信(三)
  13. MYSQL UNION 同列类型不同时的处理方法
  14. 华为手机的逆天神操作,一键变身扫描仪,99页纸质文档秒变电子版
  15. 登录注册小程序(JAVA基础案例教程第二章-课后作业)
  16. 压缩包安装fitter库,gbk编码错误解决方法
  17. obj-c中Autorelease、属相定义Property、对象的操作
  18. 将https安全证书导入jdk中
  19. JAYのpython学习笔记——数据结构之列表
  20. 蓝桥杯单片机组(CT107D 开发板)总结

热门文章

  1. 如何利用python将NWPU VHR-10目标检测遥感数据集的格式转换成VOC目标检测数据集的格式
  2. linux 挂在u盘变成只读,linux系统下优盘挂载之文件系统后只读解决方法
  3. Android自定义系列——13.Matrix Camera
  4. mysql之聚簇索引与非聚簇索引
  5. Vue.js实战第十章笔记
  6. C++ string 转化为LPCTSTR
  7. 手把手教你BCGControlBar MFC界面控件“起航”技巧(文章转载自:慧都控件网)
  8. Java函数的基本知识
  9. 转战 GithubPages
  10. 笔记-首次参加数据挖掘比赛摸索的经验(赛题为CCF-BDCI2017企业经营退出风险预测)