Spring AOP Tutorial With Examples

DZone 's Guide to

Spring AOP Tutorial With Examples

Here's everything you need to know about Spring AOP.

· Java Zone ·
Free Resource

leaf with waterdroplets

Here's everything you need to know about Spring AOP.

You may have heard of aspect-oriented programming, or AOP, before. Or maybe you haven't heard about it but have come across it through a Google-search rabbit hole? You probably do use Spring, however. So you're probably curious how to apply AOP to your Spring application.

You may also like: Overview of Spring Aspect-Oriented Programming

In this article, I'll show you what AOP is and break down its key concepts with some simple examples. We'll touch on why it can be a powerful way of programming and then go into a contrived, but plausible, example of how to apply it in Spring. All examples will be within a Spring application and written in JVM Kotlin, mainly because Kotlin is one of my favorite useful languages.

Introduction to AOP

"Aspect-oriented programming" is a curious name. It comes from the fact that we're adding new aspects to existing classes. It's an evolution of the decorator design pattern. A decorator is something you hand-code before compiling, using interfaces or base classes to enhance an existing component. That's all nice and good, but aspect-oriented programming takes this to another level. AOP lets you enhance classes with much greater flexibility than the traditional decorator pattern. You can even do it with third-party code.

Components of Spring AOP

In AOP, you have a few key parts:

Core Component

This is the class or function you want to alter. In Spring AOP, we're always altering a function. For example, we may have the following command:

class PerformACommand {
    fun execute(input: String): String {
        return "this is a result for $input"


This is the new logic you want to add to the existing class, method, sets of classes, or sets of methods. A simple example is adding log messages to the execution of certain functions:

class LoggingAspect {

    fun logMethod(joinPoint: ProceedingJoinPoint) {
        var output = joinPoint.proceed()
        println("method '${joinPoint.signature}' was called with input '${joinPoint.args.first()}' and output '$output'")


OK, now the terms get weird. A JoinPoint is a place within the core component that we’ll be adding an aspect. I’m putting this term here mainly because you’ll see it a lot when researching AOP. But for Spring AOP, the JoinPoint is always a function execution. In this example, it will be any function with an @Logged annotation: 



The pointcut is the logic by which an aspect knows to intercept and decorate the JoinPoint. Spring has a few annotations to represent these, but by far, the most popular and powerful one is @Around. In this example, the aspect is looking for the annotation "Logged" on any functions. 

If you wire the example code up to a Spring application and run:


You'll see something like this in your console:

"method 'String com.example.aop.PerformACommand.execute(String)' was called with input 'whatever' and output 'this is a result for whatever' "

Spring AOP can achieve this seeming magic by scanning the components in its ApplicationContext and dynamically generating code behind the scenes. In AOP terms, this is called "weaving."

Why AOP Is Useful

With that explanation and examples providing understanding, let's move on to the favorite part for any programmer. That's the question of "why?" We love this question as developers. We're knowledge workers who want to solve problems, not take orders. So, what problems does AOP solve in Spring? What goals does it help one achieve?

Quick Code Reuse

For one thing, adding aspects lets me reuse code across many, many classes. I don't even have to touch much of my existing code. With a simple annotation like "Logged," I can enhance numerous classes without repeating that exact logging logic.

Although I could inject a logging method into all these classes, AOP lets me do this without significantly altering them. This means I can add aspects to my code in large swaths quickly and safely.

Dealing With Third-Party Code

Let's say normally I want to inject shared behavior into a function that I then use in my core components. If my code is proved by a third-party library or framework, I can't do that! I can't alter the third-party code's behavior. Even if they're open source, it'll still take time to understand and change the right places. With AOP, I just decorate the needed behavior without touching the third-party code at all. I'll show you exactly how to do that in Spring with the blog translator example below.

Cross-Cutting Concerns

You'll hear the term "cross-cutting concerns" a lot when researching AOP. This is where it shines. Applying AOP lets you stringently use the single-responsibility principle. You can surgically slice out the pieces of your core components that aren't connected to its main behavior: authentication, logging, tracing, error handling, and the like. Your core components will be much more readable and changeable as a result.

Example: A Blog Translator

Although I showed snippets of a logging aspect earlier, I want to walk through how we might think through a more complex problem we might have, and how we can apply Spring AOP to solve it.

As a blog author, imagine if you had a tool that would automatically check your grammar for you and alter your text, even as you write! You download this library and it works like a charm. It checks grammar differently based on what part of the blog post you're on: introduction, main body, or conclusion. It heavily encourages you to have all three sections in any blog post.

You're humming along, cranking out some amazing blog posts, when a client commissions a request: can you start translating your blogs to German to reach our German audience better? So you scratch your head and do some research. You stumble upon a great library that lets you translate written text easily. You tell the client, "Yes, I can do that!" But now, you have to figure out how to wire it into your grammar-checking library. You decide this will be a great case to try out Spring AOP to combine your grammar tool with this translation library.

Wiring It Up

First, we want to add the Spring AOP dependency to our Spring Boot project. We have a "build.gradle" file to put this into:

dependencies {

Analyzing Our Core Components

Before we implement anything, we take a close look at our tool codebase. We see that we have three main components, one for each section of a blog post:

class IntroductionGrammarChecker {
    fun check(input: BlogText): BlogText {

class MainContentGrammarChecker {

    fun check(input: BlogText): BlogText {

class ConclusionGrammarChecker {
    fun check(input: BlogText, author: Author): BlogText {

Hmm... it looks like each one produces the same output: a BlogText. We want to alter the output of each of these checkers to produce German text instead of English. Looking closer, we can see that they all share the same signature. Let's keep that in mind when we figure out our pointcut.

The Core Logic

Next, let's bang out the core logic of our aspect. It'll take the output of our core component, send it through our translator library, and return that translated text:

class TranslatorAspect(val translator: Translator) {

    @Around("execution(BlogText check(BlogText))")
    fun around(joinPoint: ProceedingJoinPoint): BlogText {
        val preTranslatedText = joinPoint.proceed() as BlogText
        val translatedText = translator.translate(preTranslatedText.text, Language.GERMAN)
        return BlogText(translatedText)

Note a few things here. First, we annotate it with @Aspect . This cues Spring AOP in to treat it appropriately. The @Component annotation Spring Boot will see it in the first place.

We also use the @Around pointcut, telling it to apply this aspect to all classes that have a method signature of  check(BlogText): BlogText. There are numerous different expressions we can write here. I could've used an annotation, like the @Loggedabove, but this way, I don't have to touch the existing code at all! Very useful if you're dealing with third-party code that you can't alter.

The method signature of our aspect always takes in a ProceedingJoinPoint, which has all the info we need to run our aspect. It also contains a proceed() method, which will execute the inner component's function. Inside the function, we proceed with the core component, grabbing its output and running it through the translator, just as we planned. We return it from the aspect, with anything that uses it being none the wiser that we just translated our text to German.

A Trace of Something Familiar

Now that you're familiar with Spring AOP, you may notice something about the @Logged annotation. If you've ever used custom instrumentation for Java in Retrace, you may notice it looks a lot like the @Trace annotation.

The similarity of @Logged to @Trace is not by coincidence. @Trace is a pointcut! Although Retrace does not use spring AOP per se, it does apply many AOP principles into how it lets you configure instrumentation.

The Final Aspect

We've only touched the surface of AOP in Spring here, but I hope you can still see its power. Spring AOP gives a nonintrusive way of altering our components, even if we don't own the code for that component!

With this, we can follow the principles of code reuse. We can also implement wide-sweeping, cross-cutting concerns with just a few lines of code. So, find a place in your Spring application where this can bring value. I highly recommend starting with something like @Logged or  @Trace, so you can easily measure and improve your system performance.

Further Reading

Overview of Spring Aspect-Oriented Programming

Handling Exceptions Using Spring's AOP

Implementing AOP With Spring Boot and AspectJ

java ,spring ,aop ,aspect-oriented programming ,spring aop ,tutorial

Published at DZone with permission of Mark Henke , DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}