VOOZH about

URL: https://www.javacodegeeks.com/spring-aop-method-call-within-same-class-example.html

⇱ Spring AOP Method Call Within Same Class Example - Java Code Geeks


Spring AOP (Aspect-Oriented Programming) allows developers to modularize cross-cutting concerns like logging, transactions, or security. However, a common pitfall developers encounter is when they try to apply AOP to a method call within the same class. Let us delve into understanding how Spring AOP method calls within the same class and why it behaves differently from typical method interceptions.

1. What is Spring AOP?

Spring AOP (Aspect-Oriented Programming) is a powerful feature of the Spring Framework that enables the modularization of cross-cutting concerns such as logging, security, transaction management, and performance monitoring. Instead of embedding these concerns into core business logic, Spring AOP allows you to define them separately and weave them into your application using proxies.

Internally, Spring AOP is proxy-based. It creates a proxy object that wraps your original bean. This proxy intercepts method calls and applies the appropriate advice. Depending on whether your target object implements interfaces, Spring uses either:

  • JDK Dynamic Proxies – Used when the bean implements one or more interfaces. (Java Proxy API)
  • CGLIB Proxies – Used when the bean does not implement any interface. (CGLIB GitHub)

These proxies wrap the target bean with interceptors that apply behavior such as @Before, @After, or @Around advice, enabling behavior injection at runtime without changing the source code.

1.1 Core AOP concepts

  • Join Point: A specific point in the execution of a program, such as the execution of a method or the handling of an exception. (Join Point – Spring Docs)
  • Advice: The action taken at a particular join point. It can be executed before, after, or around the method execution. Examples include logging or authorization. (Advice – Spring Docs)
  • Pointcut: An expression that selects one or more join points where advice should be applied. (Pointcut – Spring Docs)
  • Aspect: A class that encapsulates pointcut and advice logic. It defines both what to do and where to do it. (Aspect – Spring Docs)

2. Code Example

This section walks through a complete Spring Boot example that demonstrates how Spring AOP behaves differently when a method is called internally versus via a proxy. It will help clarify the “Spring AOP method call within same class” behavior using a simple timing aspect.

2.1 Add Dependencies (pom.xml)

To get started, we need to add the required Spring Boot dependencies to our Maven project. The main ones include the core Spring Boot starter and the AOP starter, which enables proxy-based aspect weaving.

<!-- Spring Boot Starter -->
<dependency>
 <groupId>org.springframework.boot</groupId>
 <artifactId>spring-boot-starter</artifactId>
</dependency>

<!-- Spring Boot AOP Starter -->
<dependency>
 <groupId>org.springframework.boot</groupId>
 <artifactId>spring-boot-starter-aop</artifactId>
</dependency>

2.2 LogExecutionTime.java

This custom annotation is used to mark any method we want to time. It has runtime retention and targets method-level elements, making it ideal for use with an @Around aspect.

package com.example.aopdemo.annotation;

import java.lang.annotation.*;

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface LogExecutionTime {
}

2.3 LoggingAspect.java

This class defines the actual aspect using Spring AOP. It intercepts any method annotated with @LogExecutionTime and measures its execution time using an @Around advice.

package com.example.aopdemo.aspect;

import com.example.aopdemo.annotation.LogExecutionTime;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;

@Aspect
@Component
public class LoggingAspect {

 @Around("@annotation(logExecutionTime)")
 public Object logExecutionTime(ProceedingJoinPoint joinPoint, LogExecutionTime logExecutionTime) throws Throwable {
 long start = System.currentTimeMillis();

 Object result = joinPoint.proceed();

 long duration = System.currentTimeMillis() - start;
 System.out.println(joinPoint.getSignature() + " executed in " + duration + "ms");
 return result;
 }
}

2.4 UserService.java

This service class contains a method marked with the @LogExecutionTime annotation. It also includes a method to demonstrate two types of calls to internalMethod – one directly (which will skip AOP) and one via the Spring proxy (which will apply AOP).

package com.example.aopdemo.service;

import com.example.aopdemo.annotation.LogExecutionTime;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Service;

@Service
public class UserService {

 @Autowired
 private ApplicationContext context;

 public void callMethods() {
 System.out.println("Calling internal method directly (no AOP):");
 this.internalMethod(); // internal call - no AOP

 System.out.println("\nCalling internal method via proxy (AOP will apply):");
 UserService proxy = context.getBean(UserService.class);
 proxy.internalMethod();
 }

 @LogExecutionTime
 public void internalMethod() {
 System.out.println("Inside internalMethod()");
 }
}

2.5 AopDemoApplication.java

This is the Spring Boot main application class. It loads the Spring context and retrieves the UserService bean to run the test scenario for method interception.

package com.example.aopdemo;

import com.example.aopdemo.service.UserService;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;

@SpringBootApplication
public class AopDemoApplication {

 public static void main(String[] args) {
 ConfigurableApplicationContext context = SpringApplication.run(AopDemoApplication.class, args);
 UserService service = context.getBean(UserService.class);
 service.callMethods();
 }
}

2.6 Code Run and Output

The output clearly demonstrates the difference between a direct internal method call and one made through a proxy. Only the proxy-based call triggers the aspect logic and logs the execution time.

Calling internal method directly (no AOP):
Inside internalMethod()

Calling internal method via proxy (AOP will apply):
Inside internalMethod()
void com.example.aopdemo.service.UserService.internalMethod() executed in 2ms

When the application is run, Spring creates a proxy of the UserService bean and wraps the annotated method with advice defined in LoggingAspect. However, when internalMethod is called via this.internalMethod(), it bypasses the proxy since internal calls within the same class do not go through Spring’s AOP proxy. As a result, the @LogExecutionTime annotation is ignored in that case. On the other hand, when internalMethod is called via the application context proxy (i.e., context.getBean(UserService.class)), the call is routed through the proxy, allowing the aspect to intercept the call and log the execution time. This behavior illustrates the limitation of Spring AOP when it comes to internal method calls and shows why developers sometimes need workarounds such as exposing self-references via proxy-aware context access. This example effectively demonstrates the subtle but important distinction that arises when using Spring AOP for method calls within the same class.

3. Conclusion

Spring AOP is a powerful tool, but developers must be cautious when invoking methods internally within the same class. Since such calls bypass the proxy, the associated advice is not applied. By using workarounds like retrieving the proxy from the application context or refactoring code into separate beans, you can ensure AOP advice is consistently executed.

Do you want to know how to develop your skillset to become a Java Rockstar?
Subscribe to our newsletter to start Rocking right now!
To get you started we give you our best selling eBooks for FREE!
1. JPA Mini Book
2. JVM Troubleshooting Guide
3. JUnit Tutorial for Unit Testing
4. Java Annotations Tutorial
5. Java Interview Questions
6. Spring Interview Questions
7. Android UI Design
and many more ....
I agree to the Terms and Privacy Policy

Thank you!

We will contact you soon.

👁 Photo of Yatin Batra
Yatin Batra
June 26th, 2025Last Updated: June 26th, 2025
0 555 4 minutes read

Yatin Batra

An experience full-stack engineer well versed with Core Java, Spring/Springboot, MVC, Security, AOP, Frontend (Angular & React), and cloud technologies (such as AWS, GCP, Jenkins, Docker, K8).
Subscribe

This site uses Akismet to reduce spam. Learn how your comment data is processed.

0 Comments
Oldest
Newest Most Voted
Back to top button
Close
wpDiscuz