Skip to main content

Week 8 Day 1 — Spring AOP Mental Model: Proxies, Aspects, Advice, Pointcuts, and Self-Invocation

Goal

Today I want to understand Spring AOP.

Main questions:

  1. What is AOP?
  2. What problem does AOP solve?
  3. What is a cross-cutting concern?
  4. What is an aspect?
  5. What is advice?
  6. What is a pointcut?
  7. What is a join point?
  8. Why is Spring AOP proxy-based?
  9. What is the difference between JDK proxy and CGLIB proxy?
  10. Why does self-invocation not work?
  11. How is AOP related to @Transactional, security, and caching?
  12. What are common exam traps?

1. Why Learn AOP?

AOP means:

Aspect-Oriented Programming

Spring uses AOP internally for many important features.

Examples:

@Transactional
@PreAuthorize
@Cacheable
@Async
custom logging aspects
custom performance monitoring
custom auditing

When I understand AOP, I understand why these features work — and why they sometimes do not work.

Memory sentence:

AOP explains many “Spring magic” features.


2. The Problem AOP Solves

Imagine I have many service methods:

public TaskDto createTask(CreateTaskRequest request) {
log.info("Creating task");
long start = System.currentTimeMillis();

try {
// business logic
return result;
} finally {
long duration = System.currentTimeMillis() - start;
log.info("createTask took {} ms", duration);
}
}

Then another method:

public ClientDto createClient(CreateClientRequest request) {
log.info("Creating client");
long start = System.currentTimeMillis();

try {
// business logic
return result;
} finally {
long duration = System.currentTimeMillis() - start;
log.info("createClient took {} ms", duration);
}
}

Problem:

same logging logic repeated everywhere
same timing logic repeated everywhere
same security logic repeated everywhere
same transaction logic repeated everywhere

This makes code messy.

AOP helps move repeated technical logic out of business methods.

Memory sentence:

AOP separates repeated technical concerns from business logic.


3. Cross-Cutting Concern

A cross-cutting concern is logic that appears across many parts of the application.

Examples:

logging
transactions
security
caching
metrics
auditing
retry logic
performance timing
exception tracking

These concerns “cut across” many classes.

Business logic:

create task
pay invoice
register user
approve document
send report

Cross-cutting logic:

log method call
start transaction
check permission
cache result
measure execution time

Memory sentence:

Cross-cutting concerns are repeated technical concerns across many classes.


4. AOP Simple Idea

Without AOP:

Business method contains business logic + logging + transactions + security.

With AOP:

Business method contains business logic.
Aspect contains logging / transactions / security.
Spring applies aspect around matching methods.

Simple picture:

Client

Spring AOP Proxy

Before advice

Target method

After advice

Return result

Memory sentence:

AOP lets extra behavior run before, after, or around business methods.


5. Important AOP Vocabulary

TermMeaning
Aspectclass containing cross-cutting logic
Advicecode that runs at a matched point
Pointcutexpression that selects where advice applies
Join pointpoint in program execution, usually method execution in Spring AOP
Target objectreal object being proxied
Proxywrapper object created by Spring
Weavingapplying aspects to target code

Memory sentence:

Aspect contains advice; pointcut decides where it runs.


6. Aspect

An aspect is a class that contains cross-cutting logic.

Example:

@Aspect
@Component
public class LoggingAspect {
}

@Aspect means:

This class defines AOP rules.

@Component means:

Spring should manage this aspect as a bean.

Memory sentence:

An aspect is a Spring bean that contains AOP logic.


7. Advice

Advice is the code that runs.

Common advice types:

@Before
@After
@AfterReturning
@AfterThrowing
@Around

Example:

@Before("execution(* com.example.task.TaskService.*(..))")
public void logBeforeMethod() {
System.out.println("Method is about to run");
}

This advice runs before matching methods.

Memory sentence:

Advice is the action executed by an aspect.


8. Pointcut

A pointcut decides where advice applies.

Example:

execution(* com.example.task.TaskService.*(..))

Meaning:

match all methods in TaskService

Advice + pointcut:

@Before("execution(* com.example.task.TaskService.*(..))")
public void logBeforeMethod() {
System.out.println("Before TaskService method");
}

Memory sentence:

Pointcut selects methods; advice runs there.


9. Join Point

A join point is a point in program execution where advice can run.

In Spring AOP, the most important join point is:

method execution on Spring beans

Example:

taskService.createTask(request);

This method execution can be intercepted by Spring AOP.

Memory sentence:

In Spring AOP, join points are mainly method executions on Spring beans.


10. First Simple Aspect

@Aspect
@Component
public class LoggingAspect {

@Before("execution(* com.example.task.TaskService.*(..))")
public void beforeTaskServiceMethod() {
System.out.println("A TaskService method is about to run");
}
}

If this service exists:

@Service
public class TaskService {

public TaskDto createTask(CreateTaskRequest request) {
return new TaskDto(1L, request.title());
}
}

When calling:

taskService.createTask(request);

Spring can run:

A TaskService method is about to run

before the real method.

Memory sentence:

A simple aspect can run logic before service methods.


11. @Before

@Before advice runs before the method.

Example:

@Before("execution(* com.example..*Service.*(..))")
public void logBefore() {
System.out.println("Before service method");
}

Good for:

logging method entry
checking simple conditions
auditing attempts

But @Before cannot change the return value.

Memory sentence:

@Before runs before the method and cannot control the return value.


12. @After

@After advice runs after the method finishes.

It runs whether the method succeeds or throws an exception.

Example:

@After("execution(* com.example..*Service.*(..))")
public void logAfter() {
System.out.println("After service method");
}

Similar to:

finally {
}

Memory sentence:

@After runs after method completion, success or exception.


13. @AfterReturning

@AfterReturning runs only if the method returns successfully.

Example:

@AfterReturning(
pointcut = "execution(* com.example..*Service.*(..))",
returning = "result"
)
public void logAfterReturning(Object result) {
System.out.println("Method returned: " + result);
}

Good for:

logging successful result
auditing successful actions
metrics after success

Memory sentence:

@AfterReturning runs only on successful return.


14. @AfterThrowing

@AfterThrowing runs only if the method throws an exception.

Example:

@AfterThrowing(
pointcut = "execution(* com.example..*Service.*(..))",
throwing = "exception"
)
public void logException(Throwable exception) {
System.out.println("Method failed: " + exception.getMessage());
}

Good for:

error logging
exception metrics
failure auditing

Memory sentence:

@AfterThrowing runs only when the method throws an exception.


15. @Around

@Around is the most powerful advice type.

It can:

run before method
run after method
decide whether method runs
measure duration
change arguments
change return value
catch exceptions
rethrow exceptions

Example:

@Around("execution(* com.example..*Service.*(..))")
public Object measureTime(ProceedingJoinPoint joinPoint) throws Throwable {
long start = System.currentTimeMillis();

try {
return joinPoint.proceed();
} finally {
long duration = System.currentTimeMillis() - start;
System.out.println(joinPoint.getSignature() + " took " + duration + " ms");
}
}

Important:

joinPoint.proceed()

calls the real target method.

Memory sentence:

@Around controls method execution and must call proceed() to continue.


16. ProceedingJoinPoint

ProceedingJoinPoint is used with @Around.

It gives access to:

method signature
method arguments
target object
proceed()

Example:

@Around("execution(* com.example..*Service.*(..))")
public Object logAround(ProceedingJoinPoint joinPoint) throws Throwable {
System.out.println("Method: " + joinPoint.getSignature().getName());
System.out.println("Args: " + Arrays.toString(joinPoint.getArgs()));

return joinPoint.proceed();
}

Memory sentence:

ProceedingJoinPoint lets @Around advice continue to the real method.


17. Important @Around Trap

Bad:

@Around("execution(* com.example..*Service.*(..))")
public Object badAround(ProceedingJoinPoint joinPoint) {
System.out.println("Before");
return null;
}

Problem:

joinPoint.proceed() is not called
real method never runs
null is returned

Correct:

@Around("execution(* com.example..*Service.*(..))")
public Object goodAround(ProceedingJoinPoint joinPoint) throws Throwable {
System.out.println("Before");

Object result = joinPoint.proceed();

System.out.println("After");

return result;
}

Memory sentence:

In @Around, forgetting proceed() skips the real method.


18. Pointcut Expression: execution

The most common Spring AOP pointcut designator is:

execution

Example:

execution(* com.example.task.TaskService.createTask(..))

Meaning:

match createTask method in TaskService

General shape:

execution(modifiers-pattern? return-type-pattern declaring-type-pattern? method-name-pattern(parameters-pattern) throws-pattern?)

Do not panic.

For exam and daily work, remember common patterns.

Memory sentence:

execution(...) matches method execution.


19. Common Pointcut Patterns

Match one method:

execution(* com.example.task.TaskService.createTask(..))

Match all methods in one class:

execution(* com.example.task.TaskService.*(..))

Match all methods in service package:

execution(* com.example.service.*.*(..))

Match all methods in service package and subpackages:

execution(* com.example.service..*.*(..))

Match all methods ending with Service:

execution(* com.example..*Service.*(..))

Memory sentence:

* means any; .. means any subpackage or any parameters depending on position.


20. Pointcut with Annotation

I can match methods annotated with a custom annotation.

Custom annotation:

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

Aspect:

@Aspect
@Component
public class ExecutionTimeAspect {

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

try {
return joinPoint.proceed();
} finally {
long duration = System.currentTimeMillis() - start;
System.out.println(joinPoint.getSignature() + " took " + duration + " ms");
}
}
}

Usage:

@LogExecutionTime
public TaskDto createTask(CreateTaskRequest request) {
return taskService.createTask(request);
}

Memory sentence:

Annotation-based pointcuts are readable and explicit.


21. Named Pointcuts

Instead of repeating pointcut expressions, define named pointcuts.

@Aspect
@Component
public class LoggingAspect {

@Pointcut("execution(* com.example..*Service.*(..))")
public void serviceMethods() {
}

@Before("serviceMethods()")
public void beforeServiceMethod() {
System.out.println("Before service method");
}

@AfterThrowing(
pointcut = "serviceMethods()",
throwing = "exception"
)
public void afterException(Throwable exception) {
System.out.println("Exception: " + exception.getMessage());
}
}

Memory sentence:

Named pointcuts make aspects easier to reuse and read.


22. Spring AOP Is Proxy-Based

This is the most important part.

Spring AOP usually works by creating a proxy object.

Instead of injecting the real service directly:

TaskService target

Spring injects:

TaskService proxy

The proxy wraps the real target.

Flow:

Caller

Proxy

Advice

Target method

Advice

Caller

Memory sentence:

Spring AOP works by calling methods through a proxy.


23. Target Object vs Proxy

Target object:

the real service object

Proxy:

Spring-created wrapper around the real service

Example:

@Service
public class TaskService {

@Transactional
public void createTask() {
// business logic
}
}

Spring may create:

TaskService proxy

The proxy adds transaction behavior around the real method.

Memory sentence:

The proxy adds behavior; the target contains business logic.


24. Why Proxies Matter

For AOP to work, the method call must go through the proxy.

Works:

Controller -> TaskService proxy -> advice -> real TaskService method

Does not work:

TaskService target -> this.otherMethod()

because this means the real object, not the proxy.

Memory sentence:

AOP works only when the call goes through the Spring proxy.


25. Self-Invocation Problem

Self-invocation means:

a method inside the same class calls another method of the same class

Example:

@Service
public class TaskService {

public void outer() {
inner();
}

@Transactional
public void inner() {
// transaction expected?
}
}

When outer() calls inner():

this.inner()

The call does not go through the Spring proxy.

So @Transactional on inner() may not apply.

Memory sentence:

Self-invocation bypasses the proxy.


26. Self-Invocation Picture

External call:

Controller

TaskService proxy

@Transactional advice

TaskService.inner()

Internal call:

TaskService.outer()

this.inner()

no proxy

no advice

Memory sentence:

External calls can be intercepted; internal self-calls can bypass advice.


27. How to Fix Self-Invocation

Better design:

@Service
public class TaskService {

private final TaskTransactionService transactionService;

public TaskService(TaskTransactionService transactionService) {
this.transactionService = transactionService;
}

public void outer() {
transactionService.inner();
}
}

Second bean:

@Service
public class TaskTransactionService {

@Transactional
public void inner() {
// transactional logic
}
}

Now call goes:

TaskService -> TaskTransactionService proxy -> advice -> target method

Memory sentence:

Move advised method to another Spring bean to avoid self-invocation.


28. JDK Dynamic Proxy

Spring can use JDK dynamic proxies.

JDK proxy works through interfaces.

Example:

public interface TaskService {
TaskDto createTask(CreateTaskRequest request);
}

Implementation:

@Service
public class TaskServiceImpl implements TaskService {

@Override
public TaskDto createTask(CreateTaskRequest request) {
return new TaskDto(1L, request.title());
}
}

Spring can create a proxy implementing the same interface.

Memory sentence:

JDK dynamic proxy proxies interfaces.


29. CGLIB Proxy

CGLIB proxy creates a subclass of the target class.

Example:

@Service
public class TaskService {

public TaskDto createTask(CreateTaskRequest request) {
return new TaskDto(1L, request.title());
}
}

If there is no interface, Spring can use a class-based proxy.

Memory sentence:

CGLIB proxy proxies classes by subclassing.


30. JDK Proxy vs CGLIB Proxy

TopicJDK Dynamic ProxyCGLIB Proxy
Proxiesinterfacesclasses
Built into JDKyesno, but included through Spring
Needs interfaceyesno
Method limitationsinterface methodscannot advise final methods
Common in Springyesyes

Memory sentence:

JDK proxy = interface proxy. CGLIB = class proxy.


31. Final Method Trap

CGLIB uses subclassing.

Therefore, final methods cannot be overridden.

Example:

@Service
public class TaskService {

@Transactional
public final void createTask() {
// final method
}
}

A class-based proxy cannot override this final method.

So advice may not apply.

Memory sentence:

Final methods are a problem for class-based proxy advice.


32. Private Method Trap

Spring AOP works on method calls through proxies.

Private methods cannot be called from outside through the proxy.

Bad:

@Service
public class TaskService {

public void outer() {
inner();
}

@Transactional
private void inner() {
}
}

The private method is not advised.

Memory sentence:

Spring AOP does not advise private methods through proxies.


33. Spring Bean Trap

Spring AOP applies to Spring-managed beans.

Works:

@Service
public class TaskService {
}

Does not work:

TaskService service = new TaskService();

because this object is created manually, not by Spring.

Memory sentence:

Spring AOP works on Spring beans, not manually created objects.


34. AOP and @Transactional

@Transactional is commonly implemented using Spring AOP.

When method is called through proxy:

proxy starts transaction
target method runs
proxy commits or rolls back

Example:

@Service
public class TaskService {

@Transactional
public void createTask() {
// database work
}
}

Flow:

Controller

TaskService proxy

start transaction

real createTask()

commit or rollback

Memory sentence:

@Transactional depends on proxy interception in default Spring mode.


35. AOP and Method Security

Method security also uses proxy-style interception.

Example:

@PreAuthorize("hasRole('ADMIN')")
public void deleteUser(Long id) {
}

Before method runs:

security advice checks permission
if allowed -> method runs
if denied -> AccessDeniedException

Self-invocation can also be a trap for method security.

Memory sentence:

Method security is also proxy-based interception.


36. AOP and Caching

Caching also uses proxy interception.

Example:

@Cacheable("tasks")
public TaskDto findById(Long id) {
return loadTaskFromDatabase(id);
}

Flow:

proxy checks cache
if cache hit -> return cached value
if cache miss -> call target method and store result

Self-invocation can also bypass caching.

Memory sentence:

@Cacheable works when calls go through the proxy.


37. AOP and @Async

@Async also depends on Spring interception.

Example:

@Async
public void sendEmail() {
}

If called through proxy:

method can run asynchronously

If called by self-invocation:

method may run normally, not async

Memory sentence:

@Async also needs proxy-based method interception.


38. Aspect Ordering

If multiple aspects apply to the same method, order can matter.

Example:

transaction aspect
security aspect
logging aspect
metrics aspect

Spring can order aspects with:

@Order(1)

Example:

@Aspect
@Component
@Order(1)
public class SecurityLoggingAspect {
}

Lower order value has higher priority.

Memory sentence:

Aspect order matters when multiple aspects apply.


39. Example: Logging Aspect

@Aspect
@Component
public class ServiceLoggingAspect {

@Around("execution(* com.example..*Service.*(..))")
public Object logServiceMethod(ProceedingJoinPoint joinPoint) throws Throwable {
String methodName = joinPoint.getSignature().toShortString();

System.out.println("Starting " + methodName);

try {
Object result = joinPoint.proceed();
System.out.println("Finished " + methodName);
return result;
} catch (Throwable exception) {
System.out.println("Failed " + methodName + ": " + exception.getMessage());
throw exception;
}
}
}

This logs:

method start
method success
method failure

Memory sentence:

@Around is good for logging, timing, and wrapping method execution.


40. Example: Execution Time Aspect

@Aspect
@Component
public class ExecutionTimeAspect {

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

try {
return joinPoint.proceed();
} finally {
long durationNs = System.nanoTime() - start;
System.out.println(
joinPoint.getSignature().toShortString()
+ " took "
+ durationNs / 1_000_000
+ " ms"
);
}
}
}

Custom annotation:

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

Usage:

@LogExecutionTime
public List<TaskDto> findSlowTasks() {
return taskRepository.findSlowTasks();
}

Memory sentence:

Custom annotations make AOP explicit and readable.


41. What Spring AOP Cannot Do Easily

Spring AOP is limited compared with full AspectJ.

Spring AOP mainly advises:

method executions on Spring beans

It does not normally advise:

field access
constructor calls
private method calls
objects not managed by Spring
every object created with new
domain objects outside Spring container

For those, full AspectJ weaving may be needed.

Memory sentence:

Spring AOP is simpler than AspectJ and focuses on Spring bean methods.


42. Spring AOP vs AspectJ

TopicSpring AOPAspectJ
Styleproxy-basedweaving-based
ScopeSpring beansbroader Java program
Complexitysimplermore powerful
Needs Spring beanyesno
Field access join pointsnoyes
Constructor join pointsnoyes
Common usetransactions, security, caching, loggingadvanced cross-cutting needs

Memory sentence:

Spring AOP is simpler; AspectJ is more powerful.


43. When Should I Use AOP?

Good use cases:

logging
metrics
auditing
transaction-like wrappers
security checks
execution timing
cross-cutting validation
caching-like concerns

Be careful with:

business logic hidden in aspects
too broad pointcuts
aspects changing return values unexpectedly
aspects swallowing exceptions
hard-to-debug behavior

Memory sentence:

Use AOP for technical cross-cutting concerns, not core business logic.


44. Bad AOP Design

Bad:

@Around("execution(* com.example..*.*(..))")
public Object changeBusinessResult(ProceedingJoinPoint joinPoint) throws Throwable {
Object result = joinPoint.proceed();

if (result instanceof TaskDto task) {
return new TaskDto(task.id(), "Changed secretly");
}

return result;
}

Problem:

business result changes invisibly
code becomes hard to understand
debugging becomes painful

Better:

keep business rules in service/domain code
use aspects for technical concerns

Memory sentence:

Do not hide important business behavior inside aspects.


45. Testing Aspects

Aspect tests can be tricky.

Options:

unit test aspect logic separately
integration test that method call triggers aspect
test visible side effects
avoid testing Spring internals

Example:

@SpringBootTest
class ExecutionTimeAspectTest {

@Autowired
private TaskService taskService;

@Test
void aspectRunsAroundAnnotatedMethod() {
taskService.findSlowTasks();

// assert observable side effect if possible
}
}

For exam, know:

AOP behavior needs Spring proxy, so plain unit tests do not prove proxy interception.

Memory sentence:

To test real AOP interception, use a Spring test context.


46. Common Exam Traps

Trap 1

AOP is for cross-cutting concerns.


Trap 2

An aspect contains advice and pointcuts.


Trap 3

Advice is the code that runs.


Trap 4

Pointcut selects where advice runs.


Trap 5

Spring AOP is proxy-based.


Trap 6

Spring AOP mainly supports method execution join points on Spring beans.


Trap 7

AOP does not apply to manually created objects.


Trap 8

Self-invocation bypasses the proxy.


Trap 9

Private methods are not advised through Spring AOP proxies.


Trap 10

Final methods can be a problem for class-based proxies.


Trap 11

JDK dynamic proxies proxy interfaces.


Trap 12

CGLIB proxies proxy classes by subclassing.


Trap 13

@Around must call proceed() if the real method should run.


Trap 14

@Transactional, method security, caching, and async behavior often rely on proxies.


Trap 15

Use AOP for technical concerns, not hidden business logic.


47. Real Exam Question: AOP

Question:

What is AOP?

Answer:

AOP means Aspect-Oriented Programming. It is a programming style for separating cross-cutting concerns, such as logging, transactions, security, caching, or metrics, from business logic.


48. Real Exam Question: Cross-Cutting Concern

Question:

What is a cross-cutting concern?

Answer:

A cross-cutting concern is technical logic that appears across many parts of an application, such as logging, transactions, security, caching, auditing, or metrics.


49. Real Exam Question: Aspect

Question:

What is an aspect?

Answer:

An aspect is a class that contains cross-cutting logic. In Spring, it is often declared with @Aspect and registered as a Spring bean.


50. Real Exam Question: Advice

Question:

What is advice?

Answer:

Advice is the code that runs at a matched join point. Examples include @Before, @After, @AfterReturning, @AfterThrowing, and @Around.


51. Real Exam Question: Pointcut

Question:

What is a pointcut?

Answer:

A pointcut is an expression that selects where advice should run, usually matching method executions in Spring AOP.


52. Real Exam Question: Join Point

Question:

What is a join point in Spring AOP?

Answer:

In Spring AOP, a join point is typically a method execution on a Spring-managed bean.


53. Real Exam Question: Proxy-Based AOP

Question:

What does it mean that Spring AOP is proxy-based?

Answer:

It means Spring creates a proxy object around the target bean. Calls must go through the proxy for advice to run.


54. Real Exam Question: Self-Invocation

Question:

Why does self-invocation not trigger Spring AOP advice?

Answer:

Because a method inside the target object calls another method on this, bypassing the Spring proxy. Since the call does not go through the proxy, advice is not applied.


55. Real Exam Question: JDK vs CGLIB Proxy

Question:

What is the difference between JDK dynamic proxies and CGLIB proxies?

Answer:

JDK dynamic proxies proxy interfaces. CGLIB proxies classes by creating subclasses.


56. Real Exam Question: @Around

Question:

What is special about @Around advice?

Answer:

@Around advice can control method execution. It can run before and after the method, decide whether to call the method, change the return value, and handle exceptions. It must call proceed() if the target method should run.


57. Interview Answer

Question:

Explain Spring AOP in simple words.

Good answer:

Spring AOP lets us apply cross-cutting logic, such as logging, transactions, security, caching, or metrics, around Spring bean methods without putting that logic directly inside every business method. Spring usually does this by creating proxies. The caller calls the proxy, the proxy runs advice, then it calls the real target method.


58. Interview Answer

Question:

What is the difference between aspect, advice, and pointcut?

Good answer:

An aspect is the class that contains cross-cutting logic. Advice is the actual code that runs, such as before, after, or around a method. A pointcut is the expression that decides which method executions should be advised.


59. Interview Answer

Question:

Why does @Transactional sometimes not work when one method calls another method in the same class?

Good answer:

Because Spring’s default transaction management is proxy-based. The transaction advice is applied when a method call goes through the Spring proxy. If one method in the same class calls another method using this, the call bypasses the proxy, so the transactional advice may not run. This is called self-invocation.


60. Interview Answer

Question:

What is the difference between Spring AOP and AspectJ?

Good answer:

Spring AOP is proxy-based and mainly applies to method executions on Spring-managed beans. It is simpler and works well for common Spring concerns such as transactions, security, caching, and logging. AspectJ is more powerful and uses weaving, so it can advise more join point types, including field access, constructors, and objects not managed by Spring.


61. Tiny Code Practice

Create an aspect that logs before every service method.

Possible answer:

@Aspect
@Component
public class LoggingAspect {

@Before("execution(* com.example..*Service.*(..))")
public void logBeforeServiceMethod() {
System.out.println("A service method is about to run");
}
}

Question:

What does the pointcut match?

Answer:

All methods in classes whose names end with Service under com.example and its subpackages.

62. Tiny Bug Practice 1

Problem:

@Around("execution(* com.example..*Service.*(..))")
public Object around(ProceedingJoinPoint joinPoint) {
System.out.println("Before");
return null;
}

Question:

What is wrong?

Answer:

joinPoint.proceed() is not called, so the real method never runs. The advice always returns null.

Correct:

@Around("execution(* com.example..*Service.*(..))")
public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
System.out.println("Before");
Object result = joinPoint.proceed();
System.out.println("After");
return result;
}

63. Tiny Bug Practice 2

Problem:

@Service
public class TaskService {

public void outer() {
inner();
}

@Transactional
public void inner() {
// database work
}
}

Question:

Why might @Transactional not work on inner()?

Answer:

outer() calls inner() through this.inner(), not through the Spring proxy. This is self-invocation, so transaction advice may not apply.


64. Tiny Bug Practice 3

Problem:

TaskService taskService = new TaskService();
taskService.createTask();

Question:

Why will Spring AOP not apply?

Answer:

The object was created manually with new, so it is not a Spring-managed bean and no Spring proxy is involved.


65. Tiny Bug Practice 4

Problem:

@Service
public final class TaskService {
}

Question:

Why can this be a problem for CGLIB proxying?

Answer:

CGLIB creates subclass-based proxies. A final class cannot be subclassed, so class-based proxying cannot work normally.


Practice Questions and Answers

Question 1

What does AOP mean?

Answer:

AOP means Aspect-Oriented Programming.


Question 2

What problem does AOP solve?

Answer:

AOP solves the problem of repeated cross-cutting technical logic, such as logging, transactions, security, metrics, auditing, or caching, being mixed into business methods.


Question 3

What is a cross-cutting concern?

Answer:

A cross-cutting concern is logic that appears across many parts of an application, such as logging, transactions, security, or caching.


Question 4

What is an aspect?

Answer:

An aspect is a class that contains cross-cutting logic, usually declared with @Aspect and registered as a Spring bean.


Question 5

What is advice?

Answer:

Advice is the code that runs at a matched join point, such as before, after, or around a method execution.


Question 6

What is a pointcut?

Answer:

A pointcut is an expression that selects where advice should run.


Question 7

What is a join point in Spring AOP?

Answer:

In Spring AOP, a join point is usually a method execution on a Spring-managed bean.


Question 8

What does @Before do?

Answer:

@Before advice runs before the matched method executes.


Question 9

What does @AfterReturning do?

Answer:

@AfterReturning advice runs only when the matched method returns successfully.


Question 10

What does @AfterThrowing do?

Answer:

@AfterThrowing advice runs only when the matched method throws an exception.


Question 11

What does @Around do?

Answer:

@Around advice wraps method execution and can control whether the target method runs, change return values, measure time, or handle exceptions.


Question 12

Why must @Around usually call proceed()?

Answer:

Because proceed() calls the real target method. Without it, the target method does not run.


Question 13

What does execution(* com.example..*Service.*(..)) match?

Answer:

It matches all methods in classes ending with Service under com.example and its subpackages.


Question 14

What does it mean that Spring AOP is proxy-based?

Answer:

It means Spring creates a proxy around the target bean, and advice runs when calls go through that proxy.


Question 15

What is self-invocation?

Answer:

Self-invocation is when one method inside a class calls another method in the same class.


Question 16

Why does self-invocation bypass AOP?

Answer:

Because the call uses this, not the Spring proxy. Since the call does not go through the proxy, advice is not applied.


Question 17

What is the difference between JDK proxy and CGLIB proxy?

Answer:

JDK dynamic proxies proxy interfaces. CGLIB proxies classes by creating subclasses.


Question 18

Why are private methods a problem for Spring AOP?

Answer:

Private methods are not called externally through the proxy, so Spring AOP cannot advise them in the normal proxy-based model.


Question 19

How is AOP related to @Transactional?

Answer:

@Transactional is commonly implemented through Spring AOP proxies. The proxy starts, commits, or rolls back the transaction around the target method.


Question 20

When should I use Spring AOP?

Answer:

Use Spring AOP for technical cross-cutting concerns such as logging, metrics, auditing, transactions, security, or caching — not for hiding core business logic.

Final Memory Sentences

  • AOP means Aspect-Oriented Programming.
  • AOP separates cross-cutting concerns from business logic.
  • Cross-cutting concerns include logging, transactions, security, caching, metrics, and auditing.
  • An aspect contains cross-cutting logic.
  • Advice is the code that runs.
  • A pointcut selects where advice runs.
  • In Spring AOP, join points are mainly method executions on Spring beans.
  • @Before runs before the method.
  • @After runs after success or exception.
  • @AfterReturning runs after successful return.
  • @AfterThrowing runs after exception.
  • @Around wraps method execution.
  • @Around must call proceed() if the real method should run.
  • Spring AOP is proxy-based.
  • AOP works when calls go through the Spring proxy.
  • Self-invocation bypasses the proxy.
  • JDK dynamic proxy proxies interfaces.
  • CGLIB proxy proxies classes.
  • Private methods are not advised through Spring AOP proxies.
  • Final methods can be a problem for class-based proxies.
  • @Transactional, method security, caching, and async often rely on proxies.
  • Use AOP for technical concerns, not hidden business logic.