In previous tutorials about introducing aspect oriented programming and compiling-time weaving with AspectJ, I introduced you all to the @Before annotation and @After annotation to insert the code before and after when our application call to a method of an object. They are the Advice. In addition to @Before annotation and @After annotation, we also have other Advice like @AfterReturn annotation, @AfterThrowing annotation, and @Around annotation. In this tutorial, I will introduce you all more about the @Before annotation then you can have a better understanding, know when to use it.
First, I will also create a new project as an example:
AspectJ dependency:
1 2 3 4 5 |
<dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjrt</artifactId> <version>1.8.13</version> </dependency> |
I will run the example using compile-time weaving, so I will declare the plugin aspectj-maven-plugin as follows:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
<plugin> <groupId>org.codehaus.mojo</groupId> <artifactId>aspectj-maven-plugin</artifactId> <version>1.10</version> <configuration> <source>1.8</source> <target>1.8</target> </configuration> <executions> <execution> <goals> <goal>compile</goal> </goals> <configuration> <complianceLevel>1.8</complianceLevel> </configuration> </execution> </executions> </plugin> |
Class need insert code:
1 2 3 4 5 6 7 8 |
package com.huongdanjava.aspectj; public class HelloWorld { public void hello() { System.out.println("Hello"); } } |
Application class:
1 2 3 4 5 6 7 8 9 |
package com.huongdanjava.aspectj; public class Application { public static void main(String[] args) { HelloWorld hello = new HelloWorld(); hello.hello(); } } |
Now, we will define a class to insert the code which we want before the HelloWorld object ‘s hello() method using the AspectJ’s @Before annotation.
HelloWorldAspect class has the following contents:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
package com.huongdanjava.aspectj; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; @Aspect public class HelloWorldAspect { @Before("execution (* com.huongdanjava.aspectj.HelloWorld.hello(..))") public void allMethods() { System.out.println("Hello"); } } |
Here, I have defined a method in the HelloWorldAspect class named allMethods() with the @Before annotation. The content of the @Before annotation is as follows:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 |
/******************************************************************************* * Copyright (c) 2005 Contributors. * All rights reserved. * This program and the accompanying materials are made available * under the terms of the Eclipse Public License v1.0 * which accompanies this distribution and is available at * http://eclipse.org/legal/epl-v10.html * * Contributors: * initial implementation Alexandre Vasseur *******************************************************************************/ package org.aspectj.lang.annotation; import java.lang.annotation.Target; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; /** * Before advice * * @author <a href="mailto:alex AT gnilux DOT com">Alexandre Vasseur</a> */ @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) public @interface Before { /** * The pointcut expression where to bind the advice */ String value(); /** * When compiling without debug info, or when interpreting pointcuts at runtime, * the names of any arguments used in the advice declaration are not available. * Under these circumstances only, it is necessary to provide the arg names in * the annotation - these MUST duplicate the names used in the annotated method. * Format is a simple comma-separated list. */ String argNames() default ""; } |
As you can see, @Before annotation defines two attributes: value and argNames where argNames is optional. The value attribute is the most important attribute, it defines a Pointcut, which helps us to define exactly where we want to insert the code.
We can define a Pointcut using a Combinator along with a Pattern expression.
A Pattern expression is defined by the following elements:
1 |
[modifiers] [return type] [(packageName)(className)(methodName)](parameters) |
All of these elements can be declared with “*” meaning any value.
Inside:
- modifiers: defines the access modifier of the method to which we want to insert the code. We can leave it blank, it has the same meaning as the “*” value.
- return type: void or any type of data of the method which we need to insert code, return.
- (packageName) (className) (methodName): Define the method which we want to insert the code. In my example, since I was trying to insert code before the HelloWorld object’s hello() method then I defined com.huongdanjava.aspectj.HelloWorld.hello. You can also replace it with com.huongdanjava.aspectj.HelloWorld.* to insert code for all methods in the HelloWorld object.
- parameters: Define the method with the parameter we need to insert the code. We can use (..) to specify a method with any parameter.
In the above components, each component acts as a criterion to specify the location where we want to insert the code.
The Combinator defines when our code needs to be inserted, after the pattern has been satisfied, is executed. AspectJ defines a list of combinators that you can use for your purposes, here. Each combinator can be defined with different patterns, allowing us to define when the code we need to insert should be executed.
As above example, we use the “execution” combinator to execute the code when the program calls to methods in the HelloWorld object.
The result when we run the above example is as follows:
To get all the information about the method we are inserting the code, you can use the JoinPoint object as an argument in the method defined with the @Before annotation as follows:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
package com.huongdanjava.aspectj; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; @Aspect public class HelloWorldAspect { @Before("execution (* com.huongdanjava.aspectj.HelloWorld.hello(..))") public void allMethods(JoinPoint joinPoint) { System.out.println("Hello, method name: " + joinPoint.getSignature().getName()); } } |
In the code above, I used the JoinPoint object to get the name of the method being executed.
Result:
Using JoinPoint we can do many other things, we will learn more about it when discussing the other Advice.