Está en la página 1de 8

ONJava.

com: Introduction to Aspect-Oriented Programming

Published on ONJava.com (http://www.onjava.com/)


http://www.onjava.com/pub/a/onjava/2004/01/14/aop.html
See this if you're having trouble printing code examples

Introduction to Aspect-Oriented Programming

by Graham O'Regan
01/14/2004

Overview of Aspect Oriented Programming

When Object-Oriented (OO) programming entered the mainstream of software development, it had a
dramatic effect on how software was developed. Developers could visualize systems as groups of
entities and the interaction between those entities, which allowed them to tackle larger, more
complicated systems and develop them in less time than ever before. The only problem with OO
programming is that it is essentially static, and a change in requirements can have a profound impact
on development timelines.

Aspect-Oriented Programming (AOP) complements OO programming by allowing the developer to


dynamically modify the static OO model to create a system that can grow to meet new requirements.
Just as objects in the real world can change their states during their lifecycles, an application can
adopt new characteristics as it develops.

Consider an example: many of you have developed simple web applications that use servlets as the
entry point, where a servlet accepts the values of a HTML form, binds them to an object, passes them
into the application to be processed, and then returns a response to the user. The first cut of the servlet
may be very simple, with only the minimum amount of code required to fulfill the use case being
modeled. The code, however, often inflates to three to four times its original size by the time
secondary requirements such as exception handling, security, and logging have been implemented. I
use the term "secondary requirements" because a servlet should not need to know about the logging
or security mechanisms being used; its primary function is to accept input and process it.

AOP allows us to dynamically modify our static model to include the code required to fulfill the
secondary requirements without having to modify the original static model (in fact, we don't even
need to have the original code). Better still, we can often keep this additional code in a single location
rather than having to scatter it across the existing model, as we would have to if we were using OO
on its own.

http://www.onjava.com/lpt/a/4448 (1 of 8)19/07/2004 8:53:42


ONJava.com: Introduction to Aspect-Oriented Programming

In this article, we will look at a simple application that will hopefully allow
you to see the benefits of AOP firsthand, and then we will briefly discuss
how AOP could be used in your existing projects.

Terminology

Before we delve too deeply into AOP, let's introduce some standard
terminology to help us understand the concepts.

1. Cross-cutting concerns: Even though most classes in an OO model


will perform a single, specific function, they often share common,
secondary requirements with other classes. For example, we may
want to add logging to classes within the data-access layer and also to
classes in the UI layer whenever a thread enters or exits a method.
Even though the primary functionality of each class is very different, the code needed to
perform the secondary functionality is often identical.

2. Advice: This is the additional code that you want to apply to your existing model. In our
example, this is the logging code that we want to apply whenever the thread enters or exits a
method.

3. Point-cut: This is the term given to the point of execution in the application at which cross-
cutting concern needs to be applied. In our example, a point-cut is reached when the thread
enters a method, and another point-cut is reached when the thread exits the method.

4. Aspect: The combination of the point-cut and the advice is termed an aspect. In the example
below, we add a logging aspect to our application by defining a point-cut and giving the
correct advice.

There are many other facets of AOP, such as introductions (where interfaces/methods/fields can be
added to existing classes), that hold tremendous potential for developers, but I'll stick with some of
simpler facets in this article. When you are familiar with the concepts presented here, I would
recommend that you continue to investigate AOP and see how the other facets may be of use to you
in your development environment.

Existing Frameworks

Probably the most mature and fully featured framework available today is AspectJ. While AspectJ
sets the standard that most frameworks follow, the architects took the unusual step of adding new
keywords to the Java language in their implementation. Though the new syntax isn't too difficult to
learn, it does mean that you will have to change your compiler, and potentially reconfigure your
editor, in order to use the new syntax. In a large team this may not be feasible, as the whole team
could be affected. The modification to the language also increases the learning curve for teams
looking to introduce AOP into existing projects.

http://www.onjava.com/lpt/a/4448 (2 of 8)19/07/2004 8:53:42


ONJava.com: Introduction to Aspect-Oriented Programming

What we need is a framework that can be easily introduced without severely impacting the existing
development and build process. There are several frameworks that fit the bill, such as JBoss AOP,
Nanning, and Aspectwerkz (AW). For this article, I've chosen Aspectwerkz because it is probably the
easiest framework to learn and integrate into your existing projects.

Aspectwerkz, created by Jonas Boner and Alexandre Vasseur, remains one of the quickest and most
fully featured AOP frameworks available. While it may not boast all of the features of AspectJ, it is
sufficiently complete to be of great use to most developers in many situations.

One of the most interesting features of Aspectwerkz is its ability to run in two different modes: online
and offline. In online mode, AW is hooked into the low-level classloading mechanism part of the
JVM, allowing it to intercept all classloading calls and transform the bytecode on the fly. AW
provides many options to hook in, and a wrapper script can be used as a replacement for the bin/
java command to automatically detect and set a working configuration depending on the Java
version and JVM capabilities. This mode holds many benefits to developers, as it can be hooked into
any classloader and weave classes at classload time, which means that your class files are not
modified manually, but deployed as usual. However, it does require additional configuration of your
application server, which may not be possible in some situations.

In offline mode, two phases are required to generate your classes. The first phase is the standard
compilation using the javac tool that we all know and love. (In fact, most of us love it so much that
we replaced it with an Ant task years ago.) The second phase is where things get interesting, we run
the AWcompiler in offline mode and point it to the newly created class files. The compiler will then
modify the bytecode of the classes to include your advice at the correct point-cuts, as defined in an
XML file. The benefit of using the offline mode is that the classes will run in any JVM from version
1.3 and up. This is the mode that I will use in this article, as it requires no modifications to Tomcat
and could be applied to most existing projects with only slight modification to the build process.

Installing

In this article, we are going to write look at a simple application, compile it using Ant, and deploy it
on a Tomcat 4+ servlet container. I am going to assume that you have already installed the above,
along with a JVM 1.3+, and that your Tomcat installation is set to deploy applications from the
webapps folder automatically and expand the WAR files into directories (this is the default behavior,
so if you haven't modified Tomcat, this application should work out of the box). We will refer to the
location where Tomcat is installed as %TOMCAT_HOME%.

1. Download Aspectwerkz from its web site and extract the compressed file to your preferred
location. We'll refer to this location as %ASPECTWERKZ_HOME%.

2. Set the %ASPECTWERKZ_HOME% environment variable.

http://www.onjava.com/lpt/a/4448 (3 of 8)19/07/2004 8:53:42


ONJava.com: Introduction to Aspect-Oriented Programming

3. Add the Aspectwerkz compiler to your PATH environment variable; i.e., set PATH=%PATH
%;%ASPECTWERKZ_HOME%\bin\aspectwerkz.

4. Download the sample application that accompanies this article and drop it into your %
TOMCAT_HOME%\webapps folder

.
5. Add the Aspectwerkz runtime classes to Tomcat's classpath. You could drop the JAR files
from %ASPECTWERKZ_HOME%\lib into the WEB-INF\lib folder of the sample application,
or into %TOMCAT_HOME%\common\lib.

Compiling the Sample Application

If you want to play with this demo application yourself, extract the contents of the sample
application's WAR file. You'll find the aspectwerkz.xml file in the root of the directory, which gets
copied to the WEB-INF/classes directory when the application is built. The source files of the servlet
and advice classes are in WEB-INF/src; I've included an Ant script that will build these classes for
you.

Before you can see the demo in action, you will have to complete the post-compilation phase, too,
and here's how:

1. Navigate on the command line to the directory where you extracted the WAR file.
2. Type the following command to invoke the AW compiler (all on one line):

aspectwerkz -offline aspectwerkz.xml WEB-INF/classes


-cp %TOMCAT_HOME%\common\lib\servlet.jar

You should see the following if the post-compilation completes successfully:

( 1 s )
SUCCESS: WEB-INF\classes

There is an Ant task in the build file called war that you can use to recreate the WAR file.

Running the Sample Application

1. (Re)start Tomcat.
2. Open http://localhost:8080/demo/ in a browser.

http://www.onjava.com/lpt/a/4448 (4 of 8)19/07/2004 8:53:42


ONJava.com: Introduction to Aspect-Oriented Programming

When you open your browser, you will see a standard HTML form with two fields: one for the name
and one for email address of the contact. Enter some details and press submit, and you will see the
contacts details displayed and a link to a file that contains a simple contact list. OK, so the demo isn't
going to set the world on fire, but let's take a look under the hood and see what has really happened.

Code Walkthrough

Let's ignore the JSP files, as they there are of very little interest to us right now. Instead, have a look
at the code of AOPServlet.

package example;

import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
public class AOPServlet extends HttpServlet {
public void doGet(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {
Person person = new Person();
if (request.getParameter("name") != null) {
person.setName(
request.getParameter("name"));
}
if (request.getParameter("email") != null) {
person.setEmail(
request.getParameter("email"));
}
request.setAttribute("person", person);
RequestDispatcher rd =
request.getRequestDispatcher("/view.jsp");
rd.forward(request, response);
}
}

In this example, you'll notice that the servlet code is very minimal; it only contains enough code to
create an object to bind the request parameters to, and then it passes the object along in the request.
There is no persistence code, no additional imports; it simply does what it meant to do.

But our design document stipulates that we must persist all objects of type Person in our
application, so we will need to add an aspect to the application. To create an aspect, we first have to
create a file called aspectwerkz.xml and place that file in the classpath. I've include a simple example
in the sample application that you can open in your favorite editor; I'll explain what it is doing.

http://www.onjava.com/lpt/a/4448 (5 of 8)19/07/2004 8:53:42


ONJava.com: Introduction to Aspect-Oriented Programming

The first section defines the different advices that are available to us. We can add as many different
advice definitions as we like:

<advice-def name="persist" class="example.PersistenceAdvice"


deployment-model="perJVM"/>

In this snippet, we define a piece of advice called persist, which is of type example.
PersistenceAdvice. The last attribute defines the exclusivity of this advice; in this case, it's set
to perJVM, which means that only one instance of this advice will be created in each JVM. (See the
Aspectwerkz documentation for more information about deployment models.)

The next section defines our aspects. This is where we map our advice to a point-cut to create an
aspect.

<aspect name="servlet">
<pointcut-def name="all" type="method"
pattern="* example.*Servlet.doGet(..)"/>
<bind-advice pointcut="all">
<advice-ref name="persist"/>
</bind-advice>
</aspect>

Let's step through this section line by line:

1. We are creating an aspect called servlet; we can create as many aspects as we require.

2. On the second line, we are creating a point-cut called all that will only be applied to methods
(type="method").

3. The third line is where we define, using a regular expression, where we want the advice to be
given. In this example, we are stating that we want to apply the advice, regardless of the return
type (the first *), to any class in the example package whose name ends with
"Servlet" (*Servlet) that contains a method called doGet with any parameter list
(doGet(..)).

4. On the fourth line, we tell the Aspectwerkz compiler that we want to apply the following
advice to the all point-cut.

5. Here we are saying that we want to use the persist advice.

Now that we know how to map point-cuts and advice to create aspects, let's look at an example of a

http://www.onjava.com/lpt/a/4448 (6 of 8)19/07/2004 8:53:42


ONJava.com: Introduction to Aspect-Oriented Programming

class that provides advice. In our mapping file, we registered an advice of type example.
PersistenceAdvice. Here is the source of that file:

package example;

import javax.servlet.http.*;
import org.codehaus.aspectwerkz.advice.*;
import org.codehaus.aspectwerkz.joinpoint.*;

public class PersistenceAdvice extends AroundAdvice {


public PersistenceAdvice() {
super();
}
public Object execute(final JoinPoint joinPoint)
throws Throwable {
MethodJoinPoint jp =
(MethodJoinPoint) joinPoint;
final Object result = joinPoint.proceed();
Object[] parameters = jp.getParameters();
if (parameters[0] instanceof HttpServletRequest) {
HttpServletRequest request =
(HttpServletRequest) parameters[0];
if (request.getAttribute("person") != null) {
Person contact =
(Person) request.getAttribute("person");
ContactManager persistent =
new ContactManager();
String fileName =
(request.getRealPath("/")+
"contacts.txt");
persistent.save(contact, fileName);
}
}
return result;
}
}

The first line of this method is self-explanatory: we simply cast to the most specific type we can. The
second line is probably the most important: since we want to fire the method and then look at the
result, we must call proceed(), which allows the method to complete. In the next section, we are
capturing the HttpServletRequest and retrieving the object that is placed in request scope by
the servlet (remember, the doGet() method has finished at this point).

Finally, we create a class called ContactManager that persists the person's details to a text file.

http://www.onjava.com/lpt/a/4448 (7 of 8)19/07/2004 8:53:42


ONJava.com: Introduction to Aspect-Oriented Programming

This class could just as easily save the details to an XML file, a database, or another persistent store.
The point to take away is that the servlet has no idea what will happen to the bean when you design/
prototype the application; the secondary functionality can be added at any point in the future. This is
what I mean when I say that your basic application can learn new behavior as it grows, and adding
additional functionality at a later date is trivial.

Where Next?

In the example in the previous section we took a very basic application, deployed it to Tomcat, and
ran it in a browser to test the functionality. While the application as it stands isn't very useful, the
principles that it demonstrates are very powerful indeed. Imagine being able to quickly prototype
functionality and then apply the cross-cutting concerns such as security, logging, persistence, and
caching when you've finished. You could feasibly add logging to a whole application, regardless of
the number of lines of code, in less than ten minutes!

I hope this you can see beyond the simplicity of this application and see where you can use AOP in
your projects. While there might be a reasonably steep curve to overcome to familiarize yourself with
the concepts behind AOP, it will definitely pay off, cutting weeks and probably thousands of lines of
repetitive code from the average project.

Graham O'Regan is a senior developer with European Technology Consultants (ETC) in London.

Return to ONJava.com.

Copyright 2004 O'Reilly Media, Inc.

http://www.onjava.com/lpt/a/4448 (8 of 8)19/07/2004 8:53:42

También podría gustarte