侧边栏壁纸
  • 累计撰写 25 篇文章
  • 累计创建 27 个标签
  • 累计收到 44 条评论

目 录CONTENT

文章目录

spring-cloud 集成nacos(二) 集成feign和zuul

junior
2022-10-27 / 0 评论 / 0 点赞 / 1,228 阅读 / 4,727 字

前言

文章使用的代码在gitee仓库可以自行克隆。本项目有一个用户user-service服务,一个订单order-service服务和一个zuul-service网关服务。

userservice服务集成feign

feign对Ribbon和RestTemplate 进一步封装,拥有Ribbon的负载均衡,同时请求其他服务的接口比较简洁和我们平时用的service层相似,便于管理。由于本项目集成了nacos,就舍弃了feign的负载均衡策略,使用nacos的权重负载均衡。

  1. 在user-service模块的pom文件中引入feign依赖
<!-- feign       -->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>

  1. 创建一个用来访问订单模块的接口
// 使用注解添加feign客户端,name为需要访问的服务名,fallback为触发熔断执行的类
@FeignClient(name = "orderservice",fallback = OrderFeignClientFallback.class)
public interface OrderFeignClientInterface {

    //调用 orderservice 服务中的 getGoods 接口
    @GetMapping("/getGoods")
    String getGoods();
}

  1. 写一个熔断降级类实现上面定义的接口
@Component			// 作为spring的组件注入
public class OrderFeignClientFallback implements OrderFeignClientInterface {
	// 当 orderservice 服务访问不到时触发熔断,执行下面的方法
    @Override
    public String getGoods() {
        return "获取不到商品";
    }
}

  1. 在配置文件中开启feign熔断降级
feign:
  hystrix:
    enabled: true
  okhttp:
    enabled: true

  1. 在主类上添加注解开启feign客户端
@SpringBootApplication
@EnableFeignClients		// 添加注解
public class UserApplication {

    public static void main(String[] args) {
        SpringApplication.run(UserApplication.class, args);

    }
}

  1. 在控制层使用feign
@RestController
//  动态更新配置
@RefreshScope
public class UserController {

    @Resource	// 将访问订单模块的接口注入
    private OrderFeignClientInterface orderFeignClientInterface;

    // 通过从nacos配置中心获取
    @Value("${user}")
    private String user;


    @GetMapping("/buy")
    public String buy() {
        String goods = orderFeignClientInterface.getGoods();
        System.out.println("购买商品");
        return "用户:" + user + "买了一个:" + goods;
    }

    @GetMapping("/getUser")
    public String getUser() {
        System.out.println("获取用户名");
        return user;
    }

}

配置 zuul 网关

项目使用微服务各个服务在不同端口甚至不同ip,但是给用户展示的只能是一个网址,这时候我们需要一个网关服务将请求分发到各个服务中去。

  1. 在 zuul-service 中的 pom 文件引入 zuul 依赖
<!--zuul依赖-->
<dependency>
     <groupId>org.springframework.cloud</groupId>
     <artifactId>spring-cloud-starter-netflix-zuul</artifactId>
</dependency>

  1. 编写熔断降级类,当某个服务异常分发给它的请求没有响应给出一些错误信息
@Component
public class ZuulFallBack implements FallbackProvider {
    //熔断配置
    @Override
    public String getRoute() {
        //作用于所有被zuul代理的服务
        return "*";
    }

    @Override
    public ClientHttpResponse fallbackResponse(String route, Throwable cause) {
        return new ClientHttpResponse() {
            @Override
            public HttpHeaders getHeaders() {
                //添加头信息,必须要添加,不添加则熔断失败
                HttpHeaders httpHeaders=new HttpHeaders();
                httpHeaders.add("reason","theboom");
                return httpHeaders;
            }

            @Override
            public InputStream getBody() throws IOException {
                //如果熔断了展现出什么信息
                byte[] bytes = "your serve has boom".getBytes("UTF-8");
                return new ByteArrayInputStream(bytes);
            }

            @Override
            public HttpStatus getStatusCode() throws IOException {
                //报错类型400
                return HttpStatus.BAD_REQUEST;
            }

            @Override
            public int getRawStatusCode() throws IOException {
                //错误代码,和上述HttpStatus一致就行
                return 400;
            }

            @Override
            public String getStatusText() throws IOException {
                return null;
            }

            @Override
            public void close() {

            }
        };
    }
}

  1. 在网关做一些拦截操作
@Component
public class ZuulByFilter extends ZuulFilter{

    //过滤器的类型 PRE_TYPE
    @Override
    public String filterType() {
        return "pre";
    }

    //过滤器的顺序
    @Override
    public int filterOrder() {
        return 1;
    }

    @Override
    public boolean shouldFilter() {

        //获取请求上下文
        RequestContext currentContext = RequestContext.getCurrentContext();
        //获取请求对象
        HttpServletRequest request = currentContext.getRequest();
        //获取请求的地址
        String requestURI = request.getRequestURI();
        //如果包含了login,则返回false
        return !requestURI.toUpperCase().contains("LOGIN");
    }

    //执行run方法-----中心方法
    @Override
    public Object run() throws ZuulException {

        //获取上下文对象
        RequestContext currentContext = RequestContext.getCurrentContext();
        //获取对象
        HttpServletRequest request = currentContext.getRequest();
        //获取相应对象
        HttpServletResponse response = currentContext.getResponse();

        //获取请求头x-token
        String token = request.getHeader("x-token");
        //如果不存在请求头,则让重新登录
        if (StringUtils.isBlank(token)){
            currentContext.setSendZuulResponse(false);
            HashMap<String,String> map = new HashMap<>();
            map.put("success", "false");
            map.put("errorMessage","麻烦请登录" );
            //  返回错误信息
            currentContext.setResponseBody(JSON.toJSONString(map));
            //设置响应的数据格式
            response.setContentType("application/json;charset:utf-8");

        }else {
            response.setHeader("x-token", "ok");
        }
        return null;
    }
}


  1. 编写配置文件
zuul:
  prefix: /api  # 访问网关路径的前缀
  routes:     #路由代理
    user:
      path: /user/**
      serviceId: userservice  #指定服务名


    order:
      path: /order/**
      serviceId: orderservice
      
当某个服务部署在多台机器上,设置负载均衡,可以将请求分发到这些机器上(此处使用nocos的负载均衡)
#针对userservice单个服务配置负载均衡
userservice:
  ribbon:
    NFLoadBalancerRuleClassName: com.alibaba.cloud.nacos.ribbon.NacosRule # 负载均衡规则

#针对orderservice单个服务配置负载均衡
orderservice:
  ribbon:
    NFLoadBalancerRuleClassName: com.alibaba.cloud.nacos.ribbon.NacosRule # 负载均衡规则

  1. 在主类上开启网关服务
@EnableZuulProxy    // 开启zuul代理模式
@SpringBootApplication
public class ZuulApplication {
    public static void main(String[] args) {
        SpringApplication.run(ZuulApplication.class, args);
    }

}

0

评论区