configuration-properties/ @ConfigurationProperties vs @Value on Spring Boot 4.1.1. The relaxed-binding matrix is generated by binding each spelling rather than transcribed, and re-checked against real processes -- the in-process probe was wrong twice before it was right. Records the three findings that came out of it: @Value does get relaxed resolution inside Spring Boot (Boot attaches ConfigurationPropertySources), the configuration processor silently stops generating metadata on JDK 23+ when declared as a plain dependency, and @Valid is not what makes nested constraints run. profiles-and-config/ Precedence, profiles, spring.config.import and config trees. /precedence reports every source holding a property in rank order with file and line, which turns "my profile file had no effect" into a two-line answer. Also pins the counterintuitive one: an imported file outranks the file that imported it. spring-aop/ Designators, proxy types, and aspects that do not fire. One advice per supported designator so the reference table is generated from real matches; all fourteen unsupported designators fed to the parser. Two corrections to the reference documentation: unsupported designators throw UnsupportedPointcutPrimitiveException (extends RuntimeException, not IllegalArgumentException), and spring-boot-starter-aop was renamed to spring-boot-starter-aspectj in Boot 4. 19 contract tests across the three modules, 15 captured transcripts, all regenerated by scripts/run-all.sh. Verified on Spring Boot 4.1.1, Spring Framework 7.0.9, JDK 25.0.4.1. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Gip4srpzMwjgoba6uEfbr5
2.1 KiB
← Broken aspect gallery · Index
6. Diagnosing a silent aspect
Endpoint: AopDiagnosticsEndpoint.
Almost every non-firing aspect is one of three things, and all three are visible in one place.
The three questions, in order
1. Is the bean proxied at all?
AopUtils.isAopProxy(bean)
false means no pointcut matched this bean, or it is not a bean. Stop here and check the
pointcut and the registration.
2. Which kind of proxy?
AopUtils.isJdkDynamicProxy(bean) // interfaces only
AopUtils.isCglibProxy(bean) // subclass
If it is a JDK proxy and your method is not on an interface, that is your answer.
3. Is your advice in the advisor list?
if (bean instanceof Advised advised) {
Arrays.stream(advised.getAdvisors())
.map(a -> a.getAdvice().getClass().getSimpleName())
.forEach(System.out::println);
}
Proxied, right kind, and your advice missing means the pointcut matched the bean but not the method.
Output
defaultOrderService CGLIB subclass target=DefaultOrderService
class : DefaultOrderService$$SpringCGLIB$$0
interfaces : (none)
advisors : 11
Testing a pointcut without an application
The fastest check of all, and it belongs in a test rather than in a diagnostic endpoint:
AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
pointcut.setExpression("execution(* com.example.service.*.*(..))");
assertThat(pointcut.matches(Foo.class.getMethod("bar"), Foo.class)).isTrue();
Remember that setExpression does not parse; the parse happens on first matches. So this is
also how you find out that a designator is unsupported before production does.
Logging
logging.level.org.springframework.aop=DEBUG
reports proxy creation per bean. Verbose, but it answers question 1 for every bean at once.
Delete the endpoint before shipping
It reports internal wiring. If you want it permanently, put it behind the management port and authentication.