- Lab
- Core Tech

Guided: Spring Certified Professional - Aspect-oriented Programming (AOP) in Spring
This code lab will teach you how to leverage Spring Aspect-Oriented Programming (AOP) to cleanly address cross-cutting concerns like logging, validation, and performance monitoring. You'll gain practical experience implementing aspects, pointcuts, and many advice types using Spring annotations. By the end of this lab, you'll have the skills to build more modular and maintainable Spring applications by effectively separating cross-cutting concerns from core business functionality.

Path Info
Table of Contents
-
Challenge
Introduction
Welcome to the lab Guided: Spring Certified Professional - Aspect-oriented Programming (AOP) in Spring.
In this lab, you will learn how to use Spring AOP to address cross-cutting concerns in your applications. Cross-cutting concerns are functionalities like logging, security, transaction management, and monitoring that affect multiple parts of an application but are not part of the core business logic.
AOP allows you to modularize these concerns into separate units called Aspects. This helps keep your main business logic clean and focused, making the code easier to maintain and understand.
You will work with a simple restaurant order management system. The initial codebase includes basic services for placing orders and managing inventory and notifications. Throughout this lab, you will enhance this application by implementing various AOP aspects without modifying the core service classes. ---
Familiarizing with the Program Structure
The application includes the following classes in the
src/main/java
directory:Main
: This is the entry point of the application. It simulates placing and updating orders using theOrderService
.AppConfig
: This Spring configuration class enables AOP and defines the necessary beans for services and aspects.com.restaurant.service
: This package contains the core business logic services:OrderService
: Handles placing, updating, and cancelling orders. You will target methods in this class with your aspects.InventoryService
: Manages item inventory.NotificationService
: Sends notifications (e.g., to the kitchen or manager).
com.restaurant.model
: This package contains the data model classes likeOrder
,MenuItem
, andUser
.com.restaurant.aspect
: This is where you will spend most of your time. This package contains the Aspect classes you'll modify:OrderLoggingAspect
OrderNotificationAspect
InventoryAspect
ValidationAspect
ComplexPointcutAspect
PerformanceMonitoringAspect
The goal is to implement logging, notifications, inventory updates, validation, and performance monitoring using AOP concepts like
Pointcut
,Advice
(Before
,After
,AfterReturning
,AfterThrowing
,Around
), andJoinPoint
.You can compile and run the application using the Run button. Initially, the application will compile but won't work correctly until you complete the configuration.
Begin by examining the code to understand the program's structure. Once you're ready, start implementing the aspects step by step.
info> If you need help, a
solution
directory is available for reference, containing subdirectories for each step with solution files following the naming convention[step]-[task]-[file].java
(e.g.,2-1-OrderLoggingAspect.java
in thestep2
directory). -
Challenge
Understanding AOP and Creating Your First Aspect
Aspect-Oriented Programming (AOP) helps you separate cross-cutting concerns from your main business logic. In Spring AOP, the core concepts are aspects, pointcuts, and advices.
Aspects
An aspect is a module that encapsulates a specific cross-cutting concern. For example, you can have an aspect dedicated just for logging and another one just for security checks. In Spring, you define an aspect by annotating a class with
@Aspect
. Since aspects often need to be managed by the Spring container, you usually also annotate them with@Component
or define them as beans in your configuration:import org.aspectj.lang.annotation.Aspect; import org.springframework.stereotype.Component; @Aspect @Component public class LoggingAspect { // Advice and Pointcuts go here }
Pointcuts
A pointcut is an expression that selects specific points in the execution of your application, called join points. A join point could be a method call, method execution, or even field access. Pointcuts determine where an aspect's logic should be applied.
You define a pointcut using the
@Pointcut
annotation on a method within your aspect class. The annotation value contains an expression language (AspectJ pointcut expression language) to specify the target join points. For instance, you can target all methods within a specific service class or methods with a particular name pattern:import org.aspectj.lang.annotation.Pointcut; // Inside the @Aspect class @Pointcut("execution(* com.example.service.MyService.*(..))") public void serviceMethods() {}
The above example defines a pointcut named
serviceMethods
. This method is meant to be empty. Spring never invokes the body of a@Pointcut
method, it only reads the annotation's value, which in this case, targets the execution (execution(...)
) of any method (*
) in thecom.example.service.MyService
class, regardless of its parameters ((..)
).Advice
An advice is the action taken by an aspect at a particular join point selected by a pointcut. Spring AOP supports several types of advice:
@Before
: Runs before the join point method executes.@After
: Runs after the join point method completes, regardless of whether it finished normally or threw an exception.@AfterReturning
: Runs after the join point method completes successfully (returns a value).@AfterThrowing
: Runs after the join point method throws an exception.@Around
: Wraps around the join point method execution, allowing actions before and after, and even controlling whether the original method proceeds.
@Before
Advice andJoinPoint
The
@Before
advice is useful for tasks like logging entry into a method or performing pre-checks. You associate the advice with a pointcut:import org.aspectj.lang.JoinPoint; import org.aspectj.lang.annotation.Before; // Inside the @Aspect class @Before("serviceMethods()") // Reference the pointcut public void logBeforeServiceCall(JoinPoint joinPoint) { String methodName = joinPoint.getSignature().getName(); System.out.println("Entering method: " + methodName); // You can access method arguments via joinPoint.getArgs() }
The
JoinPoint
parameter provides context about the intercepted method execution, such as the method signature and arguments.Now, you'll apply these concepts to add logging to the restaurant order service.
-
Challenge
Working with Different Advice Types
In addition to running code before a method executes with
@Before
, Spring AOP provides advice types that allow you to react after a method has finished, based on how it finished.The
@After
AdviceThe
@After
advice runs after a matched method execution completes, whether it returned normally or threw an exception. This is useful for cleanup tasks or actions that must happen regardless of the method's success, like releasing resources or sending final notifications.import org.aspectj.lang.annotation.After; // Inside the @Aspect class @After("serviceMethods()") // Reference a pointcut public void cleanupAfterServiceCall(JoinPoint joinPoint) { System.out.println("Method finished: " + joinPoint.getSignature().getName()); // This runs even if the method threw an exception }
The
@AfterReturning
AdviceThe
@AfterReturning
advice runs only when a matched method executes successfully and returns a value. You can even access the return value within the advice.import org.aspectj.lang.annotation.AfterReturning; // Inside the @Aspect class @AfterReturning(pointcut = "serviceMethods()", returning = "result") public void logSuccessfulReturn(JoinPoint joinPoint, Object result) { System.out.println("Method executed successfully: " + joinPoint.getSignature().getName()); System.out.println("Returned value: " + result); // This runs only if the method did NOT throw an exception }
Note the
returning = "result"
attribute. This binds the return value of the matched method to the parameter namedresult
in the advice method. The parameter type should match (or be a supertype of) the expected return type.The
@AfterThrowing
AdviceThe
@AfterThrowing
advice runs only when a matched method execution throws an exception. This is ideal for logging errors, sending failure notifications, or attempting recovery actions.import org.aspectj.lang.annotation.AfterThrowing; // Inside the @Aspect class @AfterThrowing(pointcut = "serviceMethods()", throwing = "ex") public void handleServiceException(JoinPoint joinPoint, Throwable ex) { System.err.println("Exception in method: " + joinPoint.getSignature().getName()); System.err.println("Exception message: " + ex.getMessage()); // This runs only if the method threw an exception }
Similar to
@AfterReturning
, thethrowing = "ex"
attribute binds the thrown exception object to the parameter namedex
in the advice method. The parameter type should match (or be a supertype of) the expected exception type.Finally, any of the advice annotations (
@Before
,@After
,@AfterReturning
, etc.) can take either:- A reference to a named
@Pointcut
method, or - A literal pointcut expression string.
So instead of:
@After("serviceMethods()") // refers to a @Pointcut("...") method
You can write, for example:
@After("execution(* com.example.service.*.*(..))")
Where
"execution(* com.example.service.*.*(..))"
is the pointcut expression itself.Next, you'll implement different advice types to add notification, inventory update, and error handling logic to the order service.
- A reference to a named
-
Challenge
Targeting with Pointcuts and Conditional Logic
As you become more familiar with AOP, you'll need more sophisticated pointcut expressions to precisely target the join points where your advice should apply. Spring AOP, using the AspectJ pointcut language, offers powerful ways to achieve this.
For example, here are two types of advanced pointcut expressions:
-
Matching by Parameter Types: You can define pointcuts that match methods based on their parameter types. This is useful when you want to apply advice only to methods that handle specific kinds of data:
// Matches any method in MyService that takes a List as its first parameter @Pointcut("execution(* com.example.service.MyService.*(java.util.List,..))") public void methodsTakingListFirst() {}
Here,
java.util.List
specifies the type of the first parameter, and..
indicates that there might be zero or more subsequent parameters of any type. -
Combining Pointcuts with Logical Operators: You can combine existing pointcut definitions using logical operators like
&&
(AND),||
(OR), and!
(NOT). This allows for complex targeting logic without duplicating expression strings:@Pointcut("execution(* com.example.service.ServiceA.*(..))") public void serviceAMethods() {} @Pointcut("execution(* com.example.service.ServiceB.*(..))") public void serviceBMethods() {} // Combine using OR @Pointcut("serviceAMethods() || serviceBMethods()") public void serviceAOrBMethods() {} // Apply advice to the combined pointcut @Before("serviceAOrBMethods()") public void beforeAOrB(JoinPoint joinPoint) { System.out.println("Executing before Service A or Service B method"); }
Using AOP for Validation
A common use case for
@Before
advice combined with parameter-matching pointcuts is input validation. You can create an aspect that intercepts method calls taking certain data types (like anOrder
object) and validates them before the core business logic executes. If validation fails, the advice can throw an exception, preventing the actual method from running with invalid data.// Inside a ValidationAspect @Pointcut("execution(* com.example.service.*.*(com.example.model.DataObject,..))") public void methodsTakingDataObject() {} @Before("methodsTakingDataObject()") public void validateDataObject(JoinPoint joinPoint) { Object[] args = joinPoint.getArgs(); DataObject data = (DataObject) args[0]; // Assuming first arg is DataObject if (data == null || !data.isValid()) { // Example validation logic throw new IllegalArgumentException("Invalid DataObject provided!"); } System.out.println("DataObject validation passed."); }
In the following tasks, you will practice creating a pointcut based on parameter types for validation and combining pointcuts using the
OR
operator. -
-
Challenge
Controlling Execution with Around Advice
The most powerful type of advice in Spring AOP is the
@Around
advice. Unlike other advice types that run strictly before or after a method,@Around
advice wraps the execution of the matched method (the join point). This gives you complete control over the method call.The
@Around
AdviceWhen you use
@Around
advice, your advice method essentially intercepts the call to the target method. Inside the advice method, you decide whether, when, and how the original target method should be executed. For example, you can:- Choose to execute the original method, skip it entirely, or execute it multiple times.
- Inspect and modify the arguments passed to the original method.
- Inspect and modify the value returned by the original method.
- Perform actions both before and after the original method executes within the same advice method.
Using
ProceedingJoinPoint
To manage the execution of the wrapped method,
@Around
advice methods must have a parameter of typeProceedingJoinPoint
. This interface extendsJoinPoint
and adds theproceed
method. You must call this method if you want the original target method to run. There are two versions:Object proceed() throws Throwable
: Executes the next advice or the target method invocation.Object proceed(Object[] args) throws Throwable
: Executes the next advice or the target method invocation with modified arguments.
The return value of your
@Around
advice method will become the return value seen by the original caller, unless you choose to return something different or theproceed()
call throws an exception.@Aspect @Component public class LoggingAspect { @Around("execution(* com.example.service.*.*(..))") public Object logAround(ProceedingJoinPoint joinPoint) throws Throwable { // logic before System.out.println(">>> Entering " + joinPoint.getSignature()); Object result = joinPoint.proceed(); // logic after System.out.println("<<< Exiting " + joinPoint.getSignature()); return result; } }
In this example, the advice prints a message before calling
joinPoint.proceed()
, lets the original method run, prints another message, and then returns the original method's result.In the next tasks, you will use
@Around
advice to implement performance monitoring and add conditional logic for priority orders. -
Challenge
Conclusion
Congratulations on successfully completing this Code Lab!
You can compile and run the application either by clicking the Run button in the bottom-right corner of the screen or by using the Terminal with the following commands:
-
Compile and package the application:
mvn clean package
-
Run the application:
java -jar target/restaurant-order-system-1.0-SNAPSHOT-jar-with-dependencies.jar
When running the application, observe the output carefully. You should see how the AOP advices interleave with the core
OrderService
logic:- Logging (
@Before
) appears before the "Order placed" message from the service. - Performance (
@Around
) wraps the execution, printing the priority order message before the service logic (for order #2) and the timing message after. - Inventory Update (
@AfterReturning
) logs only after a successfulplaceOrder
call. - Kitchen Notification (
@After
) logs after everyplaceOrder
call finishes, even the one that fails. - Validation (
@Before
) throws an exception for the invalid order (order #3), preventing the coreplaceOrder
logic from running for it. - Error Handling (
@AfterThrowing
) catches the validation exception, logs the error, and triggers the manager notification. - Combined Pointcut (
@Before
) logs before theupdateOrderStatus
call.
Notice how these cross-cutting concerns are handled without modifying the
OrderService
code itself, demonstrating the power of AOP. ---Extending the Program
Here are some ideas to further enhance your skills and extend the application's capabilities:
-
Role-Based Security Aspect: Create a new aspect that intercepts calls to sensitive methods (e.g.,
cancelOrder
or maybe a futureapplyDiscount
method). Use@Before
or@Around
advice to check theUser
object associated with the operation (you might need to pass theUser
object as an argument or retrieve it differently). If the user's role (fromuser.getRole()
) doesn't allow the action (e.g., only "manager" can cancel), throw a customSecurityException
. This demonstrates using AOP for security checks. -
Custom Annotation for Auditing: Define a custom Java annotation, for example,
@Auditable
. Apply this annotation to specific methods inOrderService
(e.g.,placeOrder
,cancelOrder
). Create a new aspect with a pointcut targeting methods annotated with@Auditable
. Implement an advice (e.g.,@AfterReturning
) to log detailed audit information (like who performed the action, when, and on which order ID) whenever an annotated method completes successfully. This will teach you how to use custom annotations with AOP. -
Retry Logic Aspect: Implement an aspect using
@Around
advice that targets operations that can potentially fail. IfjoinPoint.proceed()
throws a specific type of exception (e.g.,TemporaryResourceException
), the advice could catch it, wait briefly, and retry the operation a limited number of times before finally giving up and re-throwing the exception. This shows AOP for resilience patterns.
By implementing these enhancements, you'll gain a deeper understanding of applying AOP to diverse cross-cutting concerns and controlling aspect behavior in Spring. ---
Related Courses in Pluralsight's Library
If you'd like to continue building your Spring skills or explore related topics, check out the courses available on this path:
These courses cover a wide range of topics. Explore them to further your learning journey in Spring!
-
What's a lab?
Hands-on Labs are real environments created by industry experts to help you learn. These environments help you gain knowledge and experience, practice without compromising your system, test without risk, destroy without fear, and let you learn from your mistakes. Hands-on Labs: practice your skills before delivering in the real world.
Provided environment for hands-on practice
We will provide the credentials and environment necessary for you to practice right within your browser.
Guided walkthrough
Follow along with the author’s guided walkthrough and build something new in your provided environment!
Did you know?
On average, you retain 75% more of your learning if you get time for practice.