As I’m writing this chapter, Texas (where I reside) is going through several days of record-high temperatures. It’s hot. In weather like this, air conditioning is a must.
But the downside of air conditioning is that it uses electricity, and electricity costs money. There’s little we can do to avoid paying for a cool and comfortable home.
That’s because every home has a meter that measures every kilowatt, and once a month someone comes by to read that meter so that the electric company accu-rately knows how much to bill us.
Now imagine what would happen if the meter went away and nobody came by to measure our electricity usage. Suppose that it were up to each homeowner to con-tact the electric company and report their electricity usage. Although it’s possible that some obsessive homeowners would keep careful record of their lights, televi-sions, and air conditioning, most wouldn’t bother. Most would estimate their usage and others wouldn’t bother reporting it at all. It’s too much trouble to monitor electrical usage and the temptation to not pay is too great.
This chapter covers
Basics of aspect-oriented programming
Creating aspects from POJOs
Using @AspectJ annotations
Injecting dependencies into AspectJ aspects
85 What’s aspect-oriented programming?
Electricity on the honor system might be great for consumers, but it would be less than ideal for the electric companies. That’s why we all have electric meters on our homes and why a meter reader drops by once per month to report the consumption to the electric company.
Some functions of software systems are like the electric meters on our homes. The functions need to be applied at multiple points within the application, but it’s unde-sirable to explicitly call them at every point.
Monitoring electricity consumption is an important function, but it isn’t foremost in most homeowners’ minds. Mowing the lawn, vacuuming the carpet, and cleaning the bathroom are the kinds of things that homeowners are actively involved in. Moni-toring the amount of electricity used by their house is a passive event from the home-owner’s point of view. (Although it’d be great if mowing the lawn were also a passive event—especially on these hot days.)
In software, several activities are common to most applications. Logging, security, and transaction management are important, but should they be activities that your application objects are actively participating in? Or would it be better for your applica-tion objects to focus on the business domain problems they’re designed for and leave certain aspects to be handled by someone else?
In software development, functions that span multiple points of an application are called cross-cutting concerns. Typically, these cross-cutting concerns are conceptually separate from (but often embedded directly within) the application’s business logic.
Separating these cross-cutting concerns from the business logic is where aspect-oriented programming (AOP) goes to work.
In chapter 2, you learned how to use dependency injection (DI) to manage and configure your application objects. Whereas DI helps you decouple your application objects from each other, AOP helps you decouple cross-cutting concerns from the objects that they affect.
Logging is a common example of the application of aspects. But it’s not the only thing aspects are good for. Throughout this book, you’ll see several practical applica-tions of aspects, including declarative transacapplica-tions, security, and caching.
This chapter explores Spring’s support for aspects, including how to declare regu-lar classes to be aspects and how to use annotations to create aspects. In addition, you’ll see how AspectJ—another popular AOP implementation—can complement Spring’s AOP framework. But first, before we get carried away with transactions, secu-rity, and caching, let’s see how aspects are implemented in Spring, starting with a primer on a few of AOP’s fundamentals.
4.1 What’s aspect-oriented programming?
As stated earlier, aspects help to modularize cutting concerns. In short, a cross-cutting concern can be described as any functionality that affects multiple points of an application. Security, for example, is a cross-cutting concern, in that many methods in an application can have security rules applied to them. Figure 4.1 gives a visual depic-tion of cross-cutting concerns.
86 CHAPTER 4 Aspect-oriented Spring
Figure 4.1 represents a typical application that’s broken down into modules. Each mod-ule’s main concern is to provide services for its particular domain. But each module also requires similar ancillary functionalities, such as security and transaction management.
A common object-oriented technique for reusing common functionality is to apply inheritance or delegation. But inheritance can lead to a brittle object hierarchy if the same base class is used throughout an application, and delegation can be cumbersome because
complicated calls to the delegate object may be required.
Aspects offer an alternative to inheritance and delegation that can be cleaner in many circumstances. With AOP, you still define the common functionality in one place, but you can declaratively define how and where this functionality is applied without having to modify the class to which you’re applying the new feature. Cross-cutting concerns can now be modularized into special classes called aspects. This has two benefits. First, the logic for each concern is now in one place, as opposed to being scattered all over the code base. Second, our service modules are now cleaner since they only contain code for their primary concern (or core functionality) and second-ary concerns have been moved to aspects.
4.1.1 Defining AOP terminology
Like most technologies, AOP has formed its own jargon. Aspects are often described in terms of advice, pointcuts, and join points. Figure 4.2 illustrates how these concepts are tied together.
Unfortunately, many of the terms used to describe AOP features aren’t intuitive.
Nevertheless, they’re now part of the AOP idiom, and in order to understand AOP, you must know these terms. Before you walk the walk, you have to learn to talk the talk.
ADVICE
When a meter reader shows up at your house, his purpose is to report the num-ber of kilowatt hours back to the electric company. Sure, he has a list of houses that he must visit and the information that he reports is important. But the actual act of recording electricity usage is the meter reader’s main job.
Likewise, aspects have a purpose—a job they’re meant to do. In AOP terms, the job of an aspect is called advice.
Figure 4.1 Aspects modularize cross-cutting concerns, applying logic that spans multiple application objects.
Join points
Program execution
Figure 4.2 An aspect’s functionality (advice) is woven into a program’s execution at one or more join points.
87 What’s aspect-oriented programming?
Advice defines both the what and the when of an aspect. In addition to describing the job that an aspect will perform, advice addresses the question of when to perform the job. Should it be applied before a method is invoked? After the method is invoked? Both before and after method invocation? Or should it only be applied if a method throws an exception?
Spring aspects can work with five kinds of advice:
Before—The advice functionality takes place before the advised method is invoked.
After—The advice functionality takes place after the advised method completes, regardless of the outcome.
After-returning—The advice functionality takes place after the advised method successfully completes.
After-throwing—The advice functionality takes place after the advised method throws an exception.
Around—The advice wraps the advised method, providing some functionality before and after the advised method is invoked.
JOIN POINTS
An electric company services several houses, perhaps even an entire city. Each house will have an electric meter that needs to be read and thus each house is a potential tar-get for the meter reader. The meter reader could potentially read all kinds of devices, but to do his job, he needs to target electric meters that are attached to houses.
In the same way, your application may have thousands of opportunities for advice to be applied. These opportunities are known as join points. A join point is a point in the execution of the application where an aspect can be plugged in. This point could be a method being called, an exception being thrown, or even a field being modified.
These are the points where your aspect’s code can be inserted into the normal flow of your application to add new behavior.
POINTCUTS
It’s not possible for any one meter reader to visit all houses serviced by the electric company. Instead, each one is assigned a subset of all of the houses to visit. Likewise, an aspect doesn’t necessarily advise all join points in an application. Pointcuts help nar-row down the join points advised by an aspect.
If advice defines the what and when of aspects, then pointcuts define the where. A pointcut definition matches one or more join points at which advice should be woven.
Often you specify these pointcuts using explicit class and method names or through regular expressions that define matching class and method name patterns. Some AOP frameworks allow you to create dynamic pointcuts that determine whether to apply advice based on runtime decisions, such as the value of method parameters.
ASPECTS
When a meter reader starts his day, he knows both what he’s supposed to do (report electricity usage) and which houses to collect that information from. Thus he knows everything he needs to know to get his job done.
88 CHAPTER 4 Aspect-oriented Spring
An aspect is the merger of advice and pointcuts. Taken together, advice and point-cuts define everything there is to know about an aspect—what it does and where and when it does it.
INTRODUCTIONS
An introduction allows you to add new methods or attributes to existing classes. For example, you could create an Auditable advice class that keeps the state of when an object was last modified. This could be as simple as having one method, setLast-Modified(Date), and an instance variable to hold this state. The new method and instance variable can then be introduced to existing classes without having to change them, giving them new behavior and state.
WEAVING
Weaving is the process of applying aspects to a target object to create a new proxied object. The aspects are woven into the target object at the specified join points. The weaving can take place at several points in the target object’s lifetime:
Compile time—Aspects are woven in when the target class is compiled. This requires a special compiler. AspectJ’s weaving compiler weaves aspects this way.
Classload time—Aspects are woven in when the target class is loaded into the JVM. This requires a special ClassLoader that enhances that target class’s byte-code before the class is introduced into the application. AspectJ 5’s load-time weaving (LTW) support weaves aspects in this way.
Runtime—Aspects are woven in sometime during the execution of the applica-tion. Typically, an AOP container will dynamically generate a proxy object that will delegate to the target object while weaving in the aspects. This is how Spring AOP aspects are woven.
That’s a lot of new terms to get to know. Revisiting figure 4.2, you can now see how advice contains the cross-cutting behavior that needs to be applied to an application’s objects. The join points are all the points within the execution flow of the application that are candidates to have advice applied. The pointcut defines where (at what join points) that advice is applied. The key concept you should take from this is that point-cuts define which join points get advised.
Now that you’re familiar with some basic AOP terminology, let’s see how these core AOP concepts are implemented in Spring.
4.1.2 Spring’s AOP support
Not all AOP frameworks are created equal. They may differ in how rich their join point models are. Some allow you to apply advice at the field modification level, whereas others only expose the join points related to method invocations. They may also differ in how and when they weave the aspects. Whatever the case, the ability to create pointcuts that define the join points at which aspects should be woven is what makes it an AOP framework.
89 What’s aspect-oriented programming?
Much has changed in the AOP framework landscape in the past few years. There has been some housecleaning among the AOP frameworks, resulting in some frame-works merging and others going extinct. In 2005, the AspectWerkz project merged with AspectJ, marking the last significant activity in the AOP world and leaving us with three dominant AOP frameworks:
AspectJ (http://eclipse.org/aspectj)
JBoss AOP (http://www.jboss.org/jbossaop)
Spring AOP (http://www.springframework.org)
Since this is a Spring book, we’ll focus on Spring AOP. Even so, there’s a lot of synergy between the Spring and AspectJ projects, and the AOP support in Spring borrows a lot from the AspectJ project.
Spring’s support for AOP comes in four flavors:
Classic Spring proxy-based AOP
@AspectJ annotation-driven aspects
Pure-POJO aspects
Injected AspectJ aspects (available in all versions of Spring)
The first three items are all variations on Spring’s proxy-based AOP. Consequently, Spring’s AOP support is limited to method interception. If your AOP needs exceed simple method interception (constructor or property interception, for example), you’ll want to consider implementing aspects in AspectJ, perhaps taking advantage of Spring DI to inject Spring beans into AspectJ aspects.
We’ll explore more of these Spring AOP techniques in this chapter. But before we get started, it’s important to understand a few key points of Spring’s AOP framework.
SPRING ADVICE IS WRITTEN IN JAVA
All of the advice you create within Spring is written in a standard Java class. That way, you get the benefit of developing your aspects in the same integrated development
What? No classic Spring AOP?
The term classic usually carries a good connotation. Classic cars, classic golf tourna-ments, and classic Coca-Cola are all good things.
But Spring’s classic AOP programming model isn’t so great. Oh, it was good in its day. But now Spring supports much cleaner and easier ways to work with aspects.
When held up against simple declarative AOP and annotation-based AOP, Spring’s classic AOP seems bulky and overcomplicated. Working directly with ProxyFactory-Bean can be wearying.
So I’ve chosen to not include any discussion of classic Spring AOP in this edition. If you’re really curious about how it works, then you may look at the first two editions of this book. But I think you’ll find that the new Spring AOP models are much easier to work with.
90 CHAPTER 4 Aspect-oriented Spring
environment (IDE) you’d use for your normal Java development. What’s more, the pointcuts that define where advice should be applied are typically written in XML in your Spring configuration file. This means both the aspect’s code and configuration syntax will be familiar to Java developers.
Contrast this with AspectJ. Although AspectJ now supports annotation-based aspects, AspectJ also comes as a language extension to Java. This approach has bene-fits and drawbacks. By having an AOP-specific language, you get more power and fine-grained control, as well as a richer AOP toolset. But you’re required to learn a new tool and syntax to accomplish this.
SPRING ADVISES OBJECTS AT RUNTIME
In Spring, aspects are woven into Spring-managed beans at runtime by wrapping them with a proxy class. As illustrated in figure 4.3, the proxy class poses as the target bean, intercepting advised method calls and forwarding those calls to the target bean.
Between the time when the proxy intercepts the method call and the time when it invokes the target bean’s method, the proxy performs the aspect logic.
Spring doesn’t create a proxied object until that proxied bean is needed by the application. If you’re using an ApplicationContext, the proxied objects will be cre-ated when it loads all of the beans from the BeanFactory. Because Spring creates prox-ies at runtime, you don’t need a special compiler to weave aspects in Spring’s AOP.
SPRING ONLY SUPPORTS METHOD JOIN POINTS
As mentioned earlier, multiple join point models are available through various AOP implementations. Because it’s based on dynamic proxies, Spring only supports method join points. This is in contrast to some other AOP frameworks, such as AspectJ and JBoss, which provide field and constructor join points in addition to method pointcuts. Spring’s lack of field pointcuts prevents you from creating very fine-grained advice, such as intercepting updates to an object’s field. And without constructor pointcuts, there’s no way to apply advice when a bean is instantiated.
Figure 4.3 Spring aspects are implemented as proxies that wrap the target object. The proxy handles method calls, performs additional aspect logic, and then invokes the target method.
91 Selecting join points with pointcuts
But method interception should suit most, if not all, of your needs. If you find yourself in need of more than method interception, you’ll want to complement Spring AOP with AspectJ.
Now you have a general idea of what AOP does and how it’s supported by Spring.
It’s time to get our hands dirty creating aspects in Spring. Let’s start with Spring’s declarative AOP model.
4.2 Selecting join points with pointcuts
As mentioned before, pointcuts are used to pinpoint where an aspect’s advice should be applied. Along with an aspect’s advice, pointcuts are among the most fundamental elements of an aspect. Therefore, it’s important to know how to write pointcuts.
In Spring AOP, pointcuts are defined using AspectJ’s pointcut expression language.
If you’re already familiar with AspectJ, then defining pointcuts in Spring should feel natural. But in case you’re new to AspectJ, this section will serve as a quick lesson on writing AspectJ-style pointcuts. For a more detailed discussion on AspectJ and AspectJ’s pointcut expression language, I strongly recommend Ramnivas Laddad’s AspectJ in Action, Second Edition.
The most important thing to know about AspectJ pointcuts as they pertain to Spring AOP is that Spring only supports a subset of the pointcut designators available in AspectJ. Recall that Spring AOP is proxy-based and certain pointcut expressions aren’t relevant to proxy-based AOP. Table 4.1 lists the AspectJ pointcut designators that are supported in Spring AOP.
Table 4.1 Spring leverages AspectJ’s pointcut expression language for defining Spring aspects.
AspectJ designator Description
args() Limits join point matches to the execution of methods whose arguments are instances of the given types
@args() Limits join point matches to the execution of methods whose arguments are annotated with the given annotation types
execution() Matches join points that are method executions
this() Limits join point matches to those where the bean reference of the AOP proxy is of a given type
target() Limits join point matches to those where the target object is of a given type
target() Limits join point matches to those where the target object is of a given type