微服务调用模板:Feign
微服务的本质是一系列分布式REST API的集合,因此,各服务间最常用的通信协议为HTTP协议。诚然,通过传统的写URL进行调用的方式当然可以,但未免不够优雅。而通过使用Feign,可以做到像调用本地服务一样优雅地调用远程服务。
开发目标是在Zuul中实现一个基础的过滤器,对所有经过Zuul的请求进行过滤,获取其中的Token并校验其合法性。其中,校验Token合法性的动作需要与user-service进行交互,此处通过Feign来实现。
引入依赖:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
<version>2.2.2.RELEASE</version>
</dependency>
在Zuul工程中定义如下接口:
package com.aac.acoustics.api.platform.zuul.feign;
import com.aac.acoustics.api.platform.zuul.fallback.UserServiceFallbackProvider;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
/**
* 用户服务请求Feign
*/
@FeignClient(name = "user-service")
@Component
public interface UserServiceFeign {
@RequestMapping(value = "/token/validate",method = RequestMethod.POST)
boolean validate(@RequestParam(value = "username") String username,@RequestParam(value = "token") String token);
}
无需实现该接口。@FeignClient注解参数中的“name”填写目标服务的名称,@RequestMapping注解参数中value填写服务的控制器path,即可完成调用。此处在接口上加入了@Component组件将其声明为Spring Bean,这样就可以在其他地方进行注入调用:
package com.aac.acoustics.api.platform.zuul.filter;
import com.aac.acoustics.api.platform.common.utils.ExceptionMsg;
import com.aac.acoustics.api.platform.common.utils.ResponseData;
import com.aac.acoustics.api.platform.zuul.feign.UserServiceFeign;
import com.netflix.hystrix.exception.HystrixRuntimeException;
import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import com.netflix.zuul.exception.ZuulException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import javax.servlet.http.HttpServletRequest;
/**
* 身份验证过滤器
*/
@Component
public class AuthFilter extends ZuulFilter {
private static final Logger logger = LoggerFactory.getLogger(AuthFilter.class);
private final UserServiceFeign userServiceFeign;
public AuthFilter(UserServiceFeign userServiceFeign) {
this.userServiceFeign = userServiceFeign;
}
@Override
public String filterType() {
return "pre";
}
@Override
public int filterOrder() {
return 3;
}
@Override
public boolean shouldFilter() {
return true;
}
@Override
public Object run() throws ZuulException {
logger.info("进入身份验证");
RequestContext ctx = RequestContext.getCurrentContext();
HttpServletRequest request = ctx.getRequest();
String path = request.getServletPath();
boolean needValidate = true;
boolean validatePass = false;
if(path.contains("/token") && request.getMethod().equals("GET")){
logger.info("获取Token动作,放行");
needValidate = false;
validatePass = true;
}
if(needValidate){
String username = request.getParameter("username");
logger.info("username = "+username);
String token = request.getParameter("token");
logger.info("token = "+token);
if(!StringUtils.isEmpty(username) && !StringUtils.isEmpty(token)) {
try {
validatePass = userServiceFeign.validate(username, token);
if(!validatePass){
logger.info("验证不通过");
ResponseData responseData = new ResponseData(ExceptionMsg.FORBIDDEN);
ctx.setSendZuulResponse(false);
ctx.setResponseBody(responseData.toJsonString());
}else {
ctx.set("logic-is-success", true);
}
}catch (HystrixRuntimeException e) {
logger.info("服务不可用");
ResponseData responseData = new ResponseData(ExceptionMsg.SERVICE_UNAVAILABLE);
ctx.setSendZuulResponse(false);
ctx.setResponseBody(responseData.toJsonString());
}
}
}
return null;
}
}
这里通过一个构造器注入的模式将Feign Bean注入到过滤器中,而后就可以像调用本地服务一样调用远程服务。

Feign的降级处理:
当远端服务不可用时,需要在本地执行服务降级操作。此操作只需在上述@Feign注解中指定fallback的降级处理类即可:
package com.aac.acoustics.api.platform.zuul.fallback;
import com.aac.acoustics.api.platform.zuul.feign.UserServiceFeign;
import org.springframework.stereotype.Component;
/**
* 接口服务不可用时的降级处理
* @author Rachel
*/
@Component
public class UserServiceFallbackProvider implements UserServiceFeign {
@Override
public boolean validate(String username, String token) {
return false;
}
}
浙公网安备 33010602011771号