You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring Web MVC集成Spring Doc OpenApi启动遇循环依赖错误求助

问题描述

我维护的生产应用基于Spring Core、Spring Web MVC、Spring Security构建,原本运行正常。为集成Spring Doc OpenApi,参考了StackOverflow的一个解决方案,做了以下修改:

修改内容

1. build.gradle配置

implementation (group: 'org.springdoc', name: 'springdoc-openapi-ui', version: '1.6.13'){
    exclude group: 'org.springframework', module: 'spring-webmvc'
}

2. servlet-context.xml配置

<!-- Package scan for spring doc open ui -->
<context:component-scan base-package="com.documentation.openapiconfig"/>

3. 创建OpenApiConfig类

包路径:com.documentation.openapiconfig

package com.documentation.openapiconfig;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
@EnableWebMvc
@ComponentScan(basePackages = {"org.springdoc"})
@Import({org.springdoc.core.SpringDocConfiguration.class,
         org.springdoc.webmvc.core.SpringDocWebMvcConfiguration.class,
         org.springdoc.webmvc.ui.SwaggerConfig.class,
         org.springdoc.core.SwaggerUiConfigProperties.class,
         org.springdoc.core.SwaggerUiOAuthProperties.class,
         org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration.class})

class OpenApiConfig implements WebMvcConfigurer {
}

4. spring-security.xml配置

<security:intercept-url pattern="/swagger*/**" access="ROLE_DEVELOPER"/>
<security:intercept-url pattern="/v3/api-docs" access="ROLE_DEVELOPER"/>

启动错误日志

org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter': Invocation of init method failed; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'exceptionHandlingController': Unsatisfied dependency expressed through field 'eliteUtils'; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'eliteUtils': Unsatisfied dependency expressed through field 'staffService'; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'staffService': Unsatisfied dependency expressed through field 'systemParamService'; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'systemParameterService': Unsatisfied dependency expressed through field 'staffService'; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'auditAspect': Unsatisfied dependency expressed through field 'eliteUtils'; nested exception is org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'eliteUtils': Requested bean is currently in creation: Is there an unresolvable circular reference?
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1804)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:620)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:542)
    at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:335)
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234)
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:333)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:208)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:955)
    at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:918)
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:583)
    at org.springframework.web.servlet.FrameworkServlet.configureAndRefreshWebApplicationContext(FrameworkServlet.java:702)
    at org.springframework.web.servlet.FrameworkServlet.createWebApplicationContext(FrameworkServlet.java:668)
    at org.springframework.web.servlet.FrameworkServlet.createWebApplicationContext(FrameworkServlet.java:716)
    at org.springframework.web.servlet.FrameworkServlet.initWebApplicationContext(FrameworkServlet.java:591)
    at org.springframework.web.servlet.FrameworkServlet.initServletBean(FrameworkServlet.java:530)
    at org.springframework.web.servlet.HttpServletBean.init(HttpServletBean.java:170)
    at javax.servlet.GenericServlet.init(GenericServlet.java:158)
    at org.apache.catalina.core.StandardWrapper.initServlet(StandardWrapper.java:1134)
    at org.apache.catalina.core.StandardWrapper.loadServlet(StandardWrapper.java:1089)
    at org.apache.catalina.core.StandardWrapper.load(StandardWrapper.java:983)
    at org.apache.catalina.core.StandardContext.loadOnStartup(StandardContext.java:4876)
    at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5185)
    at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:183)
    at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1384)
    at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1374)
    at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
    at org.apache.tomcat.util.threads.InlineExecutorService.execute(InlineExecutorService.java:75)
    at java.base/java.util.concurrent.AbstractExecutorService.submit(AbstractExecutorService.java:140)
    at org.apache.catalina.core.ContainerBase.startInternal(ContainerBase.java:909)
    at org.apache.catalina.core.StandardHost.startInternal(StandardHost.java:841)
    at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:183)
    at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1384)
    at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1374)
    at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
    at org.apache.tomcat.util.threads.InlineExecutorService.execute(InlineExecutorService.java:75)
    at java.base/java.util.concurrent.AbstractExecutorService.submit(AbstractExecutorService.java:140)
    at org.apache.catalina.core.ContainerBase.startInternal(ContainerBase.java:909)
    at org.apache.catalina.core.StandardEngine.startInternal(StandardEngine.java:262)
    at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:183)
    at org.apache.catalina.core.StandardService.startInternal(StandardService.java:421)
    at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:183)
    at org.apache.catalina.core.StandardServer.startInternal(StandardServer.java:930)
    at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:183)
    at org.apache.catalina.startup.Tomcat.start(Tomcat.java:468)
    at org.apache.catalina.startup.Tomcat$start$0.call(Unknown Source)
    at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:47)
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:115)
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:119)
    at org.akhikhl.gretty.TomcatServerManager.startServer(TomcatServerManager.groovy:52)
    at org.akhikhl.gretty.ServerManager$startServer$0.call(Unknown Source)
    at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:47)
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:115)
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:127)
    at org.akhikhl.gretty.Runner.run(Runner.groovy:129)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.base/java.lang.reflect.Method.invoke(Method.java:566)
    at org.codehaus.groovy.runtime.callsite.PlainObjectMetaMethodSite.doInvoke(PlainObjectMetaMethodSite.java:43)
    at org.codehaus.groovy.runtime.callsite.PogoMetaMethodSite$PogoCachedMethodSiteNoUnwrapNoCoerce.invoke(PogoMetaMethodSite.java:190)
    at org.codehaus.groovy.runtime.callsite.PogoMetaMethodSite.call(PogoMetaMethodSite.java:70)
    at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:47)
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:115)
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:119)
    at org.akhikhl.gretty.Runner.main(Runner.groovy:54)
解决方案

从错误栈看,核心问题是循环依赖触发,但这是集成SpringDoc后才出现的,根源在你配置的@EnableWebMvc上:

1. 移除OpenApiConfig类中的@EnableWebMvc

你的原生Spring MVC应用已经通过XML配置了WebMvc相关组件,添加@EnableWebMvc会覆盖原有配置,重新初始化一套Spring MVC的Bean,导致和原有Bean的依赖关系混乱,触发循环依赖。

修改后的OpenApiConfig:

package com.documentation.openapiconfig;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
@ComponentScan(basePackages = {"org.springdoc"})
@Import({org.springdoc.core.SpringDocConfiguration.class,
         org.springdoc.webmvc.core.SpringDocWebMvcConfiguration.class,
         org.springdoc.webmvc.ui.SwaggerConfig.class,
         org.springdoc.core.SwaggerUiConfigProperties.class,
         org.springdoc.core.SwaggerUiOAuthProperties.class,
         org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration.class})

class OpenApiConfig implements WebMvcConfigurer {
}

2. 验证SpringDoc依赖排除是否正确

确认你的spring-webmvc版本和SpringDoc依赖的版本兼容,排除操作没问题,避免版本冲突。

3. 优化原生循环依赖(可选)

原生代码中存在staffService ↔ systemParameterService、eliteUtils被多个Bean依赖的循环依赖,后续可以通过以下方式优化:

  • 在其中一个依赖字段上添加@Lazy实现延迟加载
  • 重构代码拆分服务职责,从根源消除循环依赖

4. 重新启动验证

完成上述修改后,重新启动应用,检查是否能正常初始化,同时访问/swagger-ui.html验证SpringDoc是否正常工作。


内容的提问来源于stack exchange,提问作者Upendra Kumar

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.10 00:35:26