SoFunction
Updated on 2025-04-05

AOP based on Aspectwerkz in Java

  1. AOP programming overview

The mainstream of object-oriented programming technology entering software development has had a huge impact on the way software development is developed. Developers can vividly express the system with a set of entities and the relationship between these entities, which allows them to design larger and more complex systems with a shorter development cycle than before. The only problem with OO development is that it is static in nature, and minor changes in demand can have a significant impact on development progress.

Aspect-Oriented Programming (AOP) is a supplement and improvement to OO technology. It allows developers to dynamically modify static OO models and construct a system that can continue to grow to meet new needs, just like objects in the real world will constantly change themselves during their life cycle, and applications can also have new functions in development.

For example, many people must have had the experience of using Servlets as entry points when developing simple web applications, that is, using Servlets to receive input from HTML forms and return them to the user after processing. The servlet at the beginning may be very simple, with only the minimum amount of code that just meets the user's needs. However, with the implementation of "second requirement", such as the implementation of functions such as exception handling, security, and logging, the size of the code will increase to three or four times the original - the reason why it is called "second requirement" is because the basic function of Servlet is to accept and process user requests. For this goal, mechanisms such as logging and security are not essential.

AOP allows dynamically changing the static model of OO, without having to modify the original static model, and can also add code required to meet the second requirement (in fact, even the original source code is not required). What is even more amazing is that the code added later can often be concentrated in one place, without having to spread the code added later across the entire model like when using OO alone.

2. Basic Terms

Before introducing AOP development examples, let’s first understand several standard AOP terms to better grasp the relevant concepts.

Cross-cutting concern

In the OO model, although most classes have single, specific functions, they usually share a second requirement with other classes. For example, when a thread enters or leaves a method, we may have to record both logs in the data access layer class and in the UI layer class. Although the basic functions of each class are extremely different, the code used to meet the second requirement is basically the same.

Advice

It refers to additional code that you want to apply to an existing model. In this case, it refers to the log code to run when a thread enters or exits a method.

Point-cut

This term refers to an execution point in an application where the previous cross-cutting concern is required. In this example, a Point-cut appears when the thread enters a method, and another Point-cut appears when the thread leaves the method.

Aspect

Point-cut and advice are combined together are called aspect. In the following example, we add a logging aspect by defining a point-cut and giving the appropriate advice.

AOP has many other features and terms, such as introduction, that is, introducing interfaces/methods/domains to existing classes - it greatly broadens the developer's imagination. However, this article only introduces some of the most basic persistence. After familiarizing with the concepts introduced here, you can further study the other features of AOP and see how to use them in your own development environment.

3. Existing framework

Currently, the most mature and most functional AOP framework is AspectJ, which has become the standard for most other frameworks to follow. However, AspectJ has also taken an extraordinary step, and its implementation has added new keywords to the Java language. Although the new syntax is not difficult to learn, it means that we have to change a compiler and reconfigure the editor. Only in this way can we adapt to the new syntax. In larger development groups, these requirements may be difficult to meet because the entire development group will be affected. Due to changes in the language itself, the learning cycle of the development team introducing AOP technology into existing projects was extended.

What we need now is a framework that can be easily introduced without any impact on the original development and construction process. There are more than one framework that meets these requirements, such as JBoss AOP, Nanning, Aspectwerkz (AW). This article uses Aspectwerkz because it is probably the easiest framework to learn and the easiest framework to integrate into existing projects.

Created by Jonas Boner and Alexandre Vasseur, Aspectwerkz is one of the fastest and most feature-rich frameworks available today. Although it lacks certain features of AspectJ, it is enough to meet the needs of most developers in many situations.

One of the most interesting features of Aspectwerkz is its ability to run in two different modes: online mode and offline mode. In online mode, AW directly interferes with the underlying class loading mechanism of JVM, intercepts all class loading requests, and implements instant conversion of bytecode. AW provides many options to interfere with the class loading process, and there is also an encapsulation script that replaces the bin/java command, which can automatically generate a set of runnable configurations based on Java version and JVM capabilities. For developers, online mode has many advantages, it can be inserted into any class loader and generate new classes during class loading. That is, we don't have to manually modify the application's classes, just deploy it the usual way. However, online mode requires additional configuration of the application server, which can sometimes be difficult to meet.

In offline mode, generating a class requires two steps. The first step is to compile with a standard compiler, and the second step is the focus - run the AWcompiler compiler in offline mode and let it handle the newly generated classes. The compiler will modify the bytecode of these classes, insert the advice in the appropriate point-cut according to the definition of an XML file. The advantage of offline mode is that the classes generated by AWcompiler can run on any virtual machine with JVM 1.3 or above. This is the mode you will use in this article because it does not require any modifications to Tomcat. You can copy them to most existing projects with a slight modification to the construction process.

4. Installation

This article will take a simple web application as an example, which is compiled with Ant and deployed on Tomcat 4+ Servlet containers. Below we assume that the reader has prepared the above environment, including JVM 1.3+, and Tomcat is set to automatically deploy applications from the webapps folder and automatically extend the WAR to the directory (this is Tomcat's default operation method, so as long as you have not modified the operation method of Tomcat, the following example can be run directly). We will call Tomcat's installation location %TOMCAT_HOME%.

⑴ Download Aspectwerkz from/to unzip the compression into the appropriate position. We will call this position %ASPECTWERKZ_HOME%.

⑵ Set the %ASPECTWERKZ_HOME% environment variable.

⑶ Add Aspectwerkz to the PATH environment variable, that is, set PATH=%PATH%;%ASPECTWERKZ_HOME%inaspectwerkz

⑷ Download the demonstration program of this article and put it into the %TOMCAT_HOME%webapps folder.

⑸ Add Aspectwerkz's runtime class to Tomcat's classpath. You can put its JAR file into the WEB-INFlib folder of the sample application, or %TOMCAT_HOME%commonlib.

    5. Compile sample application

If you want to dig into the sample application in this article, you can untie the WAR file to extract its contents. You will find that there is a file in the root directory, which will be copied to the WEB-INF/classes directory when constructing the application. The source files of Servlet and advice are in the WEB-INF/src directory, and there is also an ANT script to build these classes.

Before running this sample program, you also need to post-compile it. Here are the specific operation steps:

⑴ In the command line window, go to the directory where you unwrap the WAR file.

⑵ Enter the following command to call the AW compiler: aspectwerkz -offline WEB-INF/classes -cp %TOMCAT_HOME%. If the later compilation is successfully passed, you should see the following output:

( 1 s )

SUCCESS: WEB-INFclasses

There is an ANT task named war in the build file, which you can use to recreate the WAR file.

6. Run the sample application

First start (or restart) Tomcat, and then open http://localhost:8080/demo/ in your browser.

After the page is opened, you can see an HTML form with two input boxes, one enters a name and the other enters an email address. Enter some data, then click the button to submit the form, and a page appears showing the contact information and a link to the contact list.

7. Code analysis

The JSP page will not be analyzed, and we are not interested in it now. Let's take a look at the code of AOPServlet.

package example;

import .*;
import .*;
import .*;
public class AOPServlet extends HttpServlet {
 public void doGet(HttpServletRequest request, HttpServletResponse response)
 throws ServletException, IOException {
Person person = new Person();
if (("name") != null) {
 (
 ("name"));
}
if (("email") != null) {
 (
 ("email"));
}
("person", person);
RequestDispatcher rd =("/");
(request, response);
 }
}

In this example, the Servlet code has been as simple as possible and only contains some essential code, such as creating an object that binds the request parameters, etc., but there is no persistence operation and no additional imports are required. It only implements the most basic operations that must be implemented by the Servlet.

However, according to the documentation requirements, this application must persist all Person type objects, so add an aspect to this application. To create this aspect, we first need to create a file and put the file into the directory specified by classpath. This article provides a simple example that you can open and view with an editor.

The first part of the app defines available advices, and we can add as many advices as needed:

<advice-def name="persist" class="" deployment-model="perJVM"/>

In this snippet, we define an advice named persist, whose type is. The last property defines the exclusiveness of the advice, where its value is perJVM, which means that only one instance of the advice is created in each JVM (see Aspectwerkz's documentation for more descriptions of the deployment pattern.

The second part starts to define aspect, here is where we map advice to point-cut to create aspect.

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

Let's analyze this code line by line:

⑴ We created an aspect called servlet. If necessary, we can create any number of aspects.

⑵ In the second line, we create a point-cut called all, which only works for methods (type="method").

⑶ In the third line, we use a regular expression to specify where to apply advice. In this example, we point out that the condition for applying advice is: regardless of the type of return value (the first "*"), the name ends with a servlet (*servlet) and contains a class in the example package with a doGet method (doGet(..)) with arbitrary parameters.

⑷ In line 4, we tell the Aspectwerkz compiler to apply the subsequent advice to all point-cuts.

⑸ Here we declare that the advice to be used is persist.

Now that we know how to map point-cut and advice to create an aspect, let’s take a look at an instance of a class that provides advice. In the mapping file, we register a type of advice, and the following is the source code of that type:

package example;

import .*;
import .*;
import .*;

public class PersistenceAdvice extends AroundAdvice {
 public PersistenceAdvice() {
super();
 }
 public Object execute(final JoinPoint joinPoint)
 throws Throwable {
MethodJoinPoint jp =(MethodJoinPoint) joinPoint;
final Object result = ();
Object[] parameters = ();
if (parameters[0] instanceof HttpServletRequest) {
 HttpServletRequest request =(HttpServletRequest) parameters[0];
 if (("person") != null) {
Person contact =(Person) ("person");
ContactManager persistent = new ContactManager();
String fileName =(("/")+"");
(contact, fileName);
 }
}
return result;
 }
}


The first line of the execute() method is easy to understand, which is to try to shape it into the most specific type, and the second line may be the most important: because we want to run the method and check the results, we must call process(). In the next part, we capture the HttpServletRequest and extract the object placed by the Servlet (remember, the doGet() method has ended at this time).

Finally, we create a class named ContactManager, which functions to save Person's data to a text file. In fact, it is also very convenient to save data to XML files, databases or other persistent storage mechanisms.

One thing you need to master here is that in the stage of designing applications or building prototypes, Servlets do not know what changes will happen in the future. The functions of the second stage can be added at any time. Because of this, we say that applications can learn new abilities during the development process, and it is very convenient to add new functions in the future.

【Conclusion】 In the previous example, we experimented with a simple application, deployed it to Tomcat, and ran and tested its functionality with a browser. Although this application itself has no practical purpose, it demonstrates and confirms some very useful concepts. Imagine that you will be able to quickly build prototypes and then introduce Cross-cutting concerns like security, logging, persistence, buffering, etc. No matter how large the original app is, you will be able to easily add logging to the entire app in ten minutes!

Hopefully you can go beyond the simple examples of this article and see how to adopt AOP technology in your own projects. It certainly takes some time to get familiar with the concept of AOP, but it will certainly pay off, and for a medium-sized project it will save you weeks or write thousands of lines of duplicate code less.