Why does self-invocation bypass @Transactional in Spring Boot, even when using CGLIB proxies?

## Summary
Self-invocation occurs when a method within a Spring bean calls another `@Transactional` method in the same bean. Despite using CGLIB proxies for transaction interception, the transactional behavior fails because the call bypasses the proxy layer, executing directly on the target instance.

## Root Cause
- Spring's proxy-based AOP creates wrappers around beans to intercept method calls.
- Self-invocation uses the internal `this` reference instead of the proxied instance.
- The proxy remains uninvolved when methods within the same bean call each other.
- Transaction interceptors (like `TransactionInterceptor`) never receive the call.

## Why This Happens in Real Systems
- Logical grouping encourages co-location of related methods in one class.
- Refactoring moves transactional methods into existing service classes.
- Over-reliance on annotations obscures underlying proxy mechanics.
- Feature expansion introduces self-calls incrementally without AOP validation.

## Real-World Impact
- Data integrity violations from partial database updates.
- Missing transaction isolation (e.g., dirty reads due to unprotected queries).
- Silent failures where exceptions trigger rollback failures.
- Uncovered edge cases in production during logical rollback attempts.
- Increased debugging cycles due to non-obvious proxy behavior.

## Example or Code
```java
@Service
public class PaymentService {
    public void processPayment(PaymentData data) {
        validate(data); // Self-invocation → bypasses @Transactional
    }

    @Transactional
    public void validate(PaymentData data) {
        // DB call requiring atomicity → runs WITHOUT transaction
    }
}

How Senior Engineers Fix It

  1. Extract Transactional Logic: Move @Transactional methods to separate beans:

    @Service
    public class ValidationService {
        @Transactional
        public void validate(PaymentData data) { /* ... */ }
    }
    
    @Service
    public class PaymentService {
        @Autowired ValidationService validator;
        public void processPayment(PaymentData data) {
            validator.validate(data);
        }
    }
  2. AspectJ Mode: Replace proxy-based AOP with bytecode weaving via:

    spring.aop.proxy-target-class=false
    spring.aop.auto=true
  3. Self-Injection Workaround (occasionally):