[← Advice types](04-advice-types.md) · [Index](../README.md) · [Diagnosing →](06-diagnosing-a-silent-aspect.md) # 5. Six aspects that do not fire Sources: [`BrokenAspects`](../src/main/java/com/ankurm/aop/broken/BrokenAspects.java), [`SelfInvokingService`](../src/main/java/com/ankurm/aop/broken/SelfInvokingService.java), [`NewedUpService`](../src/main/java/com/ankurm/aop/broken/NewedUpService.java). Transcript: [`03-broken-gallery.txt`](output/03-broken-gallery.txt). None of these warn. None fail at startup. All of them look correct in review. ## 1. `@Aspect` without `@Component` `@Aspect` is an AspectJ annotation. It tells Spring how to interpret a bean it already has; it does not create one. Without a stereotype or an `@Bean` method, the class is never instantiated and the pointcut is never registered. The most common cause, and the most invisible — from the container's point of view nothing was ever requested, so there is nothing to warn about. **Fix:** add `@Component`. ## 2. A pointcut that matches nothing ```java @Before("execution(* com.ankurm.aop.services.*.*(..))") // "services", plural ``` A package name matching no type is not an error; it is an empty match set. At runtime this is indistinguishable from an aspect that was never registered. **Fix:** assert on it. `AspectJExpressionPointcut#matches(Method, Class)` in a unit test is two lines and catches every typo permanently. ## 3. A private method Neither proxy strategy can override a private method, so neither can intercept it. The annotation is legal and inert. **Fix:** make it at least package-private *and* call it from outside the object — visibility alone is not enough if the call is internal, which brings you to number 5. ## 4. A final method CGLIB proxies by subclassing. A final method is inherited rather than overridden, so calls go straight to the original. A final *class* fails loudly; a final *method* is silent. Note `beanIsProxied: true` in the transcript. The bean is proxied. This one method is not. **Fix:** remove `final`, or proxy by interface. ## 5. Self-invocation The expensive one, because the code looks right and the annotation is visible. ```json "5-self-invocation": { "beanIsProxied": true, "innerAdvisedWhenCalledFromOuter": false, "innerAdvisedWhenCalledDirectly": true } ``` Same method, same advice. Called through the proxy it is advised; reached by `this.inner()` from another method of the same object it is not, because the proxy is not in that call path. This is the same mechanism that makes `@Transactional` and `@Cacheable` silently do nothing on internal calls. Learning it once here saves learning it three times. **Fixes, best first:** 1. Move the method to another bean. This is almost always the right answer, and the resulting design is usually better anyway. 2. Inject the bean into itself and call through that reference. 3. `AopContext.currentProxy()` with `exposeProxy = true`. Works; couples your code to Spring AOP and makes the class aware it is proxied. ## 6. An object created with `new` Spring AOP advises beans. An instance built by a factory, a helper or a test has no proxy and never will. **Fix:** get it from the container. If it genuinely must be constructed by hand and still advised, that is what AspectJ load-time weaving is for.