码迷,mamicode.com
首页 > 其他好文 > 详细

微服务调用模板:Feign

时间:2020-10-16 10:35:40      阅读:22      评论:0      收藏:0      [点我收藏+]

标签:interface   enc   orm   pat   inf   public   should   通信   common   

微服务的本质是一系列分布式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;
    }
}

 

微服务调用模板:Feign

标签:interface   enc   orm   pat   inf   public   should   通信   common   

原文地址:https://www.cnblogs.com/liuxiaopen1995/p/13820589.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!