还原现场
优化前的代码:
java
// package cn.com.servermanager.controller;
@RestController
public class ProcessingController {
@Autowired
private ProcessingServiceImpl processingService;
@PostMapping("/xxxx")
public Result getProcessingServer() {
return processingService.getProcessingServer();
}
}
java
// package cn.com.servermanager.service;
@Service
public class ProcessingServiceImpl {
@Autowired
private ProcessingFeignService processingFeignService;
public Result getProcessingServer() {
return processingFeignService.getProcessingServer();
}
}
java
// package cn.com.servermanager.feignclient;
@ConditionalOnClass({Feign.class, Hystrix.class})
@Service
@FeignClient(
name = GlobalConstants.MANAGER,
path = "/xxxx",
fallbackFactory = ProcessingFallbackFactory.class,
contextId = "Processing")
public interface ProcessingFeignService {
@PostMapping("/")
Result getProcessingServer();
}
优化前,ProcessingServiceImpl只是对ProcessingFeignService做了简单的包装。优化后,删掉ProcessingServiceImpl,ProcessingController使用@Resource直接注入ProcessingFeignService
java
// package cn.com.servermanager.controller;
@RestController
public class ProcessingController {
@Resource
ProcessingFeignService processingFeignService;
@PostMapping("/xxxx")
public Result getProcessingServer() {
return processingFeignService.getProcessingServer();
}
}
代码优化后程序正常启动,但是调用接口时报错:
java
org.apache.ibatis.binding.BindingException: Invalid bound statement (not found): cn.com.servermanager.feignclient.ProcessingFeignService.getProcessingServer
at org.apache.ibatis.binding.MapperMethod$SqlCommand.<init>(MapperMethod.java:235)
at com.baomidou.mybatisplus.core.override.MybatisMapperMethod.<init>(MybatisMapperMethod.java:51)
at com.baomidou.mybatisplus.core.override.MybatisMapperProxy.lambda$cachedInvoker$0(MybatisMapperProxy.java:111)
at java.util.concurrent.ConcurrentHashMap.computeIfAbsent(ConcurrentHashMap.java:1660)
at com.baomidou.mybatisplus.core.toolkit.CollectionUtils.computeIfAbsent(CollectionUtils.java:117)
at com.baomidou.mybatisplus.core.override.MybatisMapperProxy.cachedInvoker(MybatisMapperProxy.java:98)
at com.baomidou.mybatisplus.core.override.MybatisMapperProxy.invoke(MybatisMapperProxy.java:89)
at com.sun.proxy.$Proxy216.getGeoProcessingServerResp(Unknown Source)
at cn.com.servermanager.controller.ProcessingController.getProcessingServer(ProcessingController.java:37)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:190)
at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:138)
at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:105)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:878)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:792)
at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1040)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:943)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006)
at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:909)
处理
一个feignClient接口为何报ibatis相关的错误,难道是ibatis做了她不该做的事情?查看入口类的注解,果然ProcessingFeignService在MapperScan的扫描范围内
java
@EnableFeignClients(basePackages = {"cn.com.common.feignclient", "cn.com.servermanager.feignclient"})
@SpringBootApplication()
@MapperScan("cn.com.servermanager.*")
@ComponentScan({"cn.com.servermanager", "cn.com.common"})
@ServletComponentScan
public class ServerManagerApplication {
public static void main(String[] args) {
// 无关代码省略
}
}
抛开细节简单说,通过查看@MapperScan和@EnableFeignClients的源码知晓:
1,被MapperScan扫描的接口会以非限定名作为beanName装配到spring的容器中,即spring容器中存在名为ProcessingFeignService的bean
2,被EnableFeignClients扫描的接口会以全限定名作为beanName并以contextId+"FeignClient"作为Alias装配到spring容器中,即spring容器中存在名为cn.com.servermanager.feignclient.ProcessingFeignService的bean,它的别名是ProcessingFeignClient
因此优化后的代码才会报ibatis的错误,因为通过@Resource注入的bean是被mybatis实例化的。
此时,摆在我们面前的解决方案有多种:
java
// 原始代码
@Resource
ProcessingFeignService processingFeignService;
// 方案一:修改变量名
@Resource
ProcessingFeignService processingService;
// 方案二:指定bean名称
@Resource(name = "ProcessingFeignClient")
ProcessingFeignService processingFeignService;
// 方案三:改用@Autowired
@Autowired
ProcessingFeignService processingFeignService;
方案一能生效的原因:@Resouce默认按照名称匹配bean,如果没找到则会按照类型匹配。
方案二能生效的原因:ProcessingFeignService在spring容器中的bean别名是ProcessingFeignClient。
方案三能生效的原因:@Autowired默认按照类型匹配bean。
问题解决了,但是还有两个需要优化的地方:
1,@MapperScan扫描的包范围尽量做到精确,避免粒度大装配太多无意义的bean。
2,@Service注解使用在ProcessingFeignService接口上是无效的。