前言
在我以前的使用微服务的时候,都是使用 LoadBalancerClient 调用微服务的接口,后来学习若依管理框架的时候,发现了Fegin这个配置,其实就是把远程服务接口,写成本地调用的形式,感觉还是要好好的学习一下。
1.加载Jar包
2.新建一个Feign接口类( ClearBatchFeign.java),并且注明接口实现类
3.创建一个Feign接口实现类(ClearBatchFeignFallback.java),实现Feign接口,需要加上注解@Component自动注入
4.定义DTO类来接受数据(接收的数据要和调用的接口一致)
5.调用接口,实现微服务调用
1.添加依赖
1 2 3 4
| <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> </dependency>
|
2.修改启动类@EnableFeignClients
启动类添加@EnableFeignClients,扫描包下所由@FeignClient注解描述的接口。
3.编写@FeignClient接口
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
|
@FeignClient(name="provider", contextId = "remoteProviderService", fallbackFactory = ProviderFallbackFactory.class) public interface RemoteProviderService { @GetMapping("/provider/echo/{msg}") String echoMsg(@PathVariable("msg") String msg); }
|
4.编写FallbackFactory
主要实现在服务调用失败的时候,执行的相关操作,也就是上面的ProviderFallbackFactory.class
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| @Component public class ProviderFallbackFactory implements FallbackFactory<RemoteProviderService> {
@Override public RemoteProviderService create(Throwable throwable){ log.error("用户服务调用失败:{}", throwable.getMessage()); return new RemoteProviderService() { @Override public AjaxResult echoMsg(@@PathVariable("msg") String msg){ return "调用失败"; } }; } }
|
问题
(1) @FeignClient注入service失败
这个主要就是我使用了若依开发环境自定义的 @EnableRyFeignClients 注解,这里的包中没有添加我的包路径,添加上就可以了。
1
| @EnableRyFeignClients(basePackages = {"com.ruoyi","com.xxx"})
|
(2) 服务调用不报错但是不成功
这个问题让我很头大,我在本地测试的时候,同一个微服务的一个接口能访问到,另外的一个接口却访问不了,sendWxMessageBySystem 可以找到,在使用idea进行调试的时候,可以进入到微服务的 sendWxMessageBySystem 方法中。但是同一个微服务的 sendWxMessageByAlarm,却死活找不到微服务,但是也不报错,就是直接返回一个 null,代码跳到下面一个代码中。
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| @FeignClient(name = "ph-system",contextId = "remoteWxService",fallbackFactory = RemoteWxFallbackFactory.class) public interface RemoteWxService {
@PostMapping("sendWxMessageBySystem") AjaxResult sendWxMessageBySystem(@RequestParam(value = "templateid")String templateid, @RequestParam(value = "templateparams")String templateparams, @RequestParam(value = "dbalias")String dbalias, @RequestParam(value = "sitenos")String sitenos);
@PostMapping("sendWxMessageByAlarm") AjaxResult sendWxMessageByAlarm(@RequestParam(value = "dbalias")String dbalias, @RequestParam(value = "siteno_list")String siteno_list);
}
|
在使用的时候,是这样使用的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| public void sendBreakAlarm(String sitenos){ try { String dbalias=""; if(this.config!=null){ dbalias=this.config.getDbalias(); } remoteWxService.sendWxMessageBySystem("","","",""); AjaxResult sendResult=remoteWxService..sendWxMessageByAlarm("",""); if(sendResult!=null){ logger.error(sitenos+" 设备通讯中断消息发送成功"); }else { logger.error(sitenos+" 设备通讯中断消息发送失败;消息内容:"+sendResult); } }catch (Exception e){ logger.error("sendBreakAlarmMessage",e); } }
|
下面是远程微服务的实现方法,其实非常的简单,就是接收参数,然后进行处理,理论上是没有错误的。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| @RequestMapping(value = "sendWxMessageByAlarm") public AjaxResult sendWxMessageByAlarm(@RequestParam(value = "d_t")String d_t,@RequestParam(value = "s_list")String s_list){ try { if(s_list!=null){ String[] sitenoArray=s_list.split(","); int sitenocount=sitenoArray.length; List<WxUser> wxUsers=wxUserService.getUserListByDatabase(s_list); Map<String,List<String>> userTempMap=new HashMap<>(); String templateid="rpeVC_inwvGo_mw_PWVf9-LLF64AVw3SO585lPjFGmg"; String dbalias=d_t; } }catch (Exception e){ logger.error("sendWxMessageByAlarm",e); } return AjaxResult.error(); }
|
【尝试】
1.我尝试了很多遍重写,在同一个方法里面,一个可以调用,一个不可以调用,我也尝试了使用不同的方法的名字,但是没有效果。
2.尝试修改方法参数名称,也不行。
3.尝试重启idea,删除缓存,也不行。
4.尝试调换方法的位置,也不行。
5.重启电脑也不行,只能新创建一个接口了,但是别人也是在一个接口里面写了好几个方法啊,为什么我的就不行呢?
6.尝试修改 sendWxMessageByAlarm 方法的返回值类型,也不行。
7.将 sendWxMessageByAlarm 请求参数删除。
8.尝试添加 @PostMapping(value = “sendWxMessageByAlarm”,produces =MediaType.APPLICATION_JSON_VALUE) ,也失败了。
9.尝试设置feign的超时时间,也不可以,还是直接返回了null,什么也不报错,但是我的远程接口 sendWxMessageByAlarm 返回的不是 null 啊。
1 2 3 4 5 6
| feign: client: config: default: connectTimeout: 5000 readTimeout: 3000
|
我发现了在idea中的一个奇怪的现象,就是我在调试的时候,明明调用的是下面的那个函数,最后出现调试信息的确实上面的那个函数,例如这里的 sitenos 就成了上面的东西。真是玄学啊,玄学啊,我用了很长的时间,还是找不到问题到底出在那里,真是见鬼了。
【解决】
经过长时间的尝试,我竟然发现是因为我在微服务中中配置了拦截器,在拦截器中验证了用户身份
1 2 3 4 5 6 7 8 9 10 11 12
| public class UserInterceptor implements HandlerInterceptor { private static final Logger logger= LoggerFactory.getLogger(UserInterceptor.class); @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object o) throws Exception { LoginUser loginUser=tokenService.getLoginUser(request); if(loginUser==null){ return false; } return true; } }
|
之所以 sendWxMessageBySystem 可以通过,是因为我添加了例外,这样就可以不通过拦截器了,所以可以直接进入到流程的下一步,也就是可以进行调试了。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| @Configuration public class WebMvcConfig implements WebMvcConfigurer {
@Bean public UserInterceptor userInterceptor(){ return new UserInterceptor(); }
@Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(userInterceptor()) .addPathPatterns("/**") .excludePathPatterns("/getUserInfo") .excludePathPatterns("/sendWxMessageBySystem") .excludePathPatterns("/error");
}
}
|
血的教训,血的教训,血的教训,我足足花了半天的时间检查,为什么微服务调用不成功呢?