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:
- What is AOP?
- What problem does AOP solve?
- What is a cross-cutting concern?
- What is an aspect?
- What is advice?
- What is a pointcut?
- What is a join point?
- Why is Spring AOP proxy-based?
- What is the difference between JDK proxy and CGLIB proxy?
- Why does self-invocation not work?
- How is AOP related to
@Transactional, security, and caching? - 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
| Term | Meaning |
|---|---|
| Aspect | class containing cross-cutting logic |
| Advice | code that runs at a matched point |
| Pointcut | expression that selects where advice applies |
| Join point | point in program execution, usually method execution in Spring AOP |
| Target object | real object being proxied |
| Proxy | wrapper object created by Spring |
| Weaving | applying 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:
@Beforeruns 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:
@Afterruns 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:
@AfterReturningruns 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:
@AfterThrowingruns 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:
@Aroundcontrols method execution and must callproceed()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:
ProceedingJoinPointlets@Aroundadvice 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, forgettingproceed()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
| Topic | JDK Dynamic Proxy | CGLIB Proxy |
|---|---|---|
| Proxies | interfaces | classes |
| Built into JDK | yes | no, but included through Spring |
| Needs interface | yes | no |
| Method limitations | interface methods | cannot advise final methods |
| Common in Spring | yes | yes |
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:
@Transactionaldepends 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:
@Cacheableworks 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:
@Asyncalso 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:
@Aroundis 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
| Topic | Spring AOP | AspectJ |
|---|---|---|
| Style | proxy-based | weaving-based |
| Scope | Spring beans | broader Java program |
| Complexity | simpler | more powerful |
| Needs Spring bean | yes | no |
| Field access join points | no | yes |
| Constructor join points | no | yes |
| Common use | transactions, security, caching, logging | advanced 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
@Transactionalsometimes 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.
@Beforeruns before the method.@Afterruns after success or exception.@AfterReturningruns after successful return.@AfterThrowingruns after exception.@Aroundwraps method execution.@Aroundmust callproceed()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.