现象
在使用EnableFeignClients指定加载包时,启动出现下面的异常。
ERROR 56739 --- [ main] o.s.boot.SpringApplication : Application run failed
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 'webConfigurerAdapter':
Unsatisfied dependency expressed through field 'cipherAuthInterceptor';
nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException:
Error creating bean with name 'cipherAuthInterceptor':
Unsatisfied dependency expressed through field 'authService';
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?
原因分析
本例相关代码
- 启动类
@SpringBootApplication
@EnableFeignClients({"com.lizz.test.api"})
public class LizzApplication {
public static void main(String[] args) {
SpringApplication.run(LizzApplication.class, args);
}
}
package com.lizz.test.api;
@FeignClient(name = "LIZZ-TEST-SERVER")
public interface AuthService {
/**
* 验证权限URI
*
* @param token
* @param uri
* @return String
*/
@PostMapping("/auth")
Boolean checkUri(@RequestParam(name = "token") String token,
@RequestParam(name = "uri") String uri);
}
- 配置类添加拦截器
@Configuration
public class WebConfigurerAdapter implements WebMvcConfigurer {
@Autowired
private AuthInterceptor authInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
//增加自定义拦截方法
registry.addInterceptor(authInterceptor)
.addPathPatterns("/**"); //拦截的api路径
}
}
- 拦截器
@Slf4j
@Configuration
public class AuthInterceptor implements HandlerInterceptor {
@Autowired
private AuthService authService;
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object o) throws Exception {
if (authService.checkUri("xxx","xxx")) {
return true;
} else {
return false;
}
}
}
- 其他Feign client代码
package com.lizz.test.api;
@FeignClient(name = "LIZZ-OTHER-SERVER")
public interface LizzOtherServer {
/**
* 验证权限URI
*
* @param token
* @param uri
* @return String
*/
@PostMapping("/test")
Boolean test();
}
- 引用其他Feign client
@Service
public class LizzServiceImpl {
@Autowired
private LizzOtherServer lizzOtherServer;
public void test(String type, String data) {
lizzOtherServer.test();
}
}
- 使用了WebMvcConfigurer添加拦截器
- 又在HandlerInterceptor拦截器中调用了feignclient服务
- 因此出现了循环引用的情况
- 如果只有这一个地方加载了feignclient服务,也不会出现异常情况。
- 由于本例中在其他service中使用了feignclinet方法,FeignClient初始化时会将所有feignclient进行初始化。
- 导致在HandlerInterceptor加载时出现了异常。
解决办法
- 出现类是循环引用时,通过@Lazy 延时加载的方式解决
- 即service类中加载其他feignclinet时,不加载HandlerInterceptor中引用的类
- 如果service中的类和HandlerInterceptor一样,都可以加上@Lazy
@Slf4j
@Configuration
public class AuthInterceptor implements HandlerInterceptor {
@Autowired
@Lazy
private AuthService authService;
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object o) throws Exception {
if (authService.checkUri("xxx","xxx")) {
return true;
} else {
return false;
}
}
}