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.
Here, we will see how to configure a simple Gradle project using Java with such popular frameworks as Spring AOP and AspectJ.
Gradle configuration
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!
Example function
As a starting point we will use Spring Boot. It is an excellent framework with the help of which you can quickly build a test Spring Framework application.
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.
Aspects review
Here comes the @Aspect
time!
This is a common aspect which is applied around a method, there are also many different types of aspects, such as
@Before
and @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 @ChangeParam
annotation.
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 ExampleAspect#process
function.
Try it!
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 @ChangeParam
annotation.
Internal method calls
The next step is a bit tricky. Suppose we want to add another function and call it from multiply
method.
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.
AspectJ config
To include native AspectJ functionality uncomment those lines in the gradle.build
file:
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.
Source code
The source code is available on github under MIT License.