The full picture
| Dimension | Spring AOP (proxies) | AspectJ (weaving) |
|---|---|---|
| Join points | public method execution on beans | methods (any visibility), constructors, field get/set, static, self-calls |
| Setup | nothing — it's on | ajc compiler or -javaagent LTW |
| Applies to | Spring beans only | any class the weaver touches |
| Runtime cost | one proxy hop per advised call | woven code ≈ hand-written; no proxy hop |
| Debugging/ops | familiar; visible proxy in stack | synthetic methods, transformed bytecode, agent in every JVM start |
Decision heuristics: if the pain is just self-invocation, restructure the beans — that's a design fix, not a weaving problem. If you need to advise domain entities (created by new, not the container), consider whether the concern belongs in a domain service instead. Legit AspectJ cases: security/audit frameworks needing field-level or constructor join points, performance instrumentation of code you don't own, and @Configurable for DI into non-managed objects. In observability specifically, the industry moved to ByteBuddy-based agents (OpenTelemetry) rather than app-level AspectJ — often the right answer is 'neither, use the agent ecosystem'.