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
相关产品推荐
相关产品推荐

