Implementing Aspect-Oriented Programming in Spring Using AspectJ Annotations

AspectJ is an independent AOP framework rather than a native Spring module. It is commonly integrated alongside Spring's own AOP capabilities to provide a more robust aspect-oriented solution.

Two primary approaches exist for this integration:

  1. Annotation-driven confgiuration (Recommended)
  2. XML-based configuration (Supplementary)

Dependency Configuration

Include the required libraries in your project setup. The spring-aspects module inherently bundles the AspectJ weaver, making an explicit aspectjweaver dependency unnecessary.

<dependencies>
    <!-- Spring Core -->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>5.3.5</version>
    </dependency>
    <!-- Spring AOP + AspectJ Integration -->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-aspects</artifactId>
        <version>5.3.5</version>
    </dependency>
    <!-- AOP Alliance API -->
    <dependency>
        <groupId>aopalliance</groupId>
        <artifactId>aopalliance</artifactId>
        <version>1.0</version>
    </dependency>
    <!-- Logging -->
    <dependency>
        <groupId>commons-logging</groupId>
        <artifactId>commons-logging</artifactId>
        <version>1.2</version>
    </dependency>
    <!-- Database Connection Pool -->
    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>druid</artifactId>
        <version>1.1.10</version>
    </dependency>
    <!-- Database Driver -->
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>8.0.22</version>
    </dependency>
    <!-- Unit Testing -->
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.13.1</version>
        <scope>test</scope>
    </dependency>
    <!-- Code Generation -->
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <version>1.18.12</version>
        <scope>provided</scope>
    </dependency>
</dependencies>

Pointcut Expressions

Pointcut expressions define the target methods for AOP enhancement using the execution pattern.

Syntax: execution([modifier] [returnType] [fullClassPath] [methodName]([params]))

Examples targeting different scopes:

  • execution(* com.techcorp.repository.AccountRepoImpl.create(..)) - Targets a single specific method
  • execution(* com.techcorp.repository.AccountRepoImpl.*(..)) - Targets all methods within a single class
  • execution(* com.techcorp.repository.*.*(..)) - Targets all methods across all classes in the repository package
  • execution(* com.techcorp.repository.*.create(..)) - Targets all create methods across classes in the package
  • execution(* com.techcorp.repository.*.create*(..)) - Targets all methods starting with create in the package

XML Configuration Approach

Enable component scanning and automatic proxy generation through XML configuration.

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="
       http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/context
       http://www.springframework.org/schema/context/spring-context.xsd
       http://www.springframework.org/schema/aop
       http://www.springframework.org/schema/aop/spring-aop.xsd">

    <context:component-scan base-package="com.techcorp"/>
    <aop:aspectj-autoproxy/>
</beans>

Target Interfaces and Implementations

Define the DAO interfaces.

package com.techcorp.repository;

public interface AccountRepo {
    int createAccount(Integer accountId, String accountName);
}
package com.techcorp.repository;

public interface EmployeeRepo {
    int registerEmployee(Integer empId, String empName, String role);
}

Implement the interfaces and annotate them as Spring beans.

package com.techcorp.repository.impl;

import com.techcorp.repository.AccountRepo;
import org.springframework.stereotype.Repository;

@Repository
public class AccountRepoImpl implements AccountRepo {
    @Override
    public int createAccount(Integer accountId, String accountName) {
        System.out.println("Account creation logic executed...");
        return 1;
    }
}
package com.techcorp.repository.impl;

import com.techcorp.repository.EmployeeRepo;
import org.springframework.stereotype.Repository;

@Repository
public class EmployeeRepoImpl implements EmployeeRepo {
    @Override
    public int registerEmployee(Integer empId, String empName, String role) {
        System.out.println("Employee registration logic executed...");
        return 1;
    }
}

Aspect Definition

Create the aspect class containing the advice logic. The @Aspect annotation marks this class as an aspect, while @Component registers it as a Spring bean.

package com.techcorp.aspect;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;

@Component
@Aspect
public class RepositoryAspect {

    // Shared pointcut definition targeting all creation methods
    @Pointcut("execution(* com.techcorp.repository.*.create*(..))")
    public void creationPointcut() {}

    // Before advice: Executes prior to the target method
    // JoinPoint provides access to method signature and arguments
    @Before("creationPointcut()")
    public void logBeforeExecution(JoinPoint jp) {
        System.out.println("Pre-processing: Method " + jp.getSignature().getName() + " is about to run.");
    }

    // After advice: Executes regardless of whether the target method succeeds or throws an exception
    @After("creationPointcut()")
    public void logAfterExecution(JoinPoint jp) {
        System.out.println("Post-processing: Method " + jp.getSignature().getName() + " has finished.");
    }

    // AfterReturning advice: Executes only if the target method completes successfully without exceptions
    // The 'returning' attribute binds the method result to the advice parameter
    @AfterReturning(value = "creationPointcut()", returning = "result")
    public void logSuccessfulReturn(JoinPoint jp, Object result) {
        System.out.println("Successful return detected. Output: " + result);
    }

    // AfterThrowing advice: Executes only when the target method throws an exception
    // The 'throwing' attribute binds the exception object to the advice parameter
    @AfterThrowing(value = "creationPointcut()", throwing = "err")
    public void logExceptionOccurrence(Throwable err) {
        System.out.println("Exception caught in aspect: " + err.getMessage());
    }

    // Around advice: Wraps the target method, providing control over execution timing
    // ProceedingJoinPoint.proceed() triggers the actual target method
    // The result of proceed() must be returned to preserve the original method's return value
    @Around("creationPointcut()")
    public Object monitorExecutionTime(ProceedingJoinPoint pjp) throws Throwable {
        System.out.println("Around phase A: Entering method monitor.");
        Object output = pjp.proceed();
        System.out.println("Around phase B: Exiting method monitor.");
        return output;
    }
}

Testing the XML Configuration

@Test
public void verifyXmlSetup() {
    ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
    AccountRepo accountRepo = ctx.getBean(AccountRepo.class);
    accountRepo.createAccount(101, "AdminUser");
}

Managing Multiple Aspects

When multiple aspects target the same method, the @Order annotation dictates the execution sequence. A lower numeric value signifies higher priority, placing the aspect closer to the target method invocation point.

Pure Annotation Configuration Approach

Eliminate XML entirely by utilizing a Java-based configuration class.

package com.techcorp.config;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;

@Configuration
@ComponentScan(basePackages = "com.techcorp")
@EnableAspectJAutoProxy(proxyTargetClass = true)
public class AppConfig {
}

Testing the Java Configuration

@Test
public void verifyJavaSetup() {
    ApplicationContext ctx = new AnnotationConfigApplicationContext(AppConfig.class);
    AccountRepo accountRepo = ctx.getBean(AccountRepo.class);
    accountRepo.createAccount(101, "AdminUser");
}

Tags: Spring aop aspectj annotations java

Posted on Thu, 27 Aug 2026 16:53:17 +0000 by TheStalker