Aspect-oriented paradigm is a really cool feature that you can use in your projects. With it you can easily apply additional functionality to your code without modifying the main body of a function.
We start from the gradle configuration file:
As you can see here, we use dynamic versions for gradle, e.g.
4.+. This specifies the placeholder for the latest major version of
4. In addition, we apply an
application plugin, it is really useful if you do not use any IDE. You can just use
gradle run in command line to start the application and that’s it!
First, we create a simple method which takes a number as a string and adds the multiplication symbol to the end of the number.
Probably, you have already mentioned
@AroundMethod annotation. This annotation is used to add new functionality around our method. In addition, there is a
@ChangeParam annotation, we will talk about it a bit later.
Here comes the
This is a common aspect which is applied around a method, there are also many different types of aspects, such as
@After which run before and after a method respectively (what a surprise!). And do not forget to add
@Aspect as a class annotation.
This aspect is applied only to those methods which have
@AroundMethod annotation. Plus, we add this annotation as an argument, so we can address its fields.
We have finished the preparation part. Now lets see what we can do with all of that.
We can get method arguments. Great!
Or method information itself. Much better!
Or even better - extract all annotations of method arguments. Excellent!
Java 8 features
Lets get an argument index. Remember
@ChangeParam annotation? We use java 8 and in that case let me show you some cool features that java provides in a functional way.
annotations is an array of arrays, because for each method argument we may have several annotations.
First, we create an index range:
we need to filter it somehow to get an appropriate index. We apply a filter with a predicate for that:
And as a final point we add
.findFirst(); to get the first argument index which have
This is a functional style to write the code and it is closer to the natural language, write it more and you will get used to it. Just try!
We have got the index. We can change the argument and do whatever we want with it before the function starts. Oh, and how do we actually execute a function?
This runs the function and returns its result. If you want, you can override the result by placing a new result as a return value of our
Lets run an example (source code). http://127.0.0.1:8080/multiply?number=42 if you follow the url you will see the result
(42 * 100), where
( was applied before the method (in the aspect),
* added by the method and
100) after the method (in the aspect), where
100 is the value of
Internal method calls
The next step is a bit tricky. Suppose we want to add another function and call it from
We want the result to be
((42 + 200) * 100) in that case. But what we see is
(42 + * 100). That is not correct! What could go wrong?
Actually, nothing. That is how Spring AOP works. Spring uses proxy to call a function. Then, if you call an internal method you call the exact method bypassing spring, not a proxy you need to. What can we do with that? We need native AspectJ.
To include native AspectJ functionality uncomment those lines in the
Here we get
aspectjweaver library from gradle cache and add it as a
javaagent. Now, try to open the link again.
((42 + 200) * 100). We did it!
As we see, aspect paradigm is indeed a powerful tool. We can build complex systems by using it. It is usually used for logging and method performance testing, but aspects are not limited by this.
The source code is available on github under MIT License.