1.问题背景
- 某次需求,需要在拦截器中注入调用另一个系统的Springcloud服务接口,并且此接口通过Feign的方式调用。然而在工程启动的时候报错了.报了:
Caused by: org.springframework.beans.factory.BeanCurrentlyInCreationException:
Error creating bean with name 'mvcResourceUrlProvider': Requested bean is currently in creation: Is there an unresolvable circular reference?
2.代码
@Configuration
public class WebConfiguration implements WebMvcConfigurer {
@Autowired
private AuthInterceptor authInterceptor;
@Bean
public WebMvcConfigurer WebMvcConfigurer() {
return new WebMvcConfigurer() {
@Override
public void addInterceptors(InterceptorRegistry registry) {
// ...省略无关代码
registry.addInterceptor(authInterceptor);
// ... 省略无关代码
}
}
}
}
@Component
public class AuthInterceptor extends HandlerInterceptorAdapter {
@Autowired
private AuthInfoFeign authInfoFeign;
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse
response, Object handler) throws Exception {
// ... 省略无关代码
Result<AuthInfo> result = authInfoFeign.doService();
// ... 省略无关代码
}
}
@FeignClient(value = "AService")
public interface AuthInfoFeign extends AuthenticationInfoApi {
}
3.异常报错
org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration$EnableWebMvcConfiguration': Unsatisfied dependency expressed through method 'setConfigurers' parameter 0; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'webConfiguration': Unsatisfied dependency expressed through field 'authencationInterceptor'; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'authencationInterceptor': Unsatisfied dependency expressed through field 'authenticationInfoFeign'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'com.xxx.service.feign.crm.AuthInfoFeign': FactoryBean threw exception on object creation; nested exception is org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'mvcResourceUrlProvider': Requested bean is currently in creation: Is there an unresolvable circular reference?
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredMethodElement.inject(AutowiredAnnotationBeanPostProcessor.java:676)
at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:90)
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessProperties(AutowiredAnnotationBeanPostProcessor.java:374)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1411)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:592)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:515)
at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:320)
at org.springframework.beans.factory.support.AbstractBeanFactory$$Lambda$137/1161148117.getObject(Unknown Source)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:318)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199)
at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:392)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1321)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1160)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:555)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:515)
at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:320)
at org.springframework.beans.factory.support.AbstractBeanFactory$$Lambda$137/1161148117.getObject(Unknown Source)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:318)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:204)
at org.springframework.context.event.AbstractApplicationEventMulticaster.retrieveApplicationListeners(AbstractApplicationEventMulticaster.java:239)
at org.springframework.context.event.AbstractApplicationEventMulticaster.getApplicationListeners(AbstractApplicationEventMulticaster.java:196)
at org.springframework.context.event.SimpleApplicationEventMulticaster.multicastEvent(SimpleApplicationEventMulticaster.java:133)
at org.springframework.context.event.SimpleApplicationEventMulticaster.multicastEvent(SimpleApplicationEventMulticaster.java:127)
at org.springframework.context.support.AbstractApplicationContext.registerListeners(AbstractApplicationContext.java:840)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:546)
at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:142)
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:775)
at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:397)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:316)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1260)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1248)
at com.xxx.web.WebApplication.main(WebApplication.java:27)
- 提示AuthenticationInfoFeign在创建bean的时候依赖注入mvcResourceUrlProvider循环依赖了: Caused by: org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'mvcResourceUrlProvider': Requested bean is currently in creation: Is there an unresolvable circular reference?
4.处理思路
- debug报错代码,DefaultSingletonBeanRegistry中初始化单例bean之前的校验不通过,发现已经存在了mvcResourceUrlProvider,故抛出异常报错提醒。注:DefaultSingletonBeanRegistry这个类主要用作基类的BeanFactory实现, 提供基本的管理 singleton bean 实例功能
- 原因找到了,只要解决mvcResourceUrlProvider不被重复注入即可,怀疑是否是@FeignClient生成代理对象注入Bean容器时触发的,通过feign的原理学习和源码并未发现它会注入mvcResourceUrlProvider。
mvcResourceUrlProvider重复注入的点并未找到, 期待其他的小伙伴指正答疑。
- 改变思路
- 循环依赖的错误那么我们就截断依赖注入。
在拦截器注入FeignClient时,不需要spring的自动注入, 而是手动从Spring上下文中获取bean
- 既然拦截器中注入的AuthenticationInfoFeign ,那么我们将它延时注入,启动时不将feignClient注入,而是在拦截器被配置初始化时进行注入,这不正是@Lazy注解的功能嘛。
@Lazy:延时加载。仅对单例Bean生效。而单例Bean是在Spring容器启动的时候加载的,添加@Lazy注解后就会延迟加载,在Spring容器启动的时候并不会加载,而是在当你第一次使用此bean的时候才会加载,但当你多次获取bean的时候不会重复加载。
- 按照上述思路,修改代码
5.解决方法
- 手动获取AuthenticationInfoFeign,阻止循环依赖
/**
* SpringContextUtil自行百度
*/
@Component
public class AuthInterceptor extends HandlerInterceptorAdapter {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse
response, Object handler) throws Exception {
// ... 省略无关代码
// 手动从Spring上下文中获取AuthenticationInfoFeign
AuthInfoFeign authInfoFeign = SpringContextUtil.getBean(AuthInfoFeign.class);
Result<AuthenticationInfo> result = authInfoFeign.doService();
// ... 省略无关代码
}
}
- @Lazy 延时加载AuthenticationInfoFeign
@Component
public class AuthInterceptor extends HandlerInterceptorAdapter {
@Autowired
@Lazy
private AuthInfoFeign authInfoFeign;
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse
response, Object handler) throws Exception {
// ... 省略无关代码
Result<AuthenticationInfo> result = authInfoFeign.doService();
// ... 省略无关代码
}
}
评论区