Aspects

Aspects are modularization constructs for encapsulating concerns that cut across the normal system object and module boundaries. Two classic examples including the mapping of a global persistence or security strategy to the objects in the system that must use or be controlled by them.

Think of your persistence strategy as one, well-modularized domain and your business logic as another. Rather than tangle the business objects with the code to support persistence and scatter that logic all over the application (breaking DRY), aspects modularize the integration logic between the persistence and domain-logic subsystems.

By modularization, I mean that you can express the intersection join points (defined shortly) succinctly and in one place, as well as defining the logic that expresses what should happen at those intersection points.

Terminology

Several terms are used in the AOP community.

Join PointA point of execution in a program where "advice" might be invoked.
Pointcut (one word...)A set of join points of interest, like a query over all join points in the system.
AdviceThe behavior invoked at a join point.

Potential join points include method calls, variable reads and writes, conditionals, etc.. Aquarium currently supports only method calls, which is sufficient for most needs.

There are several kinds of advice:

BeforeAdvice invoked before the actual join point is invoked.
After ReturningAdvice invoked after the join point executes successfully.
After RaisingAdvice invoked only if the join point raises an exception.
AfterAdvice invoked after the join point executes successfully or raises an exception.
AroundAdvice invoked instead of the join point. The around advice must choose whether or not to invoke the join point by calling a special "proceed" method. Otherwise, the join point is NOT executed.

Only around advice can prevent execution of the join point, except for the special case where before advice raises an exception.

There are two disadvantages of the term advice. One disadvantage is that it implies that we’re just “tweaking” the system in some sense, which is a limiting perspective. The second disadvantage is that both of the words “advise” and “advice” are used and it’s easy to use one when you meant the other!

Usage in Aquarium

Aspects are implemented as classes and you can either create instances of them or use the convenient methods that are added to Object, by default. For example, the following two sections of code are equivalent:

 1aspect1 = Aspect.new :before, :calls_to => :all_methods, 
 2                     :on_types => /*Service$/ do |join_point, object, *args|
 3  log("calling #{join_point.inspect}")
 4end
 5
 6include Aquarium::DSL
 7aspect2 = before :calls_to => :all_methods, 
 8                 :on_types => /*Service$/ do |join_point, object, *args|
 9  log("calling #{join_point.inspect}")
10end

Both examples add before advice (which logs the invocations of the methods) to all the public methods in all classes and modules whose name ends with Service. Note that while the second form is using what is effectively an instance method on the current self, it has no effect on self.

Here is a similar example that advises just a single instance of the MyService class.

1service = MyService.new(...)
2aspect = before :calls_to = :all_methods, 
3                :on_object => service do |join_point, object, *args|
4  log("calling #{join_point.inspect}")
5end

Here is effectively the same example that uses a previously-defined pointcut.

1service = MyService.new(...)
2pointcut = Pointcut.new :calls_to => :all_methods, :on_object => service
3aspect = before :pointcut => pointcut do |join_point, object, *args|
4  log("calling #{join_point.inspect}")
5end

Note that many synonyms are available for the keywords in the API. In these examples, we have used :calls_to as a synonym for :methods and :on_types for :types and :on_objects for :objects. The synonyms are designed to promote more intuitive readability.

Finally, Aquarium supports removing advice:

1aspect.unadvise

Other examples can be found in the RDoc pages.

V0.6.0
  • gem install aquarium
  • gem update aquarium

Menu

Other Links