Repository navigation
LoggedAspect fails to start when consumer app's base package overlaps com.fayupable — @Component on LoggedAspect causes double bean registration #3
Description
Summary
LoggedAspect bean creation fails at Spring context startup with:
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'loggedAspect' ...
Failed to instantiate [com.fayupable.logged.spring.aspect.LoggedAspect]: No default constructor found
Caused by: java.lang.NoSuchMethodException: com.fayupable.logged.spring.aspect.LoggedAspect.()
This happens during preInstantiateSingletons, before any @Logged method is ever invoked — a pure startup-time failure.
Environment
- logged-spring:v1.2.1 via JitPack (com.github.Fayupable.logged-lib:logged-spring:v1.2.1)
- Spring Boot 4.0.6
- Consumer app's base package: com.fayupable (i.e. @SpringBootApplication's implicit @componentscan root)
Root cause
LoggedAspect.java (logged-spring), lines ~109-111:
@Aspect
@Component
public class LoggedAspect {
This class carries both @aspect and @component, making it directly visible to Spring's classpath component-scanning — independently of how LoggedAutoConfiguration registers it.
It also declares two public constructors, neither annotated @Autowired:
public LoggedAspect(InvocationEventEmitter, MetricsRecorder, IClientInfoPort)
public LoggedAspect(InvocationEventEmitter, MetricsRecorder, IClientInfoPort, boolean)
Meanwhile LoggedAutoConfiguration registers the bean correctly, with real collaborators:
@Bean
@ConditionalOnMissingBean(LoggedAspect.class)
@ConditionalOnProperty(prefix = "logged", name = "enabled", havingValue = "true", matchIfMissing = true)
public LoggedAspect loggedAspect(InvocationEventEmitter eventEmitter, MetricsRecorder metricsRecorder,
IClientInfoPort clientInfoPort, LoggedProperties properties) {
return new LoggedAspect(eventEmitter, metricsRecorder, clientInfoPort, properties.getMdc().isEnabled());
}
Mechanism
- Any consumer app whose component-scan base package overlaps com.fayupable.logged.* (e.g. an app whose own base package is com.fayupable, or which scans broadly) will have its own @componentscan discover LoggedAspect directly, purely because it's @Component-annotated — with no knowledge of the 4-argument constructor call LoggedAutoConfiguration performs.
- LoggedAutoConfiguration.loggedAspect(...) is guarded by @ConditionalOnMissingBean(LoggedAspect.class). Once component-scanning has already produced a bean definition for LoggedAspect, this condition is satisfied and the auto-configuration's correct definition backs off.
- The component-scanned bean definition can't resolve which of the two constructors to use (no @Autowired hint) and falls back to looking for a no-arg constructor, which doesn't exist → NoSuchMethodException: ().
Confirmation this isn't consumer-specific
In a separate consumer project (also under com.fayupable), the same failure was worked around on the consumer side with:
@ComponentScan(excludeFilters = @ComponentScan.Filter(
type = FilterType.ASSIGNABLE_TYPE,
classes = LoggedAspect.class
))
Excluding LoggedAspect from that consumer's component-scan makes the failure disappear, since only LoggedAutoConfiguration's correct definition remains in play — confirming the trigger is component-scan visibility, not anything specific to one project's classpath.
Suggested fix
Remove @component from LoggedAspect:
@Aspect
// @Component <- remove
public class LoggedAspect {
@aspect alone does not make a class a component-scan target — it only tells Spring AOP to proxy the bean once it exists, however it was registered. LoggedAutoConfiguration.loggedAspect(...) already constructs it correctly. Removing @component takes it out of component-scan's visibility entirely, making the auto-configuration the single, authoritative registration path — a fix independent of any consumer's package layout, so it can't recur for future consumers regardless of their base package.
Suggested follow-up (defense in depth, not the root cause)
Add @Autowired to the intended (4-arg) constructor, or remove/narrow the visibility of the 3-arg overload, so constructor selection stays unambiguous if LoggedAspect is ever instantiated some other way in the future (tests, reflection, etc.).
Verification checklist
- A fresh Spring Boot app with base package com.fayupable (or any package overlapping com.fayupable.logged.*) starts cleanly with logged-spring on the classpath, with no @componentscan exclude filter needed on the consumer side.
- Existing LoggedAutoConfiguration tests (ApplicationContextRunner-based) still pass.
- mvn verify (tests + mutation testing + checkstyle) stays green.
Activity
Fayupable commentedon Aug 14, 2026
#4