Fix: Spring Boot "The dependencies of some of the beans in the application context form a cycle"
Quick Answer
How to fix Spring Boot circular dependency errors — BeanCurrentlyInCreationException, refactoring to break cycles, @Lazy injection, setter injection, and @PostConstruct patterns.
The Error
Spring Boot fails to start with:
***************************
APPLICATION FAILED TO START
***************************
Description:
The dependencies of some of the beans in the application context form a cycle:
userService defined in file [.../UserService.class]
↓
emailService defined in file [.../EmailService.class]
↓
userService (field com.example.UserService com.example.EmailService.userService)Or in older Spring versions:
org.springframework.beans.factory.BeanCurrentlyInCreationException:
Error creating bean with name 'userService':
Requested bean is currently in creation:
Is there an unresolvable circular reference?Or after upgrading to Spring Boot 2.6+:
Spring Boot 2.6 changed the default setting for spring.main.allow-circular-references to false.
If you need to allow for circular references, set this property to true.Why This Happens
A circular dependency exists when Bean A requires Bean B to be created, and Bean B requires Bean A to be created — forming a loop that Spring cannot resolve through constructor injection.
Spring Boot 2.6+ disabled circular dependencies by default because they often indicate a design problem:
- Service layer cycles —
UserServicedepends onEmailService, andEmailServicedepends onUserService. - Controller depending on itself — a controller autowires a service that autowires the same controller.
- Shared utility bean — two services both depend on each other through a shared operation that should be extracted into its own component.
- Constructor injection reveals the problem — with constructor injection, circular dependencies always fail at startup. With field injection, they may work via proxy magic but still represent a design flaw.
Why this matters: Circular dependencies signal that responsibilities aren’t cleanly separated. A dependency cycle means two classes know too much about each other. Fixing the design produces more maintainable, testable code.
Fix 1: Refactor to Break the Cycle (Best Fix)
The correct fix is to restructure your code so the cycle doesn’t exist. The most common approach: extract the shared logic into a third component.
Before — circular dependency:
@Service
public class UserService {
private final EmailService emailService; // UserService → EmailService
public UserService(EmailService emailService) {
this.emailService = emailService;
}
public User createUser(String email) {
User user = userRepository.save(new User(email));
emailService.sendWelcomeEmail(user); // UserService calls EmailService
return user;
}
}
@Service
public class EmailService {
private final UserService userService; // EmailService → UserService (CYCLE!)
public EmailService(UserService userService) {
this.userService = userService;
}
public void sendWelcomeEmail(User user) {
String name = userService.getDisplayName(user); // EmailService calls UserService
// send email with name
}
}After — extract the shared logic:
@Service
public class UserService {
private final EmailService emailService;
public UserService(EmailService emailService) {
this.emailService = emailService;
}
public User createUser(String email) {
User user = userRepository.save(new User(email));
emailService.sendWelcomeEmail(user.getEmail(), user.getDisplayName());
return user;
}
public String getDisplayName(User user) {
return user.getFirstName() + " " + user.getLastName();
}
}
@Service
public class EmailService {
// EmailService no longer depends on UserService
private final JavaMailSender mailSender;
public EmailService(JavaMailSender mailSender) {
this.mailSender = mailSender;
}
// Accept the data it needs as parameters — no need to call UserService
public void sendWelcomeEmail(String email, String displayName) {
// send email
}
}Another common pattern — extract to an event or mediator:
// Instead of direct service-to-service calls, use Spring events
@Service
public class UserService {
private final ApplicationEventPublisher eventPublisher;
public UserService(ApplicationEventPublisher eventPublisher) {
this.eventPublisher = eventPublisher;
}
public User createUser(String email) {
User user = userRepository.save(new User(email));
eventPublisher.publishEvent(new UserCreatedEvent(user)); // Decouple via event
return user;
}
}
@Service
public class EmailService {
// Listens for UserCreated events — no dependency on UserService
@EventListener
public void handleUserCreated(UserCreatedEvent event) {
User user = event.getUser();
sendWelcomeEmail(user.getEmail(), user.getDisplayName());
}
}Fix 2: Use @Lazy to Defer Injection
@Lazy tells Spring to inject a proxy instead of the real bean at construction time. The real bean is created only when a method is first called. This breaks the construction-time cycle without redesigning the classes:
@Service
public class UserService {
private final EmailService emailService;
// @Lazy on one of the two injections breaks the cycle
public UserService(@Lazy EmailService emailService) {
this.emailService = emailService;
}
}
@Service
public class EmailService {
private final UserService userService;
public EmailService(UserService userService) {
this.userService = userService;
}
}Or use @Lazy on the field (with field injection):
@Service
public class UserService {
@Lazy
@Autowired
private EmailService emailService;
}Note:
@Lazyis a workaround, not a design fix. Spring injects a CGLIB proxy at construction time and calls the real bean when the method is invoked. This adds a small runtime overhead and can cause confusing behavior in tests. Prefer Fix 1 (refactoring) when possible.
Fix 3: Switch from Constructor Injection to Setter Injection
Spring can resolve circular dependencies through setter injection (but not constructor injection) because with setter injection, the beans are first created (empty) and then wired together:
@Service
public class UserService {
private EmailService emailService;
// Setter injection — Spring creates UserService first, then injects EmailService
@Autowired
public void setEmailService(EmailService emailService) {
this.emailService = emailService;
}
}
@Service
public class EmailService {
private UserService userService;
@Autowired
public void setUserService(UserService userService) {
this.userService = userService;
}
}Warning: Setter injection makes dependencies optional by default — Spring won’t fail at startup if a bean is missing (it will fail only when the method is called). Use
@Autowired(required = true)if the dependency is mandatory. Like@Lazy, setter injection is a workaround. Prefer refactoring.
Fix 4: Use @PostConstruct for Initialization Logic
Sometimes the cycle occurs because a bean calls another bean during its own construction. Move the initialization logic to @PostConstruct, which runs after all beans are wired:
@Service
public class CacheService {
private final UserService userService;
private List<User> cachedUsers;
public CacheService(UserService userService) {
this.userService = userService;
// Don't call userService here — it may not be ready yet
}
@PostConstruct
public void init() {
// Called after all beans are wired — safe to call userService
this.cachedUsers = userService.findAll();
}
}Fix 5: Allow Circular References (Last Resort)
Spring Boot 2.6+ blocks circular references by default. You can re-enable them as a temporary workaround while you fix the underlying design:
# application.yml — allow circular references (temporary fix only)
spring:
main:
allow-circular-references: trueOr in application.properties:
spring.main.allow-circular-references=trueWarning: Setting
allow-circular-references=truere-enables the old behavior that Spring Boot deliberately removed. It masks the design problem and makes your application harder to reason about. Use it only as a short-term fix to keep the application running while you implement a proper structural fix. Track it as technical debt.
Fix 6: Diagnose the Full Dependency Cycle
When the cycle involves multiple beans, the error message shows the full chain. Read it carefully:
The dependencies of some of the beans in the application context form a cycle:
orderService → paymentService → notificationService → userService → orderServiceThis tells you the cycle is: orderService → paymentService → notificationService → userService → orderService.
Use Spring’s dependency graph to investigate:
// Add to your application — temporarily log all bean dependencies
@Configuration
public class BeanInspector implements ApplicationContextAware {
@Override
public void setApplicationContext(ApplicationContext ctx) throws BeansException {
ConfigurableApplicationContext context = (ConfigurableApplicationContext) ctx;
BeanFactory factory = context.getBeanFactory();
if (factory instanceof DefaultListableBeanFactory) {
DefaultListableBeanFactory beanFactory = (DefaultListableBeanFactory) factory;
for (String name : beanFactory.getBeanDefinitionNames()) {
BeanDefinition def = beanFactory.getBeanDefinition(name);
String[] deps = def.getDependsOn();
if (deps != null) {
System.out.println(name + " depends on: " + Arrays.toString(deps));
}
}
}
}
}Enable debug logging to see Spring’s bean creation order:
logging:
level:
org.springframework.beans.factory: DEBUGStill Not Working?
Check if the cycle is in test configuration. Spring test contexts can introduce cycles that don’t exist in production if test configuration beans add extra dependencies:
@TestConfiguration
public class TestConfig {
// Beans defined here can create cycles with production beans
}Check if @Component, @Service, or @Repository is accidentally applied to a class that should not be a Spring bean. An unexpected component scan can pull in a class that creates a cycle.
Check for @Configuration class cycles. Circular dependencies between @Configuration classes (where one @Bean method calls another @Configuration class’s @Bean method) also cause this error:
@Configuration
public class ConfigA {
@Bean
public BeanA beanA(BeanB beanB) { return new BeanA(beanB); } // Requires BeanB
}
@Configuration
public class ConfigB {
@Bean
public BeanB beanB(BeanA beanA) { return new BeanB(beanA); } // Requires BeanA → CYCLE
}Fix: inject by method reference instead of by parameter, or merge related configuration into a single @Configuration class.
For related Spring Boot issues, see Fix: Spring Boot DataSource Failed and Fix: Spring Security Returning 403 Forbidden.
Solo developer based in Japan. Every solution is cross-referenced with official documentation and tested before publishing.
Was this article helpful?
Related Articles
Fix: Hibernate LazyInitializationException — Could Not Initialize Proxy
How to fix Hibernate LazyInitializationException — loading lazy associations outside an active session, fetch join, @Transactional scope, DTO projection, and Open Session in View.
Fix: Spring Security Returning 403 Forbidden Unexpectedly
How to fix Spring Security 403 Forbidden errors — CSRF token missing, incorrect security configuration, method security blocking requests, and how to debug the Spring Security filter chain.
Fix: Spring Boot Failed to Configure DataSource (DataSource Auto-Configuration Error)
How to fix Spring Boot 'Failed to configure a DataSource' errors — missing URL property, driver class not found, connection refused, and how to correctly configure datasource properties for MySQL, PostgreSQL, and H2.
Fix: Spring BeanCreationException: Error creating bean with name
How to fix Spring BeanCreationException error creating bean caused by missing dependencies, circular references, wrong annotations, configuration errors, and constructor issues.